diff --git a/cl_sii/rtc/data_models.py b/cl_sii/rtc/data_models.py index 7b1ac7be..4d21d01d 100644 --- a/cl_sii/rtc/data_models.py +++ b/cl_sii/rtc/data_models.py @@ -99,6 +99,19 @@ def validate_cesion_and_dte_montos(cesion_value: int, dte_value: int) -> None: raise ValueError('Value of "cesión" must be <= value of DTE.', cesion_value, dte_value) +def validate_cesion_fecha_ultimo_vencimiento_is_consistent_with_dte( + cesion_value: date, dte_value: date +) -> None: + """ + Validate 'fecha_ultimo_vencimiento' of the "cesión" is after or equal + to 'fecha_emision' of the DTE. + + :raises ValueError: + """ + if not (cesion_value >= dte_value): + raise ValueError('Value of "cesión" must be >= value of DTE.', cesion_value, dte_value) + + @pydantic.dataclasses.dataclass( frozen=True, config=type('Config', (), dict( @@ -537,6 +550,20 @@ def validate_monto_cedido_does_not_exceed_dte_monto_total( return values + @pydantic.root_validator(skip_on_failure=True) + def validate_fecha_ultimo_vencimiento_is_consistent_with_dte( + cls, values: Mapping[str, object], + ) -> Mapping[str, object]: + fecha_ultimo_vencimiento = values['fecha_ultimo_vencimiento'] + dte_fecha_emision = values['dte_fecha_emision'] + + if isinstance(fecha_ultimo_vencimiento, date) and isinstance(dte_fecha_emision, date): + validate_cesion_fecha_ultimo_vencimiento_is_consistent_with_dte( + cesion_value=fecha_ultimo_vencimiento, dte_value=dte_fecha_emision + ) + + return values + @pydantic.dataclasses.dataclass( frozen=True, @@ -700,8 +727,6 @@ def as_dte_data_l2(self) -> dte_data_models.DteDataL2: # TODO: Validate value of 'fecha_firma_dt' in relation to the DTE data. - # TODO: Validate value of 'fecha_ultimo_vencimiento' in relation to the DTE data. - @pydantic.validator('fecha_cesion_dt') def validate_fecha_cesion_dt(cls, v: object) -> object: if isinstance(v, datetime): @@ -745,3 +770,17 @@ def validate_dte_data_l2(cls, values: Mapping[str, Any]) -> Mapping[str, object] raise return values + + @pydantic.root_validator(skip_on_failure=True) + def validate_fecha_ultimo_vencimiento_is_consistent_with_dte( + cls, values: Mapping[str, object], + ) -> Mapping[str, object]: + fecha_ultimo_vencimiento = values['fecha_ultimo_vencimiento'] + dte_fecha_emision = values['dte_fecha_emision'] + + if isinstance(fecha_ultimo_vencimiento, date) and isinstance(dte_fecha_emision, date): + validate_cesion_fecha_ultimo_vencimiento_is_consistent_with_dte( + cesion_value=fecha_ultimo_vencimiento, dte_value=dte_fecha_emision + ) + + return values diff --git a/cl_sii/rtc/data_models_aec.py b/cl_sii/rtc/data_models_aec.py index 5ca5eef8..809aac65 100644 --- a/cl_sii/rtc/data_models_aec.py +++ b/cl_sii/rtc/data_models_aec.py @@ -367,7 +367,9 @@ def validate_fecha_ultimo_vencimiento_is_consistent_with_dte( isinstance(fecha_ultimo_vencimiento, date) and isinstance(dte, dte_data_models.DteDataL1) ): - pass # TODO: Validate value of 'fecha_ultimo_vencimiento' in relation to the DTE data. + data_models.validate_cesion_fecha_ultimo_vencimiento_is_consistent_with_dte( + cesion_value=fecha_ultimo_vencimiento, dte_value=dte.fecha_emision_date + ) return values diff --git a/tests/test_rtc_data_models.py b/tests/test_rtc_data_models.py index 5d7e47ce..baf91417 100644 --- a/tests/test_rtc_data_models.py +++ b/tests/test_rtc_data_models.py @@ -730,6 +730,32 @@ def test_validate_monto_cedido_does_not_exceed_dte_monto_total(self) -> None: for expected_validation_error in expected_validation_errors: self.assertIn(expected_validation_error, validation_errors) + def test_validate_fecha_ultimo_vencimiento_is_not_before_dte_fecha_emision(self) -> None: + self._set_obj_1() + + obj = self.obj_1 + expected_validation_errors = [ + { + 'loc': ('__root__',), + 'msg': + """('Value of "cesión" must be >= value of DTE.',""" + " datetime.date(2019, 5, 1), datetime.date(2019, 5, 2))", + 'type': 'value_error', + }, + ] + + with self.assertRaises(pydantic.ValidationError) as assert_raises_cm: + dataclasses.replace( + obj, + fecha_ultimo_vencimiento=date(2019, 5, 1), + dte_fecha_emision=date(2019, 5, 2), + ) + + validation_errors = assert_raises_cm.exception.errors() + self.assertEqual(len(validation_errors), len(expected_validation_errors)) + for expected_validation_error in expected_validation_errors: + self.assertIn(expected_validation_error, validation_errors) + class CesionL2Test(CesionL1Test): """