"""Contract Advance functional tests.""" import pytest from abacus_common_logic.utils.dates import safe_format_date from abacus_account.tests.utils.factories import ( ReferencePaymentTypeFactory, ) from abacus_contract.constants import constants, error from abacus_contract.tests.utils.factories import ( ContractAdvanceFactory, ContractFactory, ) def test_create_contract_advance(fixture_client): """Test create a contract_advance.""" contract_advance = ContractAdvanceFactory.create() post_data = { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': contract_advance.advance_description, 'milestone': contract_advance.milestone, 'milestone_date': '2022-09-16', 'advance_status': contract_advance.advance_status, 'note': contract_advance.note, 'reference_payment_type_id': None, } res = fixture_client.post('contract/1/advance', json=post_data) assert res.status_code == 201 assert res.json == { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': contract_advance.advance_description, 'milestone': contract_advance.milestone, 'milestone_date': safe_format_date(contract_advance.milestone_date), 'advance_status': contract_advance.advance_status, 'note': contract_advance.note, 'created_at': safe_format_date(contract_advance.created_at), 'contract_id': contract_advance.contract_id, 'contract_advance_id': 2, 'reference_payment_type_id': None, 'vat_amount': None, 'withholding_tax_amount': None, 'amount_after_withholding_and_vat': None, 'us_source_income_rate': None, 'created_by': contract_advance.created_by, } def test_create_contract_advance_with_new_option(fixture_client): """Test create a contract_advance with milestone fund_contingent.""" mock_contract = ContractFactory.create() post_data = { 'milestone_description': 'Test milestone description', 'amount': 109.16, 'currency_code': 'USD', 'advance_description': 'Test advance description', 'milestone': constants.MILESTONES.FUND_CONTINGENT, 'milestone_date': '2022-09-16', 'advance_status': constants.ADVANCE_STATUSES.NOT_QUALIFIED, 'note': 'Test', 'reference_payment_type_id': None, } res = fixture_client.post( f'contract/{mock_contract.contract_id}/advance', json=post_data ) assert res.status_code == 201 assert res.json == { 'milestone_description': post_data['milestone_description'], 'amount': str(post_data['amount']), 'currency_code': post_data['currency_code'], 'advance_description': post_data['advance_description'], 'milestone': post_data['milestone'], 'milestone_date': post_data['milestone_date'], 'advance_status': post_data['advance_status'], 'note': post_data['note'], 'created_at': res.json['created_at'], 'contract_id': mock_contract.contract_id, 'contract_advance_id': res.json['contract_advance_id'], 'reference_payment_type_id': None, 'vat_amount': None, 'withholding_tax_amount': None, 'amount_after_withholding_and_vat': None, 'us_source_income_rate': None, 'created_by': 'default_user_id', } def test_create_contract_advance_payment_enabled(fixture_client): """Test create a contract_advance (payment enabled).""" contract_advance = ContractAdvanceFactory.create() post_data = { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': contract_advance.advance_description, 'milestone': contract_advance.milestone, 'milestone_date': '2022-09-16', 'advance_status': contract_advance.advance_status, 'note': contract_advance.note, 'reference_payment_type_id': None, 'vat_amount': str(contract_advance.vat_amount), 'withholding_tax_amount': str(contract_advance.withholding_tax_amount), 'us_source_income_rate': str(contract_advance.us_source_income_rate), } res = fixture_client.post('contract/1/advance', json=post_data) assert res.status_code == 201 assert res.json == { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': contract_advance.advance_description, 'milestone': contract_advance.milestone, 'milestone_date': safe_format_date(contract_advance.milestone_date), 'advance_status': contract_advance.advance_status, 'note': contract_advance.note, 'created_at': safe_format_date(contract_advance.created_at), 'contract_id': contract_advance.contract_id, 'contract_advance_id': 2, 'reference_payment_type_id': None, 'vat_amount': str(contract_advance.vat_amount), 'withholding_tax_amount': str(contract_advance.withholding_tax_amount), 'amount_after_withholding_and_vat': str( contract_advance.amount_after_withholding_and_vat ), 'us_source_income_rate': str(contract_advance.us_source_income_rate), 'created_by': contract_advance.created_by, } def test_create_contract_advance_payment_enabled_failure_validation(fixture_client): """Test validation failure on create a contract_advance (payment enabled).""" contract_advance = ContractAdvanceFactory.create( advance_status=constants.ADVANCE_STATUSES.QUALIFIED ) post_data = { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': contract_advance.advance_description, 'milestone': contract_advance.milestone, 'milestone_date': '2022-09-16', 'advance_status': contract_advance.advance_status, 'note': contract_advance.note, 'reference_payment_type_id': None, } res = fixture_client.post('contract/1/advance', json=post_data) assert res.status_code == 400 assert res.json == { 'code': 'error', 'message': 'Both vat_amount and withholding_tax_amount are required.', } def test_create_contract_advance_default_values(fixture_client): """Test create a contract_advance.""" contract_advance = ContractAdvanceFactory.create() post_data = { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': contract_advance.advance_description, 'milestone': contract_advance.milestone, 'milestone_date': '2022-09-16', 'note': contract_advance.note, } res = fixture_client.post('contract/1/advance', json=post_data) assert res.status_code == 201 assert res.json == { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': contract_advance.advance_description, 'milestone': contract_advance.milestone, 'milestone_date': safe_format_date(contract_advance.milestone_date), 'advance_status': constants.ADVANCE_STATUSES.NOT_QUALIFIED, 'note': contract_advance.note, 'created_at': safe_format_date(contract_advance.created_at), 'contract_id': contract_advance.contract_id, 'contract_advance_id': 2, 'reference_payment_type_id': None, 'vat_amount': None, 'withholding_tax_amount': None, 'amount_after_withholding_and_vat': None, 'us_source_income_rate': None, 'created_by': contract_advance.created_by, } def test_get_pending_contract_advances(fixture_client): """Test to get a list of pending contract advances.""" contract = ContractFactory.create() pending_contract_advance = ContractAdvanceFactory.create(contract=contract) ContractAdvanceFactory.create( contract=contract, advance_status=constants.ADVANCE_STATUSES.PAID ) contract_id = contract.contract_id status = 'pending' res = fixture_client.get( f'/contract/{contract_id}/advances/{status}/?limit=10&offset=0' ) assert res.status_code == 200 assert res.json['total_count'] == 1 assert res.json['items'] == [ { 'contract_advance_id': 1, 'milestone_description': 'Milestone Description', 'currency_code': 'USD', 'milestone_date': safe_format_date(pending_contract_advance.milestone_date), 'note': None, 'advance_status': 'not_qualified', 'milestone': 'recoupment', 'advance_description': 'Advance Description', 'reference_payment_type_id': None, 'contract_id': 1, 'created_at': safe_format_date(pending_contract_advance.created_at), 'amount': '100.00', 'vat_amount': '20.00', 'withholding_tax_amount': '-10.00', 'amount_after_withholding_and_vat': '110.00', 'us_source_income_rate': '99.000001', 'created_by': pending_contract_advance.created_by, } ] def test_get_qualified_contract_advances_by_reference_payment_type(fixture_client): """Test to get a list of pending contract advances.""" reference_payment_type = ReferencePaymentTypeFactory.create() contract = ContractFactory.create() ContractAdvanceFactory.create(contract=contract) contract_advance = ContractAdvanceFactory.create( contract=contract, advance_status=constants.ADVANCE_STATUSES.QUALIFIED, reference_payment_type=reference_payment_type, ) contract_id = contract.contract_id reference_payment_type_id = reference_payment_type.reference_payment_type_id status = 'qualified' res = fixture_client.get( f'/contract/{contract_id}/advances/{status}/' f'?limit=10&offset=0' f'&reference_payment_type_id={reference_payment_type_id}' ) assert res.status_code == 200 assert res.json['total_count'] == 1 assert res.json['items'] == [ { 'contract_advance_id': contract_advance.contract_advance_id, 'milestone_description': 'Milestone Description', 'currency_code': 'USD', 'milestone_date': safe_format_date(contract_advance.milestone_date), 'note': None, 'advance_status': 'qualified', 'milestone': 'recoupment', 'advance_description': 'Advance Description', 'reference_payment_type_id': reference_payment_type_id, 'contract_id': 1, 'created_at': safe_format_date(contract_advance.created_at), 'amount': '100.00', 'vat_amount': '20.00', 'withholding_tax_amount': '-10.00', 'amount_after_withholding_and_vat': '110.00', 'us_source_income_rate': '99.000001', 'created_by': contract_advance.created_by, } ] def test_get_all_contract_advances(fixture_client): """Test to get a list of all contract advances.""" contract = ContractFactory.create() pending_contract_advance = ContractAdvanceFactory.create(contract=contract) paid_contract_advance = ContractAdvanceFactory.create( contract=contract, advance_description='Advance Description', amount=190.90, currency_code='AUD', milestone_description='Milestone Description', milestone_date='2022-09-30', advance_status=constants.ADVANCE_STATUSES.PAID, ) contract_id = contract.contract_id res = fixture_client.get(f'/contract/{contract_id}/advances/?limit=10&offset=0') assert res.status_code == 200 assert res.json['total_count'] == 2 assert len(res.json['items']) == 2 assert sorted(res.json['items'], key=lambda x: x['contract_advance_id']) == [ { 'contract_advance_id': 1, 'milestone_description': 'Milestone Description', 'currency_code': 'USD', 'milestone_date': safe_format_date(pending_contract_advance.milestone_date), 'note': None, 'advance_status': 'not_qualified', 'milestone': 'recoupment', 'advance_description': 'Advance Description', 'reference_payment_type_id': None, 'contract_id': 1, 'created_at': safe_format_date(pending_contract_advance.created_at), 'amount': '100.00', 'vat_amount': '20.00', 'withholding_tax_amount': '-10.00', 'amount_after_withholding_and_vat': '110.00', 'us_source_income_rate': '99.000001', 'created_by': pending_contract_advance.created_by, }, { 'contract_advance_id': 2, 'milestone_description': 'Milestone Description', 'currency_code': 'AUD', 'milestone_date': safe_format_date(paid_contract_advance.milestone_date), 'note': None, 'advance_status': 'paid', 'milestone': 'recoupment', 'advance_description': 'Advance Description', 'reference_payment_type_id': None, 'contract_id': 1, 'created_at': safe_format_date(paid_contract_advance.created_at), 'amount': '190.90', 'vat_amount': '20.00', 'withholding_tax_amount': '-10.00', 'amount_after_withholding_and_vat': '110.00', 'us_source_income_rate': '99.000001', 'created_by': paid_contract_advance.created_by, }, ] def test_get_contract_advances_invalid_status(fixture_client): """Test to get a list of contract advances for an invalid status.""" contract = ContractFactory.create() status = 'test' res = fixture_client.get(f'/contract/{contract.contract_id}/advances/{status}/') assert res.status_code == 400 assert res.json['message'] == error.ERROR_INVALID_CONTRACT_ADVANCE_STATUS.format( status=', '.join(['pending', 'paid', 'qualified', 'in_review']) ) @pytest.mark.db('mysql') def test_get_paid_contract_advances(fixture_client, create_mock_paid_advances): """Test to get a list of paid contract advances.""" contract_id = 1 status = 'paid' res = fixture_client.get( f'/contract/{contract_id}/advances/{status}/?limit=10&offset=0' ) assert res.status_code == 200 items = res.json['items'] assert res.json['total_count'] == 2 assert len(items) == 2 assert sorted(items, key=lambda x: x['contract_advance_id']) == [ { 'contract_advance_id': 1, 'contract_id': 1, 'statement_period_id': 1, 'amount': '100.00', 'vat_amount': '20.00', 'withholding_tax_amount': '-10.00', 'amount_after_withholding_and_vat': '110.00', 'us_source_income_rate': '99.000001', 'currency_code': 'USD', 'advance_amount_payee_currency': '100.00', 'advance_payee_currency_code': 'USD', 'milestone': 'recoupment', 'advance_status': 'paid', 'advance_description': 'Advance Description', 'milestone_description': 'Milestone Description', 'note': None, 'reference_payment_type_id': None, 'milestone_date': '2022-09-16', 'created_at': items[0]['created_at'], 'date_paid': '2022-09-13', 'created_by': 'default_user_id', }, { 'contract_advance_id': 3, 'contract_id': 1, 'statement_period_id': 1, 'amount': '100.00', 'vat_amount': '20.00', 'withholding_tax_amount': '-10.00', 'amount_after_withholding_and_vat': '110.00', 'us_source_income_rate': '99.000001', 'currency_code': 'USD', 'advance_amount_payee_currency': '101.00', 'advance_payee_currency_code': 'USD', 'milestone': 'recoupment', 'advance_status': 'pending_payment', 'advance_description': 'Advance Description', 'milestone_description': 'Milestone Description', 'note': None, 'reference_payment_type_id': None, 'milestone_date': '2022-09-16', 'created_at': items[0]['created_at'], 'date_paid': '2022-09-13', 'created_by': 'default_user_id', }, ] def test_update_contract_advance_payment_enabled(fixture_client): """Test to update a contract_advance record.""" contract_advance = ContractAdvanceFactory() put_data = { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': 'Changed description', 'milestone': contract_advance.milestone, 'milestone_date': '2022-09-16', 'advance_status': constants.ADVANCE_STATUSES.QUALIFIED, 'note': contract_advance.note, 'vat_amount': '22.00', 'withholding_tax_amount': '-11.00', 'us_source_income_rate': '99.000001', } res = fixture_client.put( f'/contract-advance/{contract_advance.contract_advance_id}', json=put_data ) assert res.status_code == 200 assert res.json == { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': 'Changed description', 'milestone': contract_advance.milestone, 'milestone_date': safe_format_date(contract_advance.milestone_date), 'advance_status': constants.ADVANCE_STATUSES.QUALIFIED, 'note': contract_advance.note, 'reference_payment_type_id': None, 'created_at': safe_format_date(contract_advance.created_at), 'contract_id': contract_advance.contract_id, 'contract_advance_id': contract_advance.contract_advance_id, 'vat_amount': '22.00', 'withholding_tax_amount': '-11.00', 'amount_after_withholding_and_vat': '111.00', 'us_source_income_rate': '99.000001', 'created_by': contract_advance.created_by, } def test_update_contract_advance_payment_enabled_failure_validation(fixture_client): """Test validation failure on update a contract_advance record.""" contract_advance = ContractAdvanceFactory( vat_amount=None, withholding_tax_amount=None ) put_data = { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': 'Changed description', 'milestone': contract_advance.milestone, 'milestone_date': '2022-09-16', 'advance_status': constants.ADVANCE_STATUSES.QUALIFIED, 'note': contract_advance.note, } res = fixture_client.put( f'/contract-advance/{contract_advance.contract_advance_id}', json=put_data ) assert res.status_code == 400 assert res.json == { 'code': 'error', 'message': 'Both vat_amount and withholding_tax_amount are required.', } def test_update_contract_advance_with_new_milestone_option(fixture_client): """Test to update a contract_advance with new milestone option.""" contract_advance = ContractAdvanceFactory(milestone=constants.MILESTONES.OTHER) put_data = {'milestone': constants.MILESTONES.OPTION} res = fixture_client.put( f'/contract-advance/{contract_advance.contract_advance_id}', json=put_data ) assert res.status_code == 200 assert res.json == { 'milestone_description': contract_advance.milestone_description, 'amount': str(contract_advance.amount), 'currency_code': contract_advance.currency_code, 'advance_description': contract_advance.advance_description, 'milestone': constants.MILESTONES.OPTION, 'milestone_date': safe_format_date(contract_advance.milestone_date), 'advance_status': contract_advance.advance_status, 'note': contract_advance.note, 'created_at': safe_format_date(contract_advance.created_at), 'contract_id': contract_advance.contract_id, 'contract_advance_id': contract_advance.contract_advance_id, 'reference_payment_type_id': contract_advance.reference_payment_type_id, 'vat_amount': str(contract_advance.vat_amount), 'withholding_tax_amount': str(contract_advance.withholding_tax_amount), 'amount_after_withholding_and_vat': str( contract_advance.amount_after_withholding_and_vat ), 'us_source_income_rate': str(contract_advance.us_source_income_rate), 'created_by': contract_advance.created_by, } def test_delete_pending_contract_advance(fixture_client): """Test to delete pending contract advance.""" contract = ContractFactory.create() pending_contract_advance = ContractAdvanceFactory.create(contract=contract) contract_advance_id = pending_contract_advance.contract_advance_id res = fixture_client.delete(f'/contract-advance/{contract_advance_id}') assert res.status_code == 204 assert pending_contract_advance.deleted_at assert pending_contract_advance.deleted_by assert pending_contract_advance.advance_status == constants.ADVANCE_STATUSES.DELETED def test_delete_paid_contract_advance(fixture_client): """Test to delete paid contract advance.""" contract = ContractFactory.create() paid_contract_advance = ContractAdvanceFactory.create( contract=contract, advance_status=constants.ADVANCE_STATUSES.PAID ) contract_advance_id = paid_contract_advance.contract_advance_id res = fixture_client.delete(f'/contract-advance/{contract_advance_id}') assert res.status_code == 400 assert res.json['message'] == error.ERROR_CONTRACT_ADVANCE_PAID_DELETE def test_get_contract_advance_by_id(fixture_client): """Test to get a contract advance by specified ID.""" contract = ContractFactory.create() contract_advance = ContractAdvanceFactory.create(contract=contract) res = fixture_client.get( f'/contract-advance/{contract_advance.contract_advance_id}' ) assert res.status_code == 200 assert res.json == { 'contract_advance_id': contract_advance.contract_advance_id, 'milestone_description': contract_advance.milestone_description, 'currency_code': contract_advance.currency_code, 'milestone_date': safe_format_date(contract_advance.milestone_date), 'note': contract_advance.note, 'advance_status': contract_advance.advance_status, 'milestone': contract_advance.milestone, 'advance_description': contract_advance.advance_description, 'contract_id': contract_advance.contract_id, 'created_at': safe_format_date(contract_advance.created_at), 'amount': str(contract_advance.amount), 'reference_payment_type_id': None, 'vat_amount': str(contract_advance.vat_amount), 'withholding_tax_amount': str(contract_advance.withholding_tax_amount), 'amount_after_withholding_and_vat': str( contract_advance.amount_after_withholding_and_vat ), 'us_source_income_rate': str(contract_advance.us_source_income_rate), 'created_by': contract_advance.created_by, }