"""Unit tests for Contract Lifecycle Schedule schemas.""" import datetime import pytest from abacus_contract.constants.constants import \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES from abacus_contract.constants.error import ERROR_RENEWAL_OFFSET_NOT_REQUIRED from abacus_contract.constants.error import ERROR_RENEWAL_OFFSET_REQUIRED from abacus_contract.constants.error import ERROR_SCHEDULE_END_NOT_REQUIRED from abacus_contract.schemas.contract_lifecycle_schedule \ import ContractLifecycleSchedulePostSchema from abacus_contract.schemas.contract_lifecycle_schedule \ import ContractLifecycleSchedulePutSchema from abacus_contract.schemas.contract_lifecycle_schedule \ import ContractLifecycleScheduleSchema from tests.utils.factories import ContractLifecycleScheduleFactory def test_contract_lifecycle_schedule_schema(): """Test contract_lifecycle_schedule schema.""" mock_contract_lifecycle_schedule = ContractLifecycleScheduleFactory.create() res = ContractLifecycleScheduleSchema().dump( mock_contract_lifecycle_schedule ) assert res == { 'contract_lifecycle_schedule_id': mock_contract_lifecycle_schedule.contract_lifecycle_schedule_id, 'contract_id': mock_contract_lifecycle_schedule.contract_id, 'termination_notice_detail_id': mock_contract_lifecycle_schedule.termination_notice_detail_id, 'renewal_offset_detail_id': mock_contract_lifecycle_schedule.renewal_offset_detail_id, 'collection_period_detail_id': mock_contract_lifecycle_schedule.collection_period_detail_id, 'renewal_type': mock_contract_lifecycle_schedule.renewal_type, 'schedule_end': mock_contract_lifecycle_schedule.schedule_end, 'contract_lifecycle': None } def test_contract_lifecycle_schedule_post_schema(): """Test contract_lifecycle_schedule POST schema.""" continuously_active_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.CONTINUOUSLY_ACTIVE mock_data = { 'renewal_type': continuously_active_renewal_type, 'schedule_end': datetime.date(2024, 11, 28), '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': datetime.date(2020, 1, 1), } } res = ContractLifecycleSchedulePostSchema().dump(mock_data) assert res == { 'renewal_type': mock_data['renewal_type'], 'schedule_end': str(mock_data['schedule_end']), 'termination_notice_detail_interval': mock_data['termination_notice_detail_interval'], 'termination_notice_detail_type': mock_data['termination_notice_detail_type'], 'renewal_offset_detail_interval': mock_data['renewal_offset_detail_interval'], 'renewal_offset_detail_type': mock_data['renewal_offset_detail_type'], 'collection_period_detail_interval': mock_data['collection_period_detail_interval'], 'collection_period_detail_type': mock_data['collection_period_detail_type'], 'contract_lifecycle': { 'lifecycle_term_start': '2020-01-01' } } def test_validate_renewal_offset_detail_for_renew_periodically(): """Test contract_lifecycle_schedule post schema for renewal_offset_detail fields. returns the fields when renewal_type is "renews_periodically" and when both renewal_offset_detail_interval and renewal_offset_detail_type are provided. """ # noqa: E501 renew_periodically_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.RENEW_PERIODICALLY mock_data = { 'renewal_type': renew_periodically_renewal_type, 'schedule_end': None, 'termination_notice_detail_interval': 1, 'termination_notice_detail_type': 'month', 'renewal_offset_detail_interval': 1, 'renewal_offset_detail_type': 'month', 'collection_period_detail_interval': None, 'collection_period_detail_type': None, } res = ContractLifecycleSchedulePostSchema().load(mock_data) assert res == { 'renewal_type': mock_data['renewal_type'], 'schedule_end': mock_data['schedule_end'], 'termination_notice_detail_interval': mock_data['termination_notice_detail_interval'], 'termination_notice_detail_type': mock_data['termination_notice_detail_type'], 'renewal_offset_detail_interval': mock_data['renewal_offset_detail_interval'], 'renewal_offset_detail_type': mock_data['renewal_offset_detail_type'], 'collection_period_detail_interval': mock_data['collection_period_detail_interval'], 'collection_period_detail_type': mock_data['collection_period_detail_type'] } def test_validate_renewal_offset_detail_error_for_renew_periodically(): """Test contract_lifecycle_schedule post schema for renewal_offset_detail fields. throws an error when renewal_type is "renews_periodically" and when both renewal_offset_detail_interval and renewal_offset_detail_type are passed with None values. """ # noqa: E501 renew_periodically_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.RENEW_PERIODICALLY # Throws an error if both renewal_offset_detail_interval and # renewal_offset_detail_type are None. mock_data = { 'renewal_type': renew_periodically_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, } with pytest.raises(Exception) as excinfo: ContractLifecycleSchedulePostSchema().load(mock_data) assert excinfo.value.messages == {'_schema': [ ERROR_RENEWAL_OFFSET_REQUIRED.format(renew_periodically_renewal_type) ]} # Throws an error if either renewal_offset_detail_interval or # renewal_offset_detail_type is None. mock_data.update({ 'renewal_offset_detail_interval': 1 }) with pytest.raises(Exception) as excinfo: ContractLifecycleSchedulePostSchema().load(mock_data) assert excinfo.value.messages == {'_schema': [ ERROR_RENEWAL_OFFSET_REQUIRED.format(renew_periodically_renewal_type) ]} def test_validate_renewal_offset_detail_error_for_continuously_active(): """Test contract_lifecycle_schedule post schema for renewal_offset_detail fields. throws an error when renewal_type is "continuously_active" and when either renewal_offset_detail_interval or renewal_offset_detail_type is present. """ # noqa: E501 continuously_active_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.CONTINUOUSLY_ACTIVE renew_periodically_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.RENEW_PERIODICALLY # Throws an error if either renewal_offset_detail_interval or # renewal_offset_detail_type is present. mock_data = { 'renewal_type': continuously_active_renewal_type, 'schedule_end': None, 'termination_notice_detail_interval': 1, 'termination_notice_detail_type': 'month', 'renewal_offset_detail_interval': 1, 'renewal_offset_detail_type': None, 'collection_period_detail_interval': None, 'collection_period_detail_type': None, } with pytest.raises(Exception) as excinfo: ContractLifecycleSchedulePostSchema().load(mock_data) assert excinfo.value.messages == {'_schema': [ ERROR_RENEWAL_OFFSET_NOT_REQUIRED.format(renew_periodically_renewal_type) ]} def test_validate_schedule_end_error_for_renew_periodically(): """Test contract_lifecycle_schedule post schema for schedule_end field. throws an error when renewal_type is "renew_periodically" and schedule_end field is present. """ renew_periodically_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.RENEW_PERIODICALLY renew_after_certain_date_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.RENEW_AFTER_CERTAIN_DATE # Throws an error if schedule_end is present. mock_data = { 'renewal_type': renew_periodically_renewal_type, 'schedule_end': '2024-11-28', 'termination_notice_detail_interval': 1, 'termination_notice_detail_type': 'month', 'renewal_offset_detail_interval': 1, 'renewal_offset_detail_type': 'month', 'collection_period_detail_interval': None, 'collection_period_detail_type': None, } with pytest.raises(Exception) as excinfo: ContractLifecycleSchedulePostSchema().load(mock_data) assert excinfo.value.messages == {'_schema': [ ERROR_SCHEDULE_END_NOT_REQUIRED.format(renew_after_certain_date_renewal_type) ]} def test_validate_schedule_end_for_renew_after_certain_date(): """Test contract_lifecycle_schedule post schema for schedule_end field. returns the field when renewal_type is "renew_after_certain_date" and schedule_end field is present. """ renew_after_certain_date_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.RENEW_AFTER_CERTAIN_DATE mock_data = { 'renewal_type': renew_after_certain_date_renewal_type, 'schedule_end': datetime.date(2024, 11, 28), '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, } res = ContractLifecycleSchedulePostSchema().dump(mock_data) assert res == { 'renewal_type': mock_data['renewal_type'], 'schedule_end': str(mock_data['schedule_end']), 'termination_notice_detail_interval': mock_data['termination_notice_detail_interval'], 'termination_notice_detail_type': mock_data['termination_notice_detail_type'], 'renewal_offset_detail_interval': mock_data['renewal_offset_detail_interval'], 'renewal_offset_detail_type': mock_data['renewal_offset_detail_type'], 'collection_period_detail_interval': mock_data['collection_period_detail_interval'], 'collection_period_detail_type': mock_data['collection_period_detail_type'] } def test_validate_lifecycle_nested(): """Test contract_lifecycle_schedule post schema for contract_lifecycle field.""" # noqa: E501 renew_after_certain_date_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.RENEW_AFTER_CERTAIN_DATE mock_data = { 'renewal_type': renew_after_certain_date_renewal_type, 'schedule_end': datetime.date(2024, 11, 28), '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': datetime.date(2020, 1, 1), } } res = ContractLifecycleSchedulePostSchema().dump(mock_data) assert res == { 'renewal_type': mock_data['renewal_type'], 'schedule_end': str(mock_data['schedule_end']), 'termination_notice_detail_interval': mock_data['termination_notice_detail_interval'], 'termination_notice_detail_type': mock_data['termination_notice_detail_type'], 'renewal_offset_detail_interval': mock_data['renewal_offset_detail_interval'], 'renewal_offset_detail_type': mock_data['renewal_offset_detail_type'], 'collection_period_detail_interval': mock_data['collection_period_detail_interval'], 'collection_period_detail_type': mock_data['collection_period_detail_type'], 'contract_lifecycle': { 'lifecycle_term_start': '2020-01-01', } } def test_contract_lifecycle_schedule_put_schema(): """Test contract_lifecycle_schedule PUT schema.""" continuously_active_renewal_type = \ CONTRACT_LIFECYCLE_SCHEDULE_RENEWAL_TYPES.CONTINUOUSLY_ACTIVE mock_data = { 'contract_lifecycle_schedule_id': 1, 'renewal_type': continuously_active_renewal_type, 'schedule_end': datetime.date(2024, 11, 28), '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, } res = ContractLifecycleSchedulePutSchema().dump(mock_data) assert res == { 'contract_lifecycle_schedule_id': mock_data['contract_lifecycle_schedule_id'], 'renewal_type': mock_data['renewal_type'], 'schedule_end': str(mock_data['schedule_end']), 'termination_notice_detail_interval': mock_data['termination_notice_detail_interval'], 'termination_notice_detail_type': mock_data['termination_notice_detail_type'], 'renewal_offset_detail_interval': mock_data['renewal_offset_detail_interval'], 'renewal_offset_detail_type': mock_data['renewal_offset_detail_type'], 'collection_period_detail_interval': mock_data['collection_period_detail_interval'], 'collection_period_detail_type': mock_data['collection_period_detail_type'] }