"""Test utils.""" from unittest import mock from unittest.mock import call, patch from faker import Faker from src import constants, utils from src.models import ( Event, GetAccountTaxInfoResponse, GetFlowThroughAllocationResponse, GetTaxCorrectionsResponse, PaginatedContractCloseBalances, PaginatedPayableBalanceAfterTaxEntries, PaginatedPayableDetailEntries, ) from tests.unit.factories import ( AccountFactory, AccountTaxInfoFactory, ContractCloseBalanceFactory, EventFactory, FlowthroughAllocationFactory, PayableBalanceAfterTaxEntryFactory, PayableDetailEntryFactory, PaymentEntityFactory, TaxCorrectionFactory, ) @patch('src.utils.get_contract_closing_balance_entries') def test_fetch_all_contract_closing_balance_entries( mock_get_contract_closing_balance_entries: mock.MagicMock, ) -> None: """Test fetch_all_contract_closing_balance_entries method to fetch several batches and returns them in one list.""" statement_period_id = 100 account_1 = AccountFactory.build(account_id=1) account_2 = AccountFactory.build(account_id=2) eligible_accounts = [account_1, account_2] contract_close_balance_1 = ContractCloseBalanceFactory.build(account_id=1) contract_close_balance_2 = ContractCloseBalanceFactory.build(account_id=2) first_batch: PaginatedContractCloseBalances = PaginatedContractCloseBalances( items=[contract_close_balance_1], total_count=constants.BATCH_SIZE + 1 ) second_batch: PaginatedContractCloseBalances = PaginatedContractCloseBalances( items=[contract_close_balance_2], total_count=1 ) mock_get_contract_closing_balance_entries.side_effect = [first_batch, second_batch] res = utils.fetch_all_contract_closing_balance_entries( statement_period_id, eligible_accounts ) assert mock_get_contract_closing_balance_entries.call_args_list == [ call( statement_period_id, eligible_accounts, limit=constants.BATCH_SIZE, offset=0 ), call( statement_period_id, eligible_accounts, limit=constants.BATCH_SIZE, offset=constants.BATCH_SIZE, ), ] assert res == [contract_close_balance_1, contract_close_balance_2] @patch('src.utils.get_tax_corrections') def test_fetch_all_pending_tax_corrections( mock_get_tax_corrections: mock.MagicMock, faker: Faker ) -> None: """Test fetch_all_pending_tax_corrections function.""" contract_ids = faker.pylist(allowed_types=[int]) tax_corrections = TaxCorrectionFactory.batch(constants.BATCH_SIZE * 2) mock_get_tax_corrections.side_effect = [ GetTaxCorrectionsResponse( items=tax_corrections[: constants.BATCH_SIZE], total_count=constants.BATCH_SIZE * 2, ), GetTaxCorrectionsResponse( items=tax_corrections[constants.BATCH_SIZE : constants.BATCH_SIZE * 2], total_count=constants.BATCH_SIZE * 2, ), ] res = utils.fetch_all_pending_tax_corrections( constants.TaxCorrectionTypes.wht, contract_ids ) assert res == tax_corrections assert mock_get_tax_corrections.call_args_list == [ call( constants.TaxCorrectionTypes.wht, constants.TaxCorrectionStatuses.pending, None, contract_ids, constants.BATCH_SIZE, 0, ), call( constants.TaxCorrectionTypes.wht, constants.TaxCorrectionStatuses.pending, None, contract_ids, constants.BATCH_SIZE, constants.BATCH_SIZE, ), ] @patch('src.utils.get_account_tax_info') def test_fetch_all_account_tax_info_entries( mock_get_account_tax_info: mock.MagicMock, faker: Faker ) -> None: """Test fetch_all_account_tax_info_entries function.""" account_ids = faker.pylist(allowed_types=[int]) entries = AccountTaxInfoFactory.batch(constants.BATCH_SIZE * 2) mock_get_account_tax_info.side_effect = [ GetAccountTaxInfoResponse( items=entries[: constants.BATCH_SIZE], total_count=constants.BATCH_SIZE * 2 ), GetAccountTaxInfoResponse( items=entries[constants.BATCH_SIZE : constants.BATCH_SIZE * 2], total_count=constants.BATCH_SIZE * 2, ), ] res = utils.fetch_all_account_tax_info_entries(account_ids) assert res == entries assert mock_get_account_tax_info.call_args_list == [ call(account_ids, constants.BATCH_SIZE, 0), call(account_ids, constants.BATCH_SIZE, constants.BATCH_SIZE), ] def test_create_payment_entity_to_country_of_tax_policy_mapping() -> None: """Test create_payment_entity_to_country_of_tax_policy_mapping.""" # noqa: E501 ref_payment_entities = [ PaymentEntityFactory.build( reference_payment_entity_id=25, country_of_tax_reporting='UK' ), PaymentEntityFactory.build( reference_payment_entity_id=10, country_of_tax_reporting='US' ), ] expected_res = {25: 'UK', 10: 'US'} res = utils.create_payment_entity_to_country_of_tax_reporting_mapping( ref_payment_entities ) assert res == expected_res @patch('src.utils.get_flowthrough_allocation_entries') def test_fetch_all_flowthrough_allocation_entries( mock_get_flowthrough_allocation_entries: mock.MagicMock, faker: Faker ) -> None: """Test fetch_all_flowthrough_allocation_entries function to fetch several batches and returns them in one list.""" contract_ids = faker.pylist(allowed_types=[int]) allocation_1 = FlowthroughAllocationFactory.build() allocation_2 = FlowthroughAllocationFactory.build() first_batch: GetFlowThroughAllocationResponse = GetFlowThroughAllocationResponse( items=[allocation_1], total_count=constants.BATCH_SIZE + 1 ) second_batch: GetFlowThroughAllocationResponse = GetFlowThroughAllocationResponse( items=[allocation_2], total_count=constants.BATCH_SIZE // 2 ) mock_get_flowthrough_allocation_entries.side_effect = [first_batch, second_batch] res = utils.fetch_all_flowthrough_allocation_entries(contract_ids) assert mock_get_flowthrough_allocation_entries.call_args_list == [ call(contract_ids=set(contract_ids), limit=constants.BATCH_SIZE, offset=0), call( contract_ids=set(contract_ids), limit=constants.BATCH_SIZE, offset=constants.BATCH_SIZE, ), ] assert res == [allocation_1, allocation_2] @patch('src.utils.get_contract_closing_balance_entries_bulk') def test_fetch_all_contract_closing_balance_entries_bulk( mock_get_contract_closing_balance_entries_bulk: mock.MagicMock, ) -> None: """Test fetch_all_contract_closing_balance_entries_bulk paginates by closing balance ids and returns the aggregated entries.""" closing_balance_ids = [11, 22] contract_close_balance_1 = ContractCloseBalanceFactory.build() contract_close_balance_2 = ContractCloseBalanceFactory.build() mock_get_contract_closing_balance_entries_bulk.side_effect = [ PaginatedContractCloseBalances( items=[contract_close_balance_1], total_count=constants.BATCH_SIZE_REFRESH + 1, ), PaginatedContractCloseBalances( items=[contract_close_balance_2], total_count=constants.BATCH_SIZE_REFRESH + 1, ), ] res = utils.fetch_all_contract_closing_balance_entries_bulk(closing_balance_ids) assert res == [contract_close_balance_1, contract_close_balance_2] assert mock_get_contract_closing_balance_entries_bulk.call_args_list == [ call(closing_balance_ids, limit=constants.BATCH_SIZE_REFRESH, offset=0), call( closing_balance_ids, limit=constants.BATCH_SIZE_REFRESH, offset=constants.BATCH_SIZE_REFRESH, ), ] @patch('src.utils.get_payable_details_entries') def test_fetch_all_payable_details_entries( mock_get_payable_details_entries: mock.MagicMock, ) -> None: """Test fetch_all_payable_details_entries forwards filters and paginates.""" statement_period_id = 7 after_tax_ids = [1, 2] detail_groups = constants.CORRECTION_DETAIL_GROUPS detail_1 = PayableDetailEntryFactory.build() detail_2 = PayableDetailEntryFactory.build() mock_get_payable_details_entries.side_effect = [ PaginatedPayableDetailEntries( items=[detail_1], total_count=constants.BATCH_SIZE + 1 ), PaginatedPayableDetailEntries( items=[detail_2], total_count=constants.BATCH_SIZE + 1 ), ] res = utils.fetch_all_payable_details_entries( statement_period_id, after_tax_ids, detail_groups ) assert res == [detail_1, detail_2] assert mock_get_payable_details_entries.call_args_list == [ call( statement_period_id, after_tax_ids, detail_groups, limit=constants.BATCH_SIZE, offset=0, ), call( statement_period_id, after_tax_ids, detail_groups, limit=constants.BATCH_SIZE, offset=constants.BATCH_SIZE, ), ] @patch('src.utils.get_contract_balance_after_tax_entries') def test_get_all_payable_balance_after_tax_entries_by_event( mock_get_contract_balance_after_tax_entries: mock.MagicMock, ) -> None: """Test get_all_payable_balance_after_tax_entries_by_event paginates by event.""" event: Event = EventFactory.build() entry_1 = PayableBalanceAfterTaxEntryFactory.build() entry_2 = PayableBalanceAfterTaxEntryFactory.build() mock_get_contract_balance_after_tax_entries.side_effect = [ PaginatedPayableBalanceAfterTaxEntries( items=[entry_1], total_count=constants.BATCH_SIZE_REFRESH + 1 ), PaginatedPayableBalanceAfterTaxEntries( items=[entry_2], total_count=constants.BATCH_SIZE_REFRESH + 1 ), ] res = utils.get_all_payable_balance_after_tax_entries_by_event(event) assert res == [entry_1, entry_2] assert mock_get_contract_balance_after_tax_entries.call_args_list == [ call(event.abacus_event_id, limit=constants.BATCH_SIZE_REFRESH, offset=0), call( event.abacus_event_id, limit=constants.BATCH_SIZE_REFRESH, offset=constants.BATCH_SIZE_REFRESH, ), ]