"""Tests for payment allocation repository.""" from unittest.mock import patch from abacus_common_logic.connectors.database import db from sqlalchemy import select from payment.constants.constants import ( PAYMENT_ALLOCATION_LEDGER_STATUSES, PAYMENT_ALLOCATION_STATUSES, ) from payment.models.payment_allocation import PaymentAllocationFlowthrough from payment.repository import payment_allocation as repository from tests.utils.factories import ( PaymentAllocationFlowthroughFactory, PaymentGroupPaymentFactory, ) @patch( 'payment.repository.payment_allocation.get_flask_user_id', return_value='test_user', ) def test_reset_to_init_by_payment_group_payment_resets_attached_allocations( _mock_get_user_id, fresh_db, mock_contracts ): """Test that reset_to_init_by_payment_group_payment resets allocations using subquery.""" from abacus_common_logic.models.base import db as test_db payment = PaymentGroupPaymentFactory.create() test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=0')) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account (payment_group_payment_account_id, payment_group_payment_id, account_id, payoneer_program_id, current_statement_period_id, currency_code, last_payment, current_balance, balance_after_tax, created_at, created_by, last_modified, last_modified_by) VALUES (1001, :pgp_id, 1, 100158970, 1, 'USD', '0.00', '0.00', '0.00', NOW(), 'test', NOW(), 'test'), (1002, :pgp_id, 2, 100158970, 1, 'USD', '0.00', '0.00', '0.00', NOW(), 'test', NOW(), 'test') """ ), {'pgp_id': payment.payment_group_payment_id}, ) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account_detail (payment_group_payment_account_id, worksheet_account_contract_payable_after_tax_id, account_id, contract_id, payable_amount_pre_tax, tax_withholding_amount, payable_amount_post_tax, currency_code, vat_amount, created_at, created_by, last_modified, last_modified_by) VALUES (1001, 1, 1, 1, '100.00', '10.00', '90.00', 'USD', '0.00', NOW(), 'test', NOW(), 'test'), (1002, 2, 1, 1, '100.00', '10.00', '90.00', 'USD', '0.00', NOW(), 'test', NOW(), 'test') """ ) ) test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=1')) test_db.session.commit() alloc1 = PaymentAllocationFlowthroughFactory.create( contract_id=1, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc1.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc1.commit_changes() alloc2 = PaymentAllocationFlowthroughFactory.create( contract_id=1, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc2.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc2.commit_changes() alloc3 = PaymentAllocationFlowthroughFactory.create( contract_id=2, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc3.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc3.commit_changes() result = repository.reset_to_init_by_payment_group_payment( payment.payment_group_payment_id, commit=True ) assert result == 2 refreshed_alloc1 = db.session.get( PaymentAllocationFlowthrough, alloc1.payment_allocation_id ) refreshed_alloc2 = db.session.get( PaymentAllocationFlowthrough, alloc2.payment_allocation_id ) assert refreshed_alloc1.payment_status == PAYMENT_ALLOCATION_STATUSES.INIT assert refreshed_alloc1.ledger_status == PAYMENT_ALLOCATION_LEDGER_STATUSES.INIT assert refreshed_alloc2.payment_status == PAYMENT_ALLOCATION_STATUSES.INIT assert refreshed_alloc2.ledger_status == PAYMENT_ALLOCATION_LEDGER_STATUSES.INIT refreshed_alloc3 = db.session.get( PaymentAllocationFlowthrough, alloc3.payment_allocation_id ) assert ( refreshed_alloc3.payment_status == PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT ) @patch( 'payment.repository.payment_allocation.get_flask_user_id', return_value='test_user', ) def test_reset_to_init_by_payment_group_payment_ignores_deleted_details( _mock_get_user_id, fresh_db, mock_contracts ): """Test that reset ignores soft-deleted payment account details.""" from abacus_common_logic.models.base import db as test_db payment = PaymentGroupPaymentFactory.create() test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=0')) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account (payment_group_payment_account_id, payment_group_payment_id, account_id, payoneer_program_id, current_statement_period_id, currency_code, last_payment, current_balance, balance_after_tax, created_at, created_by, last_modified, last_modified_by) VALUES (2001, :pgp_id, 1, 100158970, 1, 'USD', '0.00', '0.00', '0.00', NOW(), 'test', NOW(), 'test') """ ), {'pgp_id': payment.payment_group_payment_id}, ) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account_detail (payment_group_payment_account_id, worksheet_account_contract_payable_after_tax_id, account_id, contract_id, payable_amount_pre_tax, tax_withholding_amount, payable_amount_post_tax, currency_code, vat_amount, created_at, created_by, last_modified, last_modified_by) VALUES (2001, 1, 1, 1, '100.00', '10.00', '90.00', 'USD', '0.00', NOW(), 'test', NOW(), 'test') """ ) ) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account_detail (payment_group_payment_account_id, worksheet_account_contract_payable_after_tax_id, account_id, contract_id, payable_amount_pre_tax, tax_withholding_amount, payable_amount_post_tax, currency_code, vat_amount, created_at, created_by, last_modified, last_modified_by, deleted_at, deleted_by) VALUES (2001, 2, 1, 2, '100.00', '10.00', '90.00', 'USD', '0.00', NOW(), 'test', NOW(), 'test', NOW(), 'test') """ ) ) test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=1')) test_db.session.commit() alloc1 = PaymentAllocationFlowthroughFactory.create( contract_id=1, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc1.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc1.commit_changes() alloc2 = PaymentAllocationFlowthroughFactory.create( contract_id=2, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc2.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc2.commit_changes() result = repository.reset_to_init_by_payment_group_payment( payment.payment_group_payment_id, commit=True ) assert result == 1 refreshed_alloc1 = db.session.get( PaymentAllocationFlowthrough, alloc1.payment_allocation_id ) refreshed_alloc2 = db.session.get( PaymentAllocationFlowthrough, alloc2.payment_allocation_id ) assert refreshed_alloc1.payment_status == PAYMENT_ALLOCATION_STATUSES.INIT assert refreshed_alloc1.ledger_status == PAYMENT_ALLOCATION_LEDGER_STATUSES.INIT assert ( refreshed_alloc2.payment_status == PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT ) @patch( 'payment.repository.payment_allocation.get_flask_user_id', return_value='test_user', ) def test_reset_to_init_by_payment_group_payment_handles_no_contracts( _mock_get_user_id, fresh_db, mock_contracts ): """Test that reset handles payment with no contract details.""" payment = PaymentGroupPaymentFactory.create() alloc = PaymentAllocationFlowthroughFactory.create( contract_id=1, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc.commit_changes() result = repository.reset_to_init_by_payment_group_payment( payment.payment_group_payment_id, commit=True ) assert result == 0 refreshed_alloc = db.session.get( PaymentAllocationFlowthrough, alloc.payment_allocation_id ) assert ( refreshed_alloc.payment_status == PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT ) @patch( 'payment.repository.payment_allocation.get_flask_user_id', return_value='test_user', ) def test_reset_to_init_by_payment_group_payment_account_resets_attached_allocations( _mock_get_user_id, fresh_db, mock_contracts ): """Test that reset_to_init_by_payment_group_payment_account resets allocations.""" from abacus_common_logic.models.base import db as test_db payment = PaymentGroupPaymentFactory.create() test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=0')) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account (payment_group_payment_account_id, payment_group_payment_id, account_id, payoneer_program_id, current_statement_period_id, currency_code, last_payment, current_balance, balance_after_tax, created_at, created_by, last_modified, last_modified_by) VALUES (3001, :pgp_id, 1, 100158970, 1, 'USD', '0.00', '0.00', '0.00', NOW(), 'test', NOW(), 'test'), (3002, :pgp_id, 2, 100158970, 1, 'USD', '0.00', '0.00', '0.00', NOW(), 'test', NOW(), 'test') """ ), {'pgp_id': payment.payment_group_payment_id}, ) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account_detail (payment_group_payment_account_id, worksheet_account_contract_payable_after_tax_id, account_id, contract_id, payable_amount_pre_tax, tax_withholding_amount, payable_amount_post_tax, currency_code, vat_amount, created_at, created_by, last_modified, last_modified_by) VALUES (3001, 1, 1, 1, '100.00', '10.00', '90.00', 'USD', '0.00', NOW(), 'test', NOW(), 'test'), (3002, 2, 2, 2, '100.00', '10.00', '90.00', 'USD', '0.00', NOW(), 'test', NOW(), 'test') """ ) ) test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=1')) test_db.session.commit() alloc1 = PaymentAllocationFlowthroughFactory.create( contract_id=1, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc1.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc1.commit_changes() alloc2 = PaymentAllocationFlowthroughFactory.create( contract_id=2, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc2.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc2.commit_changes() result = repository.reset_to_init_by_payment_group_payment_account( 3001, commit=True ) assert result == 1 refreshed_alloc1 = db.session.get( PaymentAllocationFlowthrough, alloc1.payment_allocation_id ) refreshed_alloc2 = db.session.get( PaymentAllocationFlowthrough, alloc2.payment_allocation_id ) assert refreshed_alloc1.payment_status == PAYMENT_ALLOCATION_STATUSES.INIT assert refreshed_alloc1.ledger_status == PAYMENT_ALLOCATION_LEDGER_STATUSES.INIT assert ( refreshed_alloc2.payment_status == PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT ) @patch( 'payment.repository.payment_allocation.get_flask_user_id', return_value='test_user', ) def test_reset_to_init_by_payment_group_payment_account_ignores_deleted_details( _mock_get_user_id, fresh_db, mock_contracts ): """Test that reset ignores soft-deleted payment account details.""" from abacus_common_logic.models.base import db as test_db payment = PaymentGroupPaymentFactory.create() test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=0')) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account (payment_group_payment_account_id, payment_group_payment_id, account_id, payoneer_program_id, current_statement_period_id, currency_code, last_payment, current_balance, balance_after_tax, created_at, created_by, last_modified, last_modified_by) VALUES (4001, :pgp_id, 1, 100158970, 1, 'USD', '0.00', '0.00', '0.00', NOW(), 'test', NOW(), 'test') """ ), {'pgp_id': payment.payment_group_payment_id}, ) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account_detail (payment_group_payment_account_id, worksheet_account_contract_payable_after_tax_id, account_id, contract_id, payable_amount_pre_tax, tax_withholding_amount, payable_amount_post_tax, currency_code, vat_amount, created_at, created_by, last_modified, last_modified_by) VALUES (4001, 1, 1, 1, '100.00', '10.00', '90.00', 'USD', '0.00', NOW(), 'test', NOW(), 'test') """ ) ) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account_detail (payment_group_payment_account_id, worksheet_account_contract_payable_after_tax_id, account_id, contract_id, payable_amount_pre_tax, tax_withholding_amount, payable_amount_post_tax, currency_code, vat_amount, created_at, created_by, last_modified, last_modified_by, deleted_at, deleted_by) VALUES (4001, 2, 1, 2, '100.00', '10.00', '90.00', 'USD', '0.00', NOW(), 'test', NOW(), 'test', NOW(), 'test') """ ) ) test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=1')) test_db.session.commit() alloc1 = PaymentAllocationFlowthroughFactory.create( contract_id=1, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc1.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc1.commit_changes() alloc2 = PaymentAllocationFlowthroughFactory.create( contract_id=2, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc2.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc2.commit_changes() result = repository.reset_to_init_by_payment_group_payment_account( 4001, commit=True ) assert result == 1 refreshed_alloc1 = db.session.get( PaymentAllocationFlowthrough, alloc1.payment_allocation_id ) refreshed_alloc2 = db.session.get( PaymentAllocationFlowthrough, alloc2.payment_allocation_id ) assert refreshed_alloc1.payment_status == PAYMENT_ALLOCATION_STATUSES.INIT assert refreshed_alloc1.ledger_status == PAYMENT_ALLOCATION_LEDGER_STATUSES.INIT assert ( refreshed_alloc2.payment_status == PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT ) @patch( 'payment.repository.payment_allocation.get_flask_user_id', return_value='test_user', ) def test_reset_to_init_by_payment_group_payment_account_handles_no_details( _mock_get_user_id, fresh_db, mock_contracts ): """Test that reset handles payment account with no detail records.""" from abacus_common_logic.models.base import db as test_db payment = PaymentGroupPaymentFactory.create() test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=0')) test_db.session.execute( test_db.text( """ INSERT INTO payment_group_payment_account (payment_group_payment_account_id, payment_group_payment_id, account_id, payoneer_program_id, current_statement_period_id, currency_code, last_payment, current_balance, balance_after_tax, created_at, created_by, last_modified, last_modified_by) VALUES (5001, :pgp_id, 1, 100158970, 1, 'USD', '0.00', '0.00', '0.00', NOW(), 'test', NOW(), 'test') """ ), {'pgp_id': payment.payment_group_payment_id}, ) test_db.session.execute(test_db.text('SET FOREIGN_KEY_CHECKS=1')) test_db.session.commit() alloc = PaymentAllocationFlowthroughFactory.create( contract_id=1, payment_status=PAYMENT_ALLOCATION_STATUSES.INIT, ) alloc.payment_status = PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT alloc.commit_changes() result = repository.reset_to_init_by_payment_group_payment_account( 5001, commit=True ) assert result == 0 refreshed_alloc = db.session.get( PaymentAllocationFlowthrough, alloc.payment_allocation_id ) assert ( refreshed_alloc.payment_status == PAYMENT_ALLOCATION_STATUSES.ATTACHED_TO_PAYMENT )