"""Tests for contract serialization.""" import datetime from decimal import Decimal import pytest from abacus_common_logic.utils.dates import safe_format_date, safe_format_datetime from abacus_contract.constants.constants import ( CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES, ) from abacus_contract.constants.error import ( ERROR_CONTRACT_LIFECYCLE_SCHEDULES_LIST_EMPTY, ) from abacus_contract.schemas.contract import ( ContractAndLifecyclePostSchema, ContractDetailSchema, ContractPostSchema, ContractPutSchema, ContractSapFormattedSchema, ContractTerminationSchema, ContractVatInfoSchema, ) from abacus_contract.tests.utils.factories import ( AccountContractFactory, ContractFactory, ReferenceSapProfitCenterFactory, ReferenceSigningEntityFactory, ) def test_contract_detail_schema(create_mock_account): """Test contract detail serialization.""" contract = ContractFactory.create(term_end=None) AccountContractFactory.create(contract=contract) result = ContractDetailSchema().dump(contract) assert result == { 'account_id': 1, 'contract_id': contract.contract_id, 'contract_name': contract.contract_name, 'contract_type': contract.contract_type, 'execution_date': None, 'initial_start_date': '2018-07-28', 'is_excluded_from_accounting_run': False, 'is_paythrough_contract': contract.is_paythrough_contract, 'is_primary_contract': contract.is_primary_contract, 'oa_contract_id': None, 'term_end': safe_format_date(contract.term_end), 'term_start': safe_format_date(contract.term_start), 'reference_signing_entity_id': 1, 'reference_sap_profit_center_id': contract.reference_sap_profit_center_id, 'sap_created_at': None, 'summary_note': contract.summary_note, 'general_note': contract.general_note, 'run_controller_id': None, } def test_contract_post_schema(): """Test contract post serialization.""" contract = ContractFactory.create(term_end=None, initial_start_date=None) oa_contract_id = 1 contract.oa_contract_id = oa_contract_id result = ContractPostSchema().dump(contract) assert result == { 'contract_id': contract.contract_id, 'contract_name': contract.contract_name, 'contract_type': contract.contract_type, 'execution_date': None, 'oa_contract_id': oa_contract_id, 'term_end': safe_format_date(contract.term_end), 'term_start': safe_format_date(contract.term_start), 'reference_signing_entity_id': 1, 'reference_sap_profit_center_id': contract.reference_sap_profit_center_id, 'summary_note': contract.summary_note, 'general_note': contract.general_note, 'is_excluded_from_accounting_run': False, 'is_primary_contract': contract.is_primary_contract, 'run_controller_id': None, } def test_contract_post_schema_no_term_dates(): """Test contract post serialization.""" contract = ContractFactory.create( term_start=None, term_end=None, initial_start_date=None ) oa_contract_id = 1 contract.oa_contract_id = oa_contract_id result = ContractPostSchema().dump(contract) assert result == { 'contract_id': contract.contract_id, 'contract_name': contract.contract_name, 'contract_type': contract.contract_type, 'execution_date': None, 'oa_contract_id': oa_contract_id, 'term_end': None, 'term_start': None, 'reference_signing_entity_id': 1, 'reference_sap_profit_center_id': contract.reference_sap_profit_center_id, 'summary_note': contract.summary_note, 'general_note': contract.general_note, 'is_excluded_from_accounting_run': False, 'is_primary_contract': contract.is_primary_contract, 'run_controller_id': None, } def test_contract_put_schema(): """Test contract put serialization.""" contract = ContractFactory.create( term_end=None, is_excluded_from_accounting_run=True ) result = ContractPutSchema().dump(contract) assert result == { 'contract_name': contract.contract_name, 'is_excluded_from_accounting_run': True, 'is_paythrough_contract': contract.is_paythrough_contract, 'reference_signing_entity_id': 1, 'reference_sap_profit_center_id': contract.reference_sap_profit_center_id, 'run_controller_id': None, 'sap_created_at': None, 'term_end': safe_format_date(contract.term_end), 'term_start': safe_format_date(contract.term_start), 'summary_note': contract.summary_note, 'general_note': contract.general_note, 'execution_date': None, 'initial_start_date': safe_format_date(contract.initial_start_date), 'is_primary_contract': contract.is_primary_contract, } def test_contract_put_schema_with_execution_date(): """Test contract put schema with execution_date.""" mock_put_request = { 'contract_name': 'Test Contract Name', 'is_excluded_from_accounting_run': False, 'execution_date': datetime.date(2024, 8, 27), } result = ContractPutSchema().dump(mock_put_request) assert result == { 'contract_name': mock_put_request['contract_name'], 'is_excluded_from_accounting_run': mock_put_request[ 'is_excluded_from_accounting_run' ], 'execution_date': str(mock_put_request['execution_date']), } def test_contract_put_schema_with_initial_start_date(): """Test contract put schema with initial_start_date.""" mock_put_request = { 'contract_name': 'Test Contract Name', 'is_excluded_from_accounting_run': False, 'initial_start_date': datetime.date(2024, 8, 27), } result = ContractPutSchema().dump(mock_put_request) assert result == { 'contract_name': mock_put_request['contract_name'], 'is_excluded_from_accounting_run': mock_put_request[ 'is_excluded_from_accounting_run' ], 'initial_start_date': str(mock_put_request['initial_start_date']), } def test_contract_put_schema_with_is_paythrough_contract(): """Test contract put schema with is_paythrough_contract.""" mock_put_request = { 'contract_name': 'Test Contract Name', 'is_excluded_from_accounting_run': False, 'is_paythrough_contract': True, } result = ContractPutSchema().dump(mock_put_request) assert result == { 'contract_name': mock_put_request['contract_name'], 'is_excluded_from_accounting_run': mock_put_request[ 'is_excluded_from_accounting_run' ], 'is_paythrough_contract': True, } def test_contract_put_termination_schema(): """Test contract put termination.""" termination_data = { 'termination_effective': '2024-08-27', 'termination_notice_received': None, } result = ContractTerminationSchema().load(termination_data) assert result == { 'termination_effective': datetime.date(2024, 8, 27), 'termination_notice_received': None, } def test_contract_post_schema_with_account_success(): """Test contract post succeeds with account_id.""" contract = ContractFactory.create(summary_note=None, general_note=None) contract_params = { 'contract_name': contract.contract_name, 'contract_type': contract.contract_type, 'term_end': safe_format_date(contract.term_end), 'term_start': safe_format_date(contract.term_start), 'account_id': 1, 'reference_signing_entity_id': contract.reference_signing_entity_id, } res = ContractPostSchema().load(contract_params) assert res == { 'account_id': contract_params.get('account_id'), 'contract_name': contract.contract_name, 'contract_type': contract.contract_type, 'reference_signing_entity_id': contract.reference_signing_entity_id, 'term_end': contract.term_end, 'term_start': contract.term_start, } def test_contract_post_schema_loads_reference_sap_profit_center_id(): """Test ContractPostSchema accepts and surfaces reference_sap_profit_center_id.""" contract_params = { 'contract_name': 'ACC-10447 PC load', 'contract_type': 'distribution', 'account_id': 1, 'reference_signing_entity_id': 1, 'reference_sap_profit_center_id': 42, } res = ContractPostSchema().load(contract_params) assert res['reference_sap_profit_center_id'] == 42 def test_contract_vat_info_list_schema(): """Test contract vat info list serialization.""" vat_info_data = [ { 'account_id': 123, 'contract_id': 123, 'country_of_tax_residence': 'GBR', 'account_is_sba_signed': True, 'client_tax_rate': Decimal('20.00'), 'supplier_tax_rate': None, } ] result = ContractVatInfoSchema(many=True).dump(vat_info_data) assert result == [ { 'account_id': 123, 'contract_id': 123, 'country_of_tax_residence': 'GBR', 'account_is_sba_signed': True, 'client_tax_rate': '20.00', 'supplier_tax_rate': None, } ] def test_contract_sap_formatted_schema(create_mock_account): """Test contract schema for SAP api.""" referenceSigningEntity = ReferenceSigningEntityFactory.create(company_code='4444') sapProfileCenter = ReferenceSapProfitCenterFactory.create( company_code=referenceSigningEntity.company_code ) contract = ContractFactory.create( term_start='2025-01-01', term_end='2025-01-01', reference_signing_entity=referenceSigningEntity, ) account_contract = AccountContractFactory.create(contract=contract) mock_sap_schema = { 'account_id': account_contract.account_id, 'contract_id': contract.contract_id, 'contract_name': contract.contract_name, 'contract_type': contract.contract_type, 'term_end': contract.term_end, 'term_start': contract.term_start, 'Bukrs': sapProfileCenter.company_code, 'Prctr': sapProfileCenter.profit_center, } result = ContractSapFormattedSchema().dump(mock_sap_schema) assert result == { 'AccountId': str(contract.account_id), 'ContractId': str(contract.contract_id), 'ContractName': contract.contract_name, 'ContractType': contract.contract_type, 'DateTo': safe_format_datetime(contract.term_end), 'DateFrm': safe_format_datetime(contract.term_start), 'Bukrs': sapProfileCenter.company_code, 'Prctr': sapProfileCenter.profit_center, 'BusUnit': None, 'Zzfield1': None, 'Zzfield2': None, 'Zzfield3': None, } def test_contract_name_sap_formatted_schema(create_mock_account): """Test contract schema for SAP api with long contract_name.""" referenceSigningEntity = ReferenceSigningEntityFactory.create(company_code='4444') sapProfileCenter = ReferenceSapProfitCenterFactory.create( company_code=referenceSigningEntity.company_code ) contract = ContractFactory.create( term_start='2025-01-01', term_end='2025-01-01', reference_signing_entity=referenceSigningEntity, ) account_contract = AccountContractFactory.create(contract=contract) contract.contract_name = 'AGR503463 - Joel Madden, Benji Madden, Billy Martin, Dean Butterworth and Paul Thomas professionally known as “Good Charlotte” - AWAL Recordings Agreement (Christmas EP)' mock_sap_schema = { 'account_id': account_contract.account_id, 'contract_id': contract.contract_id, 'contract_name': contract.contract_name, 'contract_type': contract.contract_type, 'term_end': contract.term_end, 'term_start': contract.term_start, 'Bukrs': sapProfileCenter.company_code, 'Prctr': sapProfileCenter.profit_center, } result = ContractSapFormattedSchema().dump(mock_sap_schema) assert result == { 'AccountId': str(contract.account_id), 'ContractId': str(contract.contract_id), 'ContractName': contract.contract_name[:120], 'ContractType': contract.contract_type, 'DateTo': safe_format_datetime(contract.term_end), 'DateFrm': safe_format_datetime(contract.term_start), 'Bukrs': sapProfileCenter.company_code, 'Prctr': sapProfileCenter.profit_center, 'BusUnit': None, 'Zzfield1': None, 'Zzfield2': None, 'Zzfield3': None, } def test_contract_and_lifecycle_post_request_schema( mock_contract_and_lifecycle_post_payload, ): """Test contract, contract_lifecycle and contract_lifecycle_schedule POST schema.""" continuously_active_renewal_type = ( CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.CONTINUOUSLY_ACTIVE ) reference_signing_entity_id = mock_contract_and_lifecycle_post_payload['contract'][ 'reference_signing_entity_id' ] mock_contract_and_lifecycle_post_payload['contract_lifecycle'] = { 'lifecycle_term_start': datetime.date(2024, 7, 30) } res = ContractAndLifecyclePostSchema().dump( mock_contract_and_lifecycle_post_payload ) assert res == { 'contract': { 'account_id': 1, 'contract_type': 'distribution', 'execution_date': None, 'reference_signing_entity_id': reference_signing_entity_id, 'summary_note': 'This is for the test', 'general_note': 'This is for the test (general_note)', 'contract_name': 'Test Contract', 'oa_contract_id': 1, }, 'contract_lifecycle_schedules': [ { 'renewal_type': continuously_active_renewal_type, 'schedule_end': None, 'termination_notice_detail_interval': 1, 'termination_notice_detail_type': 'month', 'renewal_offset_detail_interval': None, 'renewal_offset_detail_type': None, 'collection_period_detail_interval': None, 'collection_period_detail_type': None, } ], 'contract_lifecycle': {'lifecycle_term_start': '2024-07-30'}, } def test_contract_and_lifecycle_post_request_schema_error( mock_contract_and_lifecycle_post_payload, ): """Test contract_lifecycle_schedule post schema. throws an error when an empty list passed to the contract_lifecycle_schedules field. """ mock_contract_and_lifecycle_post_payload['contract_lifecycle_schedules'] = [] with pytest.raises(Exception) as excinfo: ContractAndLifecyclePostSchema().load(mock_contract_and_lifecycle_post_payload) assert excinfo.value.messages == { '_schema': [ERROR_CONTRACT_LIFECYCLE_SCHEDULES_LIST_EMPTY] }