Skip to content

Commit 1ec38a0

Browse files
committed
rtc.data_models: validates 'fecha_cesion_dt' is before or equal to the current day
1 parent d816913 commit 1ec38a0

File tree

3 files changed

+62
-12
lines changed

3 files changed

+62
-12
lines changed

cl_sii/rtc/data_models.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,23 @@ def validate_cesion_seq(value: int) -> None:
4747
raise ValueError("Value is out of the valid range.", value)
4848

4949

50+
def validate_cesion_fecha(value: datetime, tz: tz_utils.PytzTimezone) -> None:
51+
"""
52+
Validate value of date and time when the "cesión" happened.
53+
54+
:raises ValueError:
55+
"""
56+
57+
tz_utils.validate_dt_tz(value, tz)
58+
59+
current_date_in_tz = tz_utils.get_now_tz_aware().astimezone(tz)
60+
61+
if not (value.date() <= current_date_in_tz.date()):
62+
raise ValueError(
63+
'Value of "fecha_cesion_dt" must be before or equal to the current day.', value
64+
)
65+
66+
5067
def validate_cesion_monto(value: int) -> None:
5168
"""
5269
Validate amount of the "cesión".
@@ -245,9 +262,9 @@ def validate_dte_tipo_dte(cls, v: object) -> object:
245262
return v
246263

247264
@pydantic.validator('fecha_cesion_dt')
248-
def validate_datetime_tz(cls, v: object) -> object:
265+
def validate_fecha_cesion_dt(cls, v: object) -> object:
249266
if isinstance(v, datetime):
250-
tz_utils.validate_dt_tz(v, cls.DATETIME_FIELDS_TZ)
267+
validate_cesion_fecha(v, cls.DATETIME_FIELDS_TZ)
251268
return v
252269

253270
@pydantic.validator('fecha_cesion_dt')
@@ -321,6 +338,9 @@ class CesionL0:
321338
- Same timestamp as the "Registro AoR DTE" event ``DTE Cedido``.
322339
- The above statements were empirically verified for
323340
``CesionNaturalKey(dte_key=DteNaturalKey(Rut('99***140-4'), 33, 3105), seq=2)``.
341+
- When receiving an XML AEC document, the SII validates this date is before or
342+
equal to the current day.
343+
Source: (https://www.sii.cl/factura_electronica/ins_tecnico.pdf)
324344
325345
.. warning:: The timestamp is generated by the signer of the AEC so it
326346
cannot be fully trusted. It is not clear how much validation is
@@ -392,9 +412,9 @@ def validate_seq(cls, v: object) -> object:
392412
return v
393413

394414
@pydantic.validator('fecha_cesion_dt')
395-
def validate_datetime_tz(cls, v: object) -> object:
415+
def validate_fecha_cesion_dt(cls, v: object) -> object:
396416
if isinstance(v, datetime):
397-
tz_utils.validate_dt_tz(v, cls.DATETIME_FIELDS_TZ)
417+
validate_cesion_fecha(v, cls.DATETIME_FIELDS_TZ)
398418
return v
399419

400420

@@ -676,10 +696,13 @@ def as_dte_data_l2(self) -> dte_data_models.DteDataL2:
676696

677697
# TODO: Validate value of 'fecha_ultimo_vencimiento' in relation to the DTE data.
678698

679-
@pydantic.validator(
680-
'fecha_cesion_dt',
681-
'fecha_firma_dt',
682-
)
699+
@pydantic.validator('fecha_cesion_dt')
700+
def validate_fecha_cesion_dt(cls, v: object) -> object:
701+
if isinstance(v, datetime):
702+
validate_cesion_fecha(v, cls.DATETIME_FIELDS_TZ)
703+
return v
704+
705+
@pydantic.validator('fecha_firma_dt')
683706
def validate_datetime_tz(cls, v: object) -> object:
684707
if isinstance(v, datetime):
685708
tz_utils.validate_dt_tz(v, cls.DATETIME_FIELDS_TZ)

cl_sii/rtc/data_models_aec.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,9 @@ def validate_contribuyente_razon_social(cls, v: object) -> object:
324324
return v
325325

326326
@pydantic.validator('fecha_cesion_dt')
327-
def validate_datetime_tz(cls, v: object) -> object:
327+
def validate_fecha_cesion_dt(cls, v: object) -> object:
328328
if isinstance(v, datetime):
329-
tz_utils.validate_dt_tz(v, cls.DATETIME_FIELDS_TZ)
329+
data_models.validate_cesion_fecha(v, cls.DATETIME_FIELDS_TZ)
330330
return v
331331

332332
@pydantic.root_validator(skip_on_failure=True)

tests/test_rtc_data_models.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import dataclasses
44
import unittest
5-
from datetime import date, datetime
5+
from datetime import date, datetime, timedelta
66

77
import pydantic
88

@@ -223,7 +223,7 @@ def test_validate_dte_tipo_dte(self) -> None:
223223
validation_errors = assert_raises_cm.exception.errors()
224224
self.assertIn(expected_validation_error, validation_errors)
225225

226-
def test_validate_datetime_tz(self) -> None:
226+
def test_validate_fecha_cesion_dt(self) -> None:
227227
self._set_obj_1()
228228

229229
obj = self.obj_1
@@ -269,6 +269,33 @@ def test_validate_datetime_tz(self) -> None:
269269
validation_errors = assert_raises_cm.exception.errors()
270270
self.assertIn(expected_validation_error, validation_errors)
271271

272+
# Test value constraints:
273+
274+
tomorrow_tz_aware = tz_utils.get_now_tz_aware().astimezone(
275+
CesionAltNaturalKey.DATETIME_FIELDS_TZ
276+
).replace(microsecond=0) + timedelta(days=1)
277+
278+
expected_validation_error = {
279+
'loc': ('fecha_cesion_dt',),
280+
'msg':
281+
'('
282+
'''\'Value of "fecha_cesion_dt" must be before or equal to the current day.\','''
283+
' datetime.datetime('
284+
f'{tomorrow_tz_aware.strftime("%Y, %-m, %-d, %-H, %-M, %-S")},'
285+
' tzinfo=<DstTzInfo \'America/Santiago\' -03-1 day, 21:00:00 DST>)'
286+
')',
287+
'type': 'value_error',
288+
}
289+
290+
with self.assertRaises(pydantic.ValidationError) as assert_raises_cm:
291+
dataclasses.replace(
292+
obj,
293+
fecha_cesion_dt=tomorrow_tz_aware,
294+
)
295+
296+
validation_errors = assert_raises_cm.exception.errors()
297+
self.assertIn(expected_validation_error, validation_errors)
298+
272299
def test_truncate_fecha_cesion_dt_to_minutes(self) -> None:
273300
self._set_obj_1()
274301

0 commit comments

Comments
 (0)