"""Unit tests for payment_group_payment_account logic.""" from decimal import Decimal from unittest.mock import call, MagicMock, patch from abacus_common_logic.connectors.database import db from marshmallow.exceptions import ValidationError import pytest from sqlalchemy import func, select from payment.constants.constants import PAYMENT_TYPES from payment.logic import payment_group_payment_account as logic from payment.logic.exceptions import EntityDoesNotExist, LogicError from payment.models import PaymentGroupPaymentAccount from tests.utils.factories import ( PaymentDebitCreditDataEntryFactory, PaymentGroupPaymentAccountDetailFactory, PaymentGroupPaymentAccountFactory, PaymentGroupPaymentFactory, WorksheetAccountContractClosingBalanceFactory, WorksheetPayableBalanceAfterTaxFactory, ) @patch( 'payment.logic.payment_group_payment_account.' '_create_payment_group_payment_account_details' ) @patch('payment.logic.payment_group_payment_account._validate_params') @patch('payment.logic.payment_group_payment_account._get_matching_payments') @patch('payment.logic.payment_group_payment_account.models') def test_bulk_create_success( mock_models, mock_get_matching_payment, mock_validate_params, mock_create_payment_group_payment_account_details, mock_accounts, mock_contracts, mock_abacus_event, mock_worksheet_account_contract_closing_balance, ): """Test successfully creating multiple payment_group_payment_account records.""" payment_group_payment = PaymentGroupPaymentFactory.create() payment_group_payment_account1 = PaymentGroupPaymentAccountFactory.create() payment_group_payment_account2 = PaymentGroupPaymentAccountFactory.create() worksheet_payable = WorksheetPayableBalanceAfterTaxFactory.create() mock_models.PaymentGroupPayment.get_by_id.return_value = payment_group_payment mock_models.PaymentGroupPaymentAccount.build.side_effect = [ payment_group_payment_account1, payment_group_payment_account2, ] mock_models.WorksheetPayableBalanceAfterTax.get_by_payment_group_payment_and_account_ids.return_value = { worksheet_payable.account_id: [worksheet_payable] } mock_validate_params.return_value = None mock_get_matching_payment.return_value = {} params = [ { 'account_id': 1, 'contracts_payable': [ { 'contract_id': 123, 'current_balance': '100.00', 'currency_code': 'USD', } ], 'currency_code': 'USD', 'current_balance': '100.00', 'last_payment': '1000.00', }, { 'account_id': 2, 'contracts_payable': [ { 'contract_id': 456, 'current_balance': '150.00', 'currency_code': 'CAD', }, { 'contract_id': 789, 'current_balance': '50.00', 'currency_code': 'CAD', }, ], 'currency_code': 'CAD', 'current_balance': '200.00', 'last_payment': '2000.00', }, ] logic.bulk_create(payment_group_payment.payment_group_payment_id, params) assert db.session.execute( select(func.count()).select_from(select(PaymentGroupPaymentAccount).subquery()) ).scalar_one() == len(params) assert mock_models.PaymentGroupPaymentAccount.build.call_count == len(params) assert mock_validate_params.call_count == len(params) assert ( mock_models.WorksheetPayableBalanceAfterTax.get_by_payment_group_payment_and_account_ids.call_args_list == [call(payment_group_payment.payment_group_payment_id, [1, 2], True)] ) assert mock_get_matching_payment.call_args_list == [call([worksheet_payable])] assert mock_create_payment_group_payment_account_details.call_args_list == [ call([worksheet_payable]), call([]), ] assert mock_create_payment_group_payment_account_details.call_count == len(params) @patch( 'payment.logic.payment_group_payment_account.' '_create_payment_group_payment_account_details' ) @patch('payment.logic.payment_group_payment_account._validate_params') @patch('payment.logic.payment_group_payment_account._get_matching_payments') @patch('payment.logic.payment_group_payment_account.models') def test_bulk_create_success_pending_payment( mock_models, mock_get_matching_payment, mock_validate_params, mock_create_payment_group_payment_account_details, mock_accounts, mock_contracts, mock_abacus_event, mock_worksheet_account_contract_closing_balance, ): """Test successfully creating multiple payment_group_payment_account records.""" payment_group_payment = PaymentGroupPaymentFactory.create() payment_group_payment_account1 = PaymentGroupPaymentAccountFactory.create() payment_group_payment_account2 = PaymentGroupPaymentAccountFactory.create() worksheet_payable = WorksheetPayableBalanceAfterTaxFactory.create() mock_models.PaymentGroupPayment.get_by_id.return_value = payment_group_payment mock_models.PaymentGroupPaymentAccount.build.side_effect = [ payment_group_payment_account1, payment_group_payment_account2, ] mock_models.WorksheetPayableBalanceAfterTax.get_by_payment_group_payment_and_account_ids.return_value = { worksheet_payable.account_id: [worksheet_payable] } mock_validate_params.return_value = None pending_payment = PaymentGroupPaymentFactory.create() mock_get_matching_payment.return_value = { payment_group_payment_account1.account_id: [pending_payment] } params = [ { 'account_id': 1, 'contracts_payable': [ { 'contract_id': 123, 'current_balance': '100.00', 'currency_code': 'USD', } ], 'currency_code': 'USD', 'current_balance': '100.00', 'last_payment': '1000.00', }, { 'account_id': 2, 'contracts_payable': [ { 'contract_id': 456, 'current_balance': '150.00', 'currency_code': 'CAD', }, { 'contract_id': 789, 'current_balance': '50.00', 'currency_code': 'CAD', }, ], 'currency_code': 'CAD', 'current_balance': '200.00', 'last_payment': '2000.00', }, ] logic.bulk_create(payment_group_payment.payment_group_payment_id, params) assert db.session.execute( select(func.count()).select_from(select(PaymentGroupPaymentAccount).subquery()) ).scalar_one() == len(params) assert mock_models.PaymentGroupPaymentAccount.build.call_count == len(params) assert params[0]['prior_payment_group_payment_id'] == 4 assert params[1]['prior_payment_group_payment_id'] is None assert mock_validate_params.call_count == len(params) assert ( mock_models.WorksheetPayableBalanceAfterTax.get_by_payment_group_payment_and_account_ids.call_args_list == [call(payment_group_payment.payment_group_payment_id, [1, 2], True)] ) assert mock_get_matching_payment.call_args_list == [call([worksheet_payable])] assert mock_create_payment_group_payment_account_details.call_args_list == [ call([worksheet_payable]), call([]), ] assert mock_create_payment_group_payment_account_details.call_count == len(params) @patch('payment.logic.payment_group_payment_account._validate_params') @patch('payment.logic.payment_group_payment_account._get_pending_payment') @patch('payment.logic.payment_group_payment_account.models') def test_bulk_create_error( mock_models, mock_get_pending_payment, mock_validate_params, mock_accounts ): """Test bulk creation returns error when params are invalid.""" payment_group_payment = PaymentGroupPaymentFactory.create() mock_models.PaymentGroupPayment.get_by_id.return_value = payment_group_payment mock_validate_params.side_effect = ValidationError('no bueno') mock_get_pending_payment.return_value = None params = { 'account_id': 1, 'contracts_payable': [ {'contract_id': 123, 'current_balance': '100.00', 'currency_code': 'USD'} ], 'currency_code': 'USD', 'current_balance': '100.00', 'last_payment': '1000.00', } with pytest.raises(LogicError, match='no bueno'): logic.bulk_create(payment_group_payment.payment_group_payment_id, [params]) assert ( db.session.execute( select(func.count()).select_from( select(PaymentGroupPaymentAccount).subquery() ) ).scalar_one() == 0 ) mock_validate_params.assert_called_once_with(params) mock_get_pending_payment.assert_not_called() mock_models.PaymentGroupPaymentAccount.build.assert_not_called() @patch('payment.logic.payment_group_payment_account.payment_allocation_repository') @patch('payment.logic.payment_group_payment_account.payable_details_repository') @patch('payment.logic.payment_group_payment_account.models') def test_delete_payment_group_payment_account( mock_models, payable_details_repository_mock, payment_allocation_repository_mock, mock_accounts, ): """Test successfully soft deleting a payment_group_payment_account.""" mock_models.PaymentGroupPaymentAccount.delete_by_id_or_error.return_value = None payment_allocation_repository_mock.reset_to_init_by_payment_group_payment_account.return_value = 2 payment_account = PaymentGroupPaymentAccountFactory.create() object_id = payment_account.payment_group_payment_account_id mock_models.PaymentGroupPaymentAccount.get_by_id.return_value = payment_account payment_account.payment_group_payment.is_posted = MagicMock(return_value=False) res = logic.delete_payment_group_payment_account(object_id) assert res is None mock_models.PaymentGroupPaymentAccount.get_by_id.assert_called_once_with(object_id) payment_allocation_repository_mock.reset_to_init_by_payment_group_payment_account.assert_called_once_with( payment_account.payment_group_payment_account_id ) mock_models.PaymentGroupPaymentAccount.delete_by_id_or_error.assert_called_once_with( payment_account.payment_group_payment_account_id, soft_delete=True ) mock_models.PaymentGroupPaymentAccountDetail.soft_delete_by_payment_group_payment_account.assert_called_once_with( payment_account.payment_group_payment_account_id ) mock_models.WorksheetPayableBalanceAfterTax.soft_delete_by_payment_group_payment_account.assert_called_once_with( payment_account.payment_group_payment_account_id ) payable_details_repository_mock.soft_delete_by_payment_group_payment_account.assert_called_once_with( payment_account.payment_group_payment_account_id ) @patch('payment.logic.payment_group_payment_account.models.PaymentGroupPaymentAccount') def test_delete_payment_group_payment_account_error( mock_payment_account_models, mock_accounts ): """Test LogicError is raised when parent payment_group_payment is posted.""" payment_account = PaymentGroupPaymentAccountFactory.create() object_id = payment_account.payment_group_payment_account_id mock_payment_account_models.get_by_id.return_value = payment_account payment_account.payment_group_payment.is_sent = MagicMock(return_value=True) with pytest.raises(LogicError): logic.delete_payment_group_payment_account(object_id) mock_payment_account_models.delete_by_id_or_error.assert_not_called() @patch('payment.logic.payment_group_payment_account.models.PaymentGroupPaymentAccount') def test_delete_payment_group_payment_account_not_found(mock_payment_account_models): """Test EntityDoesNotExist is raised when account is not found.""" mock_payment_account_models.get_by_id.return_value = None with pytest.raises(EntityDoesNotExist): logic.delete_payment_group_payment_account(999) mock_payment_account_models.delete_by_id_or_error.assert_not_called() @patch('payment.logic.payment_group_payment_account.models') def test_get_accounts_list(mock_models, mock_accounts): """Test getting a list of payment_group_payment_accounts.""" payment_group_payment = PaymentGroupPaymentFactory.create() payment_accounts = [ PaymentGroupPaymentAccountFactory.create( account_id=i, payment_group_payment=payment_group_payment, vat_amount=Decimal('20.00'), ) for i in range(1, 6) ] params = { 'limit': 10, 'offset': 0, 'payment_group_payment_id': payment_group_payment.payment_group_payment_id, 'sort_by': 'account_name', 'sort_order': 'asc', } mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment.return_value = ( payment_accounts ) mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment_count.return_value = len( payment_accounts ) res = logic.get_accounts_list(**params) assert res.items == payment_accounts assert res.total_count == len(payment_accounts) assert all(item.vat_amount == Decimal('20.00') for item in res.items) mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment.assert_called_once_with( limit=params.get('limit'), offset=params.get('offset'), order_by=params.get('sort_by'), order_dir=params.get('sort_order'), payment_group_payment_id=payment_group_payment.payment_group_payment_id, is_pending=False, search_term=None, ) mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment_count.assert_called_once_with( payment_group_payment.payment_group_payment_id, False, None ) @patch('payment.logic.payment_group_payment_account.models') def test_get_accounts_list_search(mock_models, mock_accounts): """Test getting a list of payment_group_payment_accounts.""" payment_group_payment = PaymentGroupPaymentFactory.create() params = { 'limit': 10, 'offset': 0, 'payment_group_payment_id': payment_group_payment.payment_group_payment_id, 'sort_by': 'account_name', 'sort_order': 'asc', 'search_term': 'account name', } mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment.return_value = [] mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment_count.return_value = 0 res = logic.get_accounts_list(**params) assert res.items == [] assert res.total_count == 0 mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment.assert_called_once_with( limit=params.get('limit'), offset=params.get('offset'), order_by=params.get('sort_by'), order_dir=params.get('sort_order'), payment_group_payment_id=payment_group_payment.payment_group_payment_id, is_pending=False, search_term='account name', ) mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment_count.assert_called_once_with( payment_group_payment.payment_group_payment_id, False, 'account name' ) @patch('payment.logic.payment_group_payment_account.models') def test_get_accounts_list_pending(mock_models, mock_accounts): """Test getting a list of pending payment_group_payment_accounts.""" prior = PaymentGroupPaymentFactory.create() payment_group_payment = PaymentGroupPaymentFactory.create() payment_accounts = [ PaymentGroupPaymentAccountFactory.create( account_id=i, prior_payment_group_payment_id=prior.payment_group_payment_id, payment_group_payment=payment_group_payment, ) for i in range(1, 6) ] params = { 'is_pending': True, 'limit': 10, 'offset': 0, 'payment_group_payment_id': payment_group_payment.payment_group_payment_id, 'sort_by': 'account_name', 'sort_order': 'asc', } mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment.return_value = ( payment_accounts ) mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment_count.return_value = len( payment_accounts ) res = logic.get_accounts_list(**params) assert res.items == payment_accounts assert res.total_count == len(payment_accounts) mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment.assert_called_once_with( limit=params.get('limit'), offset=params.get('offset'), order_by=params.get('sort_by'), order_dir=params.get('sort_order'), payment_group_payment_id=payment_group_payment.payment_group_payment_id, is_pending=True, search_term=None, ) mock_models.PaymentGroupPaymentAccount.get_by_payment_group_payment_count.assert_called_once_with( payment_group_payment.payment_group_payment_id, True, None ) @patch('payment.logic.payment_group_payment_account.models.PaymentGroupPaymentAccount') def test_get_payment_group_payment_account_success( mock_payment_account_models, mock_accounts ): """Test get_payment_group_payment_account returns the account when found.""" payment_account = PaymentGroupPaymentAccountFactory.create() object_id = payment_account.payment_group_payment_account_id mock_payment_account_models.get_by_id.return_value = payment_account res = logic.get_payment_group_payment_account(object_id) assert res == payment_account mock_payment_account_models.get_by_id.assert_called_once_with(object_id) @patch('payment.logic.payment_group_payment_account.models.PaymentGroupPaymentAccount') def test_get_payment_group_payment_account_not_found(mock_payment_account_models): """Test EntityDoesNotExist is raised when account is not found.""" mock_payment_account_models.get_by_id.return_value = None with pytest.raises(EntityDoesNotExist): logic.get_payment_group_payment_account(999) @patch('payment.logic.payment_group_payment_account.models') def test_get_last_posted_payment_by_account(mock_models, mock_accounts): """Test getting an account's last posted payment.""" payment_account = PaymentGroupPaymentAccountFactory.create() account_id = payment_account.account_id mock_models.PaymentGroupPaymentAccount.last_posted_payment_by_account.return_value = payment_account res = logic.get_last_posted_payment_by_account(account_id) assert res == payment_account mock_models.PaymentGroupPaymentAccount.last_posted_payment_by_account.assert_called_once_with( account_id ) @patch('payment.logic.payment_group_payment_account.models') def test_get_last_posted_payment_by_account_none(mock_models, mock_accounts): """Test getting an account's last posted payment when it does not have one.""" account_id = 1 mock_models.PaymentGroupPaymentAccount.last_posted_payment_by_account.return_value = None res = logic.get_last_posted_payment_by_account(account_id) assert res is None mock_models.PaymentGroupPaymentAccount.last_posted_payment_by_account.assert_called_once_with( account_id ) @patch('payment.logic.payment_group_payment_account._get_pending_payment') def test_get_pending_payment_by_account(mock_get_pending_payment, mock_accounts): """Test getting an account's pending payment.""" pending_payment = PaymentGroupPaymentAccountFactory.create() account_id = pending_payment.account_id mock_get_pending_payment.return_value = pending_payment res = logic.get_pending_payment_by_account(account_id) assert res == pending_payment mock_get_pending_payment.assert_called_once_with(account_id) @patch('payment.logic.payment_group_payment_account._get_pending_payment') def test_get_pending_payment_by_account_none(mock_get_pending_payment, mock_accounts): """Test getting an account's pending payment when it does not have any.""" account_id = 123 mock_get_pending_payment.return_value = None res = logic.get_pending_payment_by_account(account_id) assert res is None mock_get_pending_payment.assert_called_once_with(account_id) @patch('payment.logic.payment_group_payment_account.models') def test_get_totals_by_payment_group_payment(mock_models): """Test successfully getting account and amount totals grouped by currency.""" payment_group_payment_id = 1 expected_response = [ { 'account_count': 10, 'currency_code': 'EUR', 'currency_total': 1000.00, 'payment_group_payment_id': payment_group_payment_id, }, { 'account_count': 2, 'currency_code': 'GBP', 'currency_total': 200.00, 'payment_group_payment_id': payment_group_payment_id, }, ] mock_models.PaymentGroupPayment.get_by_id.return_value = None mock_models.PaymentGroupPaymentAccount.group_by_currency_code.return_value = ( expected_response ) res = logic.get_totals_by_payment_group_payment(payment_group_payment_id) assert res == expected_response mock_models.PaymentGroupPaymentAccount.group_by_currency_code.assert_called_once_with( payment_group_payment_id ) @patch('payment.logic.payment_group_payment_account.models') def test_get_totals_by_payment_group_payment_ids(mock_models): """Test successfully getting account and amount totals grouped by currency from many payment_group_payments.""" ids = [456356, 97858987] expected_response = [ { 'data': { 'account_count': 10, 'currency_code': 'EUR', 'currency_total': 1000.00, 'payment_group_payment_id': ids[0], } }, { 'data': { 'account_count': 2, 'currency_code': 'GBP', 'currency_total': 200.00, 'payment_group_payment_id': ids[1], } }, ] mock_models.PaymentGroupPaymentAccount.group_by_currency_code_for_many_payment_group_payments.return_value = [ row['data'] for row in expected_response ] result = logic.get_totals_by_payment_group_payment_ids(ids) assert len(result['items']) == len(expected_response) mock_models.PaymentGroupPaymentAccount.group_by_currency_code_for_many_payment_group_payments.assert_called_once_with( ids ) @patch('payment.logic.payment_group_payment_account.models') def test_get_totals_by_payment_group_payment_ids_with_none(mock_models): """Test successfully getting account and amount totals grouped by currency from many payment_group_payments.""" ids = [456356, 97858987] expected_response = [ { 'data': { 'account_count': 10, 'currency_code': 'EUR', 'currency_total': 1000.00, 'payment_group_payment_id': ids[0], } }, {'data': None}, ] mock_models.PaymentGroupPaymentAccount.group_by_currency_code_for_many_payment_group_payments.return_value = [ row['data'] for row in expected_response ] result = logic.get_totals_by_payment_group_payment_ids(ids) assert result['items'][1]['data'] is None mock_models.PaymentGroupPaymentAccount.group_by_currency_code_for_many_payment_group_payments.assert_called_once_with( ids ) @patch('payment.logic.payment_group_payment_account.models') def test_update_payment_group_payment_account(mock_models, mock_accounts): """Test successfully updating a payment_group_payment_account.""" payment_account = PaymentGroupPaymentAccountFactory.create() object_id = payment_account.payment_group_payment_account_id mock_models.PaymentGroupPaymentAccount.get_by_id.return_value = payment_account mock_models.PaymentGroupPaymentAccount.commit_changes.return_value = None new_note = 'duly noted' assert not payment_account.note res = logic.update_payment_group_payment_account(object_id, new_note) assert res == payment_account assert res.note == new_note mock_models.PaymentGroupPaymentAccount.get_by_id.assert_called_once_with(object_id) mock_models.PaymentGroupPaymentAccount.commit_changes.assert_called_once() @patch('payment.logic.payment_group_payment_account.models.PaymentGroupPaymentAccount') def test_update_payment_group_payment_account_not_found(mock_payment_account_models): """Test EntityDoesNotExist is raised when account is not found.""" mock_payment_account_models.get_by_id.return_value = None with pytest.raises(EntityDoesNotExist): logic.update_payment_group_payment_account(999, 'some note') mock_payment_account_models.commit_changes.assert_not_called() @patch('payment.logic.payment_group_payment_account.models') def test_get_pending_payment(mock_models, mock_accounts): """Test getting an account's pending payments.""" payment_account = PaymentGroupPaymentAccountFactory.create() mock_models.PaymentGroupPaymentAccount.pending_payments_by_account.return_value = [ payment_account ] res = logic._get_pending_payment(payment_account.account_id) assert res == payment_account @patch('payment.logic.payment_group_payment_account.models') def test_get_pending_payment_none(mock_models): """Test getting an account's pending payments when it has none.""" mock_models.PaymentGroupPaymentAccount.pending_payments_by_account.return_value = [] res = logic._get_pending_payment(123) assert not res @patch('payment.logic.payment_group_payment_account.validate_currency') def test_validate_params_valid(mock_validate_currency): """Test when parameters are valid.""" mock_validate_currency.return_value = None res = logic._validate_params({'currency_code': 'USD'}) assert res is None @patch('payment.logic.payment_group_payment_account.validate_currency') def test_validate_params_invalid_currency(mock_validate_currency): """Test when currency is invalid.""" mock_validate_currency.return_value.errors = MagicMock({'message': 'NO'}) with pytest.raises(ValidationError): logic._validate_params({'currency_code': 'OMG'}) @patch('payment.logic.payment_group_payment_account.models') def test_get_totals_grouped_by_program_id(mock_models): """Test successfully getting amount totals grouped by payoneer program id.""" payment_group_payment_id = 1 expected_response = [ { 'account_count': 5, 'currency_code': 'EUR', 'currency_total': 1000.00, 'payoneer_program_id': 1, 'payment_entity_name': 'AWAL-UK', }, { 'account_count': 2, 'currency_code': 'USD', 'currency_total': 1500.00, 'payoneer_program_id': 2, 'payment_entity_name': 'AWAL-UK', }, ] mock_models.PaymentGroupPayment.get_by_id.return_value = None mock_models.PaymentGroupPaymentAccount.get_payment_totals_grouped_by_program_id.return_value = expected_response res = logic.get_totals_grouped_by_program_id(payment_group_payment_id) assert res == expected_response mock_models.PaymentGroupPaymentAccount.get_payment_totals_grouped_by_program_id.assert_called_once_with( payment_group_payment_id ) @patch('payment.logic.payment_group_payment_account.models') def test_create_payment_group_payment_account_details( mock_models, mock_accounts, mock_statement_periods, mock_contracts, mock_abacus_event, mock_ledger_account_contracts, mock_worksheet_account_contract_closing_balance, ): """Test _create_payment_group_payment_account_details function.""" worksheet = WorksheetPayableBalanceAfterTaxFactory.create() logic._create_payment_group_payment_account_details([worksheet]) assert mock_models.PaymentGroupPaymentAccountDetail.build.call_args_list == [ call( worksheet_account_contract_payable_after_tax_id=worksheet.worksheet_account_contract_payable_after_tax_id, # noqa account_id=worksheet.account_id, contract_id=worksheet.contract_id, payable_amount_pre_tax=worksheet.payable_amount_pre_tax, tax_withholding_amount=worksheet.tax_withholding_amount, vat_amount=worksheet.vat_amount, payable_amount_post_tax=worksheet.payable_amount_post_tax, currency_code=worksheet.currency_code, ) ] @pytest.mark.parametrize('payment_type', PAYMENT_TYPES) @patch('payment.logic.payment_group_payment_account.models') def test_get_credit_data( mock_models, payment_type, mock_accounts, mock_contracts, mock_abacus_event, mock_ledger_account_contracts, ): """Test get_credit_data method.""" worksheet_closing_balance = WorksheetAccountContractClosingBalanceFactory.create() worksheet_after_tax1 = WorksheetPayableBalanceAfterTaxFactory.create( # noqa worksheet_account_contract_closing_balance_id=worksheet_closing_balance.worksheet_account_contract_closing_balance_id ) detail = PaymentGroupPaymentAccountDetailFactory.create( # noqa worksheet_account_contract_payable_after_tax_id=worksheet_after_tax1.worksheet_account_contract_payable_after_tax_id ) mock_models.PaymentGroupPaymentAccountDetail.get_by_payment_group_payment_account.return_value = [ # noqa detail ] mock_data_entry = PaymentDebitCreditDataEntryFactory.build() mock_models.PaymentDebitCreditDataEntry.return_value = mock_data_entry res = logic.get_credit_data(detail.payment_group_payment_account, payment_type) match payment_type: case PAYMENT_TYPES.WHT: # negative according to formula, make positive amount = ( detail.tax_withholding_amount * -1 if detail.tax_withholding_amount else detail.tax_withholding_amount ) case PAYMENT_TYPES.VAT: # positive according to formula, make negative amount = detail.vat_amount * -1 if detail.vat_amount else detail.vat_amount case _: # positive according to formula, return as is amount = detail.payable_amount_post_tax assert res == [mock_data_entry] assert ( mock_models.PaymentGroupPaymentAccountDetail.get_by_payment_group_payment_account.call_args_list == [ # noqa call( detail.payment_group_payment_account, ) ] ) assert mock_models.PaymentDebitCreditDataEntry.call_args_list == [ call( detail.account_id, detail.contract_id, detail.currency_code, amount, detail.worksheet_account_contract_payable_after_tax_id, ) ] @pytest.mark.parametrize('payment_type', PAYMENT_TYPES) @patch('payment.logic.payment_group_payment_account.models') def test_get_credit_data_no_zero_amounts( mock_models, payment_type, mock_accounts, mock_contracts, mock_abacus_event, mock_ledger_account_contracts, ): """Test get_credit_data method.""" worksheet_closing_balance = WorksheetAccountContractClosingBalanceFactory.create() worksheet_after_tax1 = WorksheetPayableBalanceAfterTaxFactory.create( # noqa worksheet_account_contract_closing_balance_id=worksheet_closing_balance.worksheet_account_contract_closing_balance_id ) detail = PaymentGroupPaymentAccountDetailFactory.create( # noqa worksheet_account_contract_payable_after_tax_id=worksheet_after_tax1.worksheet_account_contract_payable_after_tax_id, payable_amount_pre_tax=0, tax_withholding_amount=0, payable_amount_post_tax=0, vat_amount=0, ) mock_models.PaymentGroupPaymentAccountDetail.get_by_payment_group_payment_account.return_value = [ # noqa detail ] mock_data_entry = PaymentDebitCreditDataEntryFactory.build() mock_models.PaymentDebitCreditDataEntry.return_value = mock_data_entry res = logic.get_credit_data(detail.payment_group_payment_account, payment_type) assert res == [] @patch( 'payment.logic.payment_group_payment_account.payment_group_payment_account_repository' ) def test_get_last_payments( mock_repository, mock_abacus_event, mock_statement_periods, mock_accounts, mock_contracts, faker, ): """Test get_last_payments function.""" payment_group_payment_account = PaymentGroupPaymentAccountFactory.create() account_ids = faker.pylist(value_types=[int]) payment_statuses = ['init'] limit = faker.pyint(20, 300) offset = faker.pyint(1, 10) mock_repository.get_last_payments.return_value = ( [payment_group_payment_account], 1, ) result = logic.get_last_payments( limit, offset, account_ids, ) assert result == {'items': [payment_group_payment_account], 'total_count': 1} assert mock_repository.get_last_payments.call_args_list == [ call( limit=limit, offset=offset, account_ids=account_ids, ) ] @patch( 'payment.logic.payment_group_payment_account.' 'payment_group_payment_account_repository' ) def test_payments_search( mock_repository, faker, ): """Test payments_search.""" account_ids = [1, 2, 3] contract_ids = [10, 11] payment_statuses = ['active', 'pending'] limit = faker.pyint(1, 200) offset = faker.pyint(0, 20) payment_group_payment = PaymentGroupPaymentFactory.create() mock_repository.payments_search.return_value = ( [payment_group_payment], 1, ) result = logic.payments_search( account_ids=account_ids, contract_ids=contract_ids, payment_statuses=payment_statuses, limit=limit, offset=offset, ) assert result == {'items': [payment_group_payment], 'total_count': 1} assert mock_repository.payments_search.call_args_list == [ call( account_ids=account_ids, contract_ids=contract_ids, payment_statuses=payment_statuses, limit=limit, offset=offset, ) ] def test_get_matching_payments( mock_statement_periods, mock_accounts, mock_contracts, mock_abacus_event, mock_ledger_account_contracts, ): """Test get matching payments returns matching payment.""" statement_period_id = 1 worksheet_closing_balance = WorksheetAccountContractClosingBalanceFactory.create( statement_period_id=statement_period_id ) worksheet_after_tax = WorksheetPayableBalanceAfterTaxFactory.create( # noqa worksheet_account_contract_closing_balance_id=worksheet_closing_balance.worksheet_account_contract_closing_balance_id, statement_period_id=statement_period_id, abacus_event_id=1, ) payment = PaymentGroupPaymentFactory.create() payment_account = PaymentGroupPaymentAccountFactory.create( payment_group_payment=payment, payment_group_payment_id=payment.payment_group_payment_id, ) PaymentGroupPaymentAccountDetailFactory.create( payment_group_payment_account=payment_account, worksheet_account_contract_payable_after_tax_id=worksheet_after_tax.worksheet_account_contract_payable_after_tax_id, ) new_worksheet_after_tax = WorksheetPayableBalanceAfterTaxFactory.create( # noqa worksheet_account_contract_closing_balance_id=worksheet_closing_balance.worksheet_account_contract_closing_balance_id, statement_period_id=statement_period_id, ) result = logic._get_matching_payments([new_worksheet_after_tax]) assert ( result[new_worksheet_after_tax.account_id][0].payment_group_payment_id == payment.payment_group_payment_id )