from decimal import Decimal from unittest import mock from unittest.mock import patch from src.constants import PayableDetailTypes from src.processors.base.payment_batch_processor import PaymentBatchProcessor from tests.unit.factories import ( ContractCloseBalanceFactory, EligibleAccountLevelDataFactory, EventFactory, FlowthroughAllocationFactory, ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections_vat' ) @patch('src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections') @patch( 'src.processors.base.payment_batch_processor.fetch_all_flowthrough_allocation_entries' ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_contract_closing_balance_entries' ) def test_flowthrough_wins_over_closing_balance( mock_fetch_closing_balance: mock.MagicMock, mock_fetch_flowthrough: mock.MagicMock, mock_fetch_wht: mock.MagicMock, mock_fetch_vat: mock.MagicMock, ) -> None: """Test flowthrough wins when amount exceeds closing balance. Scenario: - Contract has $1000 flowthrough pending - Contract has $800 closing balance - System aggregates flowthrough to $1000 - Max calculation: max($1000, $800) = $1000 - Payment created for $1000 - Worksheet record created with amount = $1000 (flowthrough used) """ # Setup: Create test data mock_event = EventFactory.build(statement_period_id=318) mock_account = EligibleAccountLevelDataFactory.build( account_id=1, currency_code='USD', country_of_tax_policy='USA', country_of_tax_residence='USA', ) closing_balance = ContractCloseBalanceFactory.build( account_id=mock_account.account_id, contract_id=1001, amount=Decimal('800.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation_1 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('600.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation_2 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('400.00'), statement_period_id=mock_event.statement_period_id, ) # Configure mocks mock_fetch_closing_balance.return_value = [closing_balance] mock_fetch_flowthrough.return_value = [ flowthrough_allocation_1, flowthrough_allocation_2, ] mock_fetch_wht.return_value = [] mock_fetch_vat.return_value = [] # Create processor and run processor = PaymentBatchProcessor( abacus_event=mock_event, accounts=[mock_account], ) processor._setup_contract_worksheets() processor._append_flowthrough_allocations_to_worksheets() # Get the worksheet for assertions worksheet = processor._contract_worksheets_by_id[closing_balance.contract_id] # Verify the flowthrough amount wins over closing balance assert worksheet.payable_amount_pre_tax == Decimal('1000.00') assert worksheet.payable_amount_post_tax == Decimal('1000.00') assert worksheet._closing_balance_detail.amount_payable == Decimal('0') assert len(worksheet._details) == 3 # Verify flowthrough allocation details ft_details = [ d for d in worksheet._details if d.payable_detail_type_id == PayableDetailTypes.flowthrough_allocation ] assert len(ft_details) == 2 ft_amounts = sorted([d.amount_payable for d in ft_details]) assert ft_amounts == [Decimal('400.00'), Decimal('600.00')] # Verify payable item payable_item = worksheet.get_payable_balance_after_tax_item() assert payable_item.payable_amount_pre_tax == Decimal('1000.00') assert payable_item.payable_amount_post_tax == Decimal('1000.00') assert payable_item.contract_id == closing_balance.contract_id assert payable_item.account_id == mock_account.account_id @patch( 'src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections_vat' ) @patch('src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections') @patch( 'src.processors.base.payment_batch_processor.fetch_all_flowthrough_allocation_entries' ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_contract_closing_balance_entries' ) def test_closing_balance_wins_over_flowthrough( mock_fetch_closing_balance: mock.MagicMock, mock_fetch_flowthrough: mock.MagicMock, mock_fetch_wht: mock.MagicMock, mock_fetch_vat: mock.MagicMock, ) -> None: """Test closing balance wins when amount exceeds flowthrough. Scenario: - Contract has $500 flowthrough pending - Contract has $1200 closing balance - System aggregates flowthrough to $500 - Max calculation: max($500, $1200) = $1200 - Payment created for $1200 - Worksheet record created with closing balance used, flowthrough NOT used """ # Setup: Create test data mock_event = EventFactory.build(statement_period_id=318) mock_account = EligibleAccountLevelDataFactory.build( account_id=1, currency_code='USD', country_of_tax_policy='USA', country_of_tax_residence='USA', ) closing_balance = ContractCloseBalanceFactory.build( account_id=mock_account.account_id, contract_id=1001, amount=Decimal('1200.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation_1 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('300.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation_2 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('200.00'), statement_period_id=mock_event.statement_period_id, ) # Configure mocks mock_fetch_closing_balance.return_value = [closing_balance] mock_fetch_flowthrough.return_value = [ flowthrough_allocation_1, flowthrough_allocation_2, ] mock_fetch_wht.return_value = [] mock_fetch_vat.return_value = [] # Create processor and run processor = PaymentBatchProcessor( abacus_event=mock_event, accounts=[mock_account], ) processor._setup_contract_worksheets() processor._append_flowthrough_allocations_to_worksheets() # Get the worksheet for assertions worksheet = processor._contract_worksheets_by_id[closing_balance.contract_id] # Verify the closing balance amount wins over flowthrough assert worksheet.payable_amount_pre_tax == Decimal('1200.00') assert worksheet.payable_amount_post_tax == Decimal('1200.00') assert worksheet._closing_balance_detail.amount_payable == Decimal('1200.00') assert len(worksheet._details) == 3 # Verify flowthrough allocation details show zero (not used) ft_details = [ d for d in worksheet._details if d.payable_detail_type_id == PayableDetailTypes.flowthrough_allocation ] assert len(ft_details) == 2 ft_amounts = [d.amount_payable for d in ft_details] assert all(amount == Decimal('0') for amount in ft_amounts) # Verify payable item payable_item = worksheet.get_payable_balance_after_tax_item() assert payable_item.payable_amount_pre_tax == Decimal('1200.00') assert payable_item.payable_amount_post_tax == Decimal('1200.00') assert payable_item.contract_id == closing_balance.contract_id assert payable_item.account_id == mock_account.account_id @patch( 'src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections_vat' ) @patch('src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections') @patch( 'src.processors.base.payment_batch_processor.fetch_all_flowthrough_allocation_entries' ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_contract_closing_balance_entries' ) def test_flowthrough_tie_with_closing_balance( mock_fetch_closing_balance: mock.MagicMock, mock_fetch_flowthrough: mock.MagicMock, mock_fetch_wht: mock.MagicMock, mock_fetch_vat: mock.MagicMock, ) -> None: """Test exact tie between flowthrough and closing balance. Scenario: - Contract has $1000 flowthrough pending - Contract has $1000 closing balance - Max calculation: max($1000, $1000) = $1000 - Payment created for $1000 - Worksheet record created with closing balance used (balance wins in ties) """ # Setup: Create test data mock_event = EventFactory.build(statement_period_id=318) mock_account = EligibleAccountLevelDataFactory.build( account_id=1, currency_code='USD', country_of_tax_policy='USA', country_of_tax_residence='USA', ) closing_balance = ContractCloseBalanceFactory.build( account_id=mock_account.account_id, contract_id=1001, amount=Decimal('1000.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation_1 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('600.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation_2 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('400.00'), statement_period_id=mock_event.statement_period_id, ) # Configure mocks mock_fetch_closing_balance.return_value = [closing_balance] mock_fetch_flowthrough.return_value = [ flowthrough_allocation_1, flowthrough_allocation_2, ] mock_fetch_wht.return_value = [] mock_fetch_vat.return_value = [] # Create processor and run processor = PaymentBatchProcessor( abacus_event=mock_event, accounts=[mock_account], ) processor._setup_contract_worksheets() processor._append_flowthrough_allocations_to_worksheets() # Get the worksheet for assertions worksheet = processor._contract_worksheets_by_id[closing_balance.contract_id] # Verify the closing balance is used when amounts are equal assert worksheet.payable_amount_pre_tax == Decimal('1000.00') assert worksheet.payable_amount_post_tax == Decimal('1000.00') assert worksheet._closing_balance_detail.amount_payable == Decimal('1000.00') assert len(worksheet._details) == 3 # Verify flowthrough allocation details show zero (not used in ties) ft_details = [ d for d in worksheet._details if d.payable_detail_type_id == PayableDetailTypes.flowthrough_allocation ] assert len(ft_details) == 2 ft_amounts = [d.amount_payable for d in ft_details] assert all(amount == Decimal('0') for amount in ft_amounts) # Verify payable item payable_item = worksheet.get_payable_balance_after_tax_item() assert payable_item.payable_amount_pre_tax == Decimal('1000.00') assert payable_item.payable_amount_post_tax == Decimal('1000.00') assert payable_item.contract_id == closing_balance.contract_id assert payable_item.account_id == mock_account.account_id @patch( 'src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections_vat' ) @patch('src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections') @patch( 'src.processors.base.payment_batch_processor.fetch_all_flowthrough_allocation_entries' ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_contract_closing_balance_entries' ) def test_multiple_allocations_same_contract( mock_fetch_closing_balance: mock.MagicMock, mock_fetch_flowthrough: mock.MagicMock, mock_fetch_wht: mock.MagicMock, mock_fetch_vat: mock.MagicMock, ) -> None: """Test multiple allocations for same contract are all processed. Scenario: - Contract has 3 allocations: $300, $400, $300 = total $1000 - Closing balance = $800 - System aggregates ALL allocations - Max calculation: max($1000, $800) = $1000 - Payment created for $1000 - All 3 allocations get worksheet records """ # Setup: Create test data mock_event = EventFactory.build(statement_period_id=318) mock_account = EligibleAccountLevelDataFactory.build( account_id=1, currency_code='USD', country_of_tax_policy='USA', country_of_tax_residence='USA', ) closing_balance = ContractCloseBalanceFactory.build( account_id=mock_account.account_id, contract_id=1001, amount=Decimal('800.00'), statement_period_id=mock_event.statement_period_id, ) # Create 3 allocations for the same contract flowthrough_allocation_1 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('300.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation_2 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('400.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation_3 = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('300.00'), statement_period_id=mock_event.statement_period_id, ) # Configure mocks mock_fetch_closing_balance.return_value = [closing_balance] mock_fetch_flowthrough.return_value = [ flowthrough_allocation_1, flowthrough_allocation_2, flowthrough_allocation_3, ] mock_fetch_wht.return_value = [] mock_fetch_vat.return_value = [] # Create processor and run processor = PaymentBatchProcessor( abacus_event=mock_event, accounts=[mock_account], ) processor._setup_contract_worksheets() processor._append_flowthrough_allocations_to_worksheets() # Get the worksheet for assertions worksheet = processor._contract_worksheets_by_id[closing_balance.contract_id] # Verify the flowthrough amount wins over closing balance assert worksheet.payable_amount_pre_tax == Decimal('1000.00') assert worksheet.payable_amount_post_tax == Decimal('1000.00') assert worksheet._closing_balance_detail.amount_payable == Decimal('0') assert len(worksheet._details) == 4 # 1 closing balance + 3 flowthrough # Verify all 3 flowthrough allocation details are present ft_details = [ d for d in worksheet._details if d.payable_detail_type_id == PayableDetailTypes.flowthrough_allocation ] assert len(ft_details) == 3 ft_amounts = sorted([d.amount_payable for d in ft_details]) assert ft_amounts == [Decimal('300.00'), Decimal('300.00'), Decimal('400.00')] # Verify payable item payable_item = worksheet.get_payable_balance_after_tax_item() assert payable_item.payable_amount_pre_tax == Decimal('1000.00') assert payable_item.payable_amount_post_tax == Decimal('1000.00') assert payable_item.contract_id == closing_balance.contract_id assert payable_item.account_id == mock_account.account_id @patch( 'src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections_vat' ) @patch('src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections') @patch( 'src.processors.base.payment_batch_processor.fetch_all_flowthrough_allocation_entries' ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_contract_closing_balance_entries' ) def test_high_volume_allocations_single_contract( mock_fetch_closing_balance: mock.MagicMock, mock_fetch_flowthrough: mock.MagicMock, mock_fetch_wht: mock.MagicMock, mock_fetch_vat: mock.MagicMock, ) -> None: """Test high volume of allocations for single contract (pagination). Scenario: - Contract has 250 flowthrough allocations (requires pagination) - First API call retrieves 100 allocations = $7,500 - Second API call retrieves 100 allocations = $7,500 - Third API call retrieves remaining 50 allocations = $3,500 - Total aggregated flowthrough = $18,500 - Closing balance = $20,000 - Max calculation: max($18,500, $20,000) = $20,000 - Payment created for $20,000 - Worksheet records created for all 250 allocations with amount = $0 """ # Setup: Create test data mock_event = EventFactory.build(statement_period_id=318) mock_account = EligibleAccountLevelDataFactory.build( account_id=1, currency_code='USD', country_of_tax_policy='USA', country_of_tax_residence='USA', ) closing_balance = ContractCloseBalanceFactory.build( account_id=mock_account.account_id, contract_id=1001, amount=Decimal('20000.00'), statement_period_id=mock_event.statement_period_id, ) # Create 250 allocations (100 @ $75 each = $15,000 + 100 @ $75 each = $15,000 + 50 @ $70 each = $3,500 total $18,500) first_batch_allocations = [ FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('75.00'), statement_period_id=mock_event.statement_period_id, ) for _ in range(100) ] second_batch_allocations = [ FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('75.00'), statement_period_id=mock_event.statement_period_id, ) for _ in range(100) ] third_batch_allocations = [ FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('70.00'), statement_period_id=mock_event.statement_period_id, ) for _ in range(50) ] all_allocations = ( first_batch_allocations + second_batch_allocations + third_batch_allocations ) # Configure mocks mock_fetch_closing_balance.return_value = [closing_balance] mock_fetch_flowthrough.return_value = all_allocations mock_fetch_wht.return_value = [] mock_fetch_vat.return_value = [] # Create processor and run processor = PaymentBatchProcessor( abacus_event=mock_event, accounts=[mock_account], ) processor._setup_contract_worksheets() processor._append_flowthrough_allocations_to_worksheets() # Get the worksheet for assertions worksheet = processor._contract_worksheets_by_id[closing_balance.contract_id] # Verify the closing balance wins over flowthrough assert worksheet.payable_amount_pre_tax == Decimal('20000.00') assert worksheet.payable_amount_post_tax == Decimal('20000.00') assert worksheet._closing_balance_detail.amount_payable == Decimal('20000.00') assert len(worksheet._details) == 251 # 1 closing balance + 250 flowthrough # Verify all 250 flowthrough allocation details are present with amount = $0 ft_details = [ d for d in worksheet._details if d.payable_detail_type_id == PayableDetailTypes.flowthrough_allocation ] assert len(ft_details) == 250 assert all(d.amount_payable == Decimal('0') for d in ft_details) # Verify payable item payable_item = worksheet.get_payable_balance_after_tax_item() assert payable_item.payable_amount_pre_tax == Decimal('20000.00') assert payable_item.payable_amount_post_tax == Decimal('20000.00') assert payable_item.contract_id == closing_balance.contract_id assert payable_item.account_id == mock_account.account_id @patch( 'src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections_vat' ) @patch('src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections') @patch( 'src.processors.base.payment_batch_processor.fetch_all_flowthrough_allocation_entries' ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_contract_closing_balance_entries' ) def test_zero_closing_balance_with_flowthrough( mock_fetch_closing_balance: mock.MagicMock, mock_fetch_flowthrough: mock.MagicMock, mock_fetch_wht: mock.MagicMock, mock_fetch_vat: mock.MagicMock, ) -> None: """Test flowthrough wins when closing balance is zero. Scenario: - Contract has $500 flowthrough - Contract has $0 closing balance - Max calculation: max($500, $0) = $500 - Payment created for $500 - Worksheet shows flowthrough amount = $500 """ # Setup: Create test data mock_event = EventFactory.build(statement_period_id=318) mock_account = EligibleAccountLevelDataFactory.build( account_id=1, currency_code='USD', country_of_tax_policy='USA', country_of_tax_residence='USA', ) closing_balance = ContractCloseBalanceFactory.build( account_id=mock_account.account_id, contract_id=1001, amount=Decimal('0.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('500.00'), statement_period_id=mock_event.statement_period_id, ) # Configure mocks mock_fetch_closing_balance.return_value = [closing_balance] mock_fetch_flowthrough.return_value = [flowthrough_allocation] mock_fetch_wht.return_value = [] mock_fetch_vat.return_value = [] # Create processor and run processor = PaymentBatchProcessor( abacus_event=mock_event, accounts=[mock_account], ) processor._setup_contract_worksheets() processor._append_flowthrough_allocations_to_worksheets() # Get the worksheet for assertions worksheet = processor._contract_worksheets_by_id[closing_balance.contract_id] # Verify the flowthrough amount is used (closing balance is zero) assert worksheet.payable_amount_pre_tax == Decimal('500.00') assert worksheet.payable_amount_post_tax == Decimal('500.00') assert worksheet._closing_balance_detail.amount_payable == Decimal('0') assert len(worksheet._details) == 2 # 1 closing balance + 1 flowthrough # Verify flowthrough allocation detail ft_details = [ d for d in worksheet._details if d.payable_detail_type_id == PayableDetailTypes.flowthrough_allocation ] assert len(ft_details) == 1 assert ft_details[0].amount_payable == Decimal('500.00') # Verify payable item payable_item = worksheet.get_payable_balance_after_tax_item() assert payable_item.payable_amount_pre_tax == Decimal('500.00') assert payable_item.payable_amount_post_tax == Decimal('500.00') assert payable_item.contract_id == closing_balance.contract_id assert payable_item.account_id == mock_account.account_id @patch( 'src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections_vat' ) @patch('src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections') @patch( 'src.processors.base.payment_batch_processor.fetch_all_flowthrough_allocation_entries' ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_contract_closing_balance_entries' ) def test_both_zero_amounts( mock_fetch_closing_balance: mock.MagicMock, mock_fetch_flowthrough: mock.MagicMock, mock_fetch_wht: mock.MagicMock, mock_fetch_vat: mock.MagicMock, ) -> None: """Test no payment when both flowthrough and closing balance are zero. Scenario: - Contract has $0 flowthrough - Contract has $0 closing balance - Max calculation: max($0, $0) = $0 - No payment created (nothing to pay) - System processes but creates zero-amount worksheet """ # Setup: Create test data mock_event = EventFactory.build(statement_period_id=318) mock_account = EligibleAccountLevelDataFactory.build( account_id=1, currency_code='USD', country_of_tax_policy='USA', country_of_tax_residence='USA', ) closing_balance = ContractCloseBalanceFactory.build( account_id=mock_account.account_id, contract_id=1001, amount=Decimal('0.00'), statement_period_id=mock_event.statement_period_id, ) flowthrough_allocation = FlowthroughAllocationFactory.build( contract_id=closing_balance.contract_id, amount_to_payment=Decimal('0.00'), statement_period_id=mock_event.statement_period_id, ) # Configure mocks mock_fetch_closing_balance.return_value = [closing_balance] mock_fetch_flowthrough.return_value = [flowthrough_allocation] mock_fetch_wht.return_value = [] mock_fetch_vat.return_value = [] # Create processor and run processor = PaymentBatchProcessor( abacus_event=mock_event, accounts=[mock_account], ) processor._setup_contract_worksheets() processor._append_flowthrough_allocations_to_worksheets() # Get the worksheet for assertions worksheet = processor._contract_worksheets_by_id[closing_balance.contract_id] # Verify both amounts are zero assert worksheet.payable_amount_pre_tax == Decimal('0') assert worksheet.payable_amount_post_tax == Decimal('0') assert worksheet._closing_balance_detail.amount_payable == Decimal('0') assert len(worksheet._details) == 2 # 1 closing balance + 1 flowthrough # Verify flowthrough allocation detail shows zero ft_details = [ d for d in worksheet._details if d.payable_detail_type_id == PayableDetailTypes.flowthrough_allocation ] assert len(ft_details) == 1 assert ft_details[0].amount_payable == Decimal('0') # Verify payable item shows zero payable_item = worksheet.get_payable_balance_after_tax_item() assert payable_item.payable_amount_pre_tax == Decimal('0') assert payable_item.payable_amount_post_tax == Decimal('0') assert payable_item.contract_id == closing_balance.contract_id assert payable_item.account_id == mock_account.account_id @patch( 'src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections_vat' ) @patch('src.processors.base.payment_batch_processor.fetch_all_pending_tax_corrections') @patch( 'src.processors.base.payment_batch_processor.fetch_all_flowthrough_allocation_entries' ) @patch( 'src.processors.base.payment_batch_processor.fetch_all_contract_closing_balance_entries' ) def test_no_flowthrough_allocations_standard_payment( mock_fetch_closing_balance: mock.MagicMock, mock_fetch_flowthrough: mock.MagicMock, mock_fetch_wht: mock.MagicMock, mock_fetch_vat: mock.MagicMock, ) -> None: """Test standard payment when no flowthrough allocations exist. Scenario: - Contract has $0 flowthrough (no allocations) - Contract has $1000 closing balance - No flowthrough allocations retrieved for this contract - Payment created for $1000 using standard logic (existing behavior) - No flowthrough worksheet records created """ # Setup: Create test data mock_event = EventFactory.build(statement_period_id=318) mock_account = EligibleAccountLevelDataFactory.build( account_id=1, currency_code='USD', country_of_tax_policy='USA', country_of_tax_residence='USA', ) closing_balance = ContractCloseBalanceFactory.build( account_id=mock_account.account_id, contract_id=1001, amount=Decimal('1000.00'), statement_period_id=mock_event.statement_period_id, ) # Configure mocks - no flowthrough allocations mock_fetch_closing_balance.return_value = [closing_balance] mock_fetch_flowthrough.return_value = [] # No flowthrough allocations mock_fetch_wht.return_value = [] mock_fetch_vat.return_value = [] # Create processor and run processor = PaymentBatchProcessor( abacus_event=mock_event, accounts=[mock_account], ) processor._setup_contract_worksheets() processor._append_flowthrough_allocations_to_worksheets() # Get the worksheet for assertions worksheet = processor._contract_worksheets_by_id[closing_balance.contract_id] # Verify standard payment behavior (closing balance only) assert worksheet.payable_amount_pre_tax == Decimal('1000.00') assert worksheet.payable_amount_post_tax == Decimal('1000.00') assert worksheet._closing_balance_detail.amount_payable == Decimal('1000.00') assert len(worksheet._details) == 1 # Only closing balance detail # Verify no flowthrough allocation details ft_details = [ d for d in worksheet._details if d.payable_detail_type_id == PayableDetailTypes.flowthrough_allocation ] assert len(ft_details) == 0 # Verify payable item payable_item = worksheet.get_payable_balance_after_tax_item() assert payable_item.payable_amount_pre_tax == Decimal('1000.00') assert payable_item.payable_amount_post_tax == Decimal('1000.00') assert payable_item.contract_id == closing_balance.contract_id assert payable_item.account_id == mock_account.account_id