Skip to content

Commit

Permalink
Merge pull request #706 from cordada/feature/sii-dte-skip-validations…
Browse files Browse the repository at this point in the history
…-when-input-is-trusted-2

Improvements and fixes related to validation of trusted inputs
  • Loading branch information
jtrobles-cdd authored Sep 26, 2024
2 parents a222b1c + 152a909 commit b773d27
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 40 deletions.
3 changes: 3 additions & 0 deletions src/cl_sii/dte/data_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,3 +918,6 @@ def validate_referencias_codigo_ref_is_consistent_with_tipo_dte(self) -> DteXmlD
)

return self


DTE_XML_DATA_PYDANTIC_TYPE_ADAPTER = pydantic.TypeAdapter(DteXmlData)
51 changes: 33 additions & 18 deletions src/cl_sii/dte/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,24 @@ def validate_dte_xml(xml_doc: XmlElement) -> None:
xml_utils.validate_xml_doc(DTE_XML_SCHEMA_OBJ, xml_doc)


def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteXmlData:
def parse_dte_xml(xml_doc: XmlElement, trust_input: bool = False) -> data_models.DteXmlData:
"""
Parse data from a DTE XML doc.
.. warning::
It is assumed that ``xml_doc`` is an
``{http://www.sii.cl/SiiDte}/DTE`` XML element.
:param xml_doc:
DTE XML document.
:param trust_input:
If ``True``, the input data is trusted to be valid and
some validation errors are replaced by warnings.
.. warning::
Use this option *only* if the DTE XML document was obtained directly
from the SII *and* you need to work around some validation errors
that the SII should have caught, but let through.
:raises ValueError:
:raises TypeError:
:raises NotImplementedError:
Expand Down Expand Up @@ -511,23 +521,28 @@ def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteXmlData:
_text_strip_or_raise(signature_key_info_x509_cert_em)
)

return data_models.DteXmlData(
emisor_rut=emisor_rut_value,
tipo_dte=tipo_dte_value,
folio=folio_value,
fecha_emision_date=fecha_emision_value,
receptor_rut=receptor_rut_value,
monto_total=monto_total_value,
emisor_razon_social=emisor_razon_social_value,
receptor_razon_social=receptor_razon_social_value,
fecha_vencimiento_date=fecha_vencimiento_value,
firma_documento_dt=tmst_firma_value,
signature_value=signature_signature_value,
signature_x509_cert_der=signature_key_info_x509_cert_der,
emisor_giro=emisor_giro_value,
emisor_email=emisor_email_value,
receptor_email=receptor_email_value,
referencias=referencia_xml_list,
return data_models.DTE_XML_DATA_PYDANTIC_TYPE_ADAPTER.validate_python(
dict(
emisor_rut=emisor_rut_value,
tipo_dte=tipo_dte_value,
folio=folio_value,
fecha_emision_date=fecha_emision_value,
receptor_rut=receptor_rut_value,
monto_total=monto_total_value,
emisor_razon_social=emisor_razon_social_value,
receptor_razon_social=receptor_razon_social_value,
fecha_vencimiento_date=fecha_vencimiento_value,
firma_documento_dt=tmst_firma_value,
signature_value=signature_signature_value,
signature_x509_cert_der=signature_key_info_x509_cert_der,
emisor_giro=emisor_giro_value,
emisor_email=emisor_email_value,
receptor_email=receptor_email_value,
referencias=referencia_xml_list,
),
context={
data_models.VALIDATION_CONTEXT_TRUST_INPUT: trust_input,
},
)


Expand Down
3 changes: 3 additions & 0 deletions src/cl_sii/rtc/data_models_aec.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,3 +798,6 @@ def validate_signature_value_and_signature_x509_cert_der_may_only_be_none_togeth
)

return self


AEC_XML_PYDANTIC_TYPE_ADAPTER = pydantic.TypeAdapter(AecXml)
38 changes: 22 additions & 16 deletions src/cl_sii/rtc/parse_aec.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import cl_sii.dte.data_models
import cl_sii.dte.parse
from cl_sii.dte.constants import TipoDte
from cl_sii.dte.data_models import DteXmlData
from cl_sii.dte.data_models import DteXmlData, is_input_trusted_according_to_validation_context
from cl_sii.dte.parse import DTE_XMLNS_MAP
from cl_sii.libs import encoding_utils, tz_utils, xml_utils
from cl_sii.libs.xml_utils import XmlElement
Expand Down Expand Up @@ -88,7 +88,7 @@ def parse_aec_xml(xml_doc: XmlElement, trust_input: bool = False) -> data_models
that the SII should have caught, but let through.
"""
aec_struct = _Aec.parse_xml(xml_doc, trust_input=trust_input)
return aec_struct.as_aec_xml()
return aec_struct.as_aec_xml(trust_input=trust_input)


###############################################################################
Expand Down Expand Up @@ -656,10 +656,11 @@ def parse_xml_to_dict(xml_em: XmlElement) -> Mapping[str, object]:

@pydantic.field_validator('dte', mode='before')
@classmethod
def validate_dte(cls, v: object) -> object:
def validate_dte(cls, v: object, info: pydantic.ValidationInfo) -> object:
if isinstance(v, XmlElement):
cl_sii.dte.parse.validate_dte_xml(v)
v = cl_sii.dte.parse.parse_dte_xml(v)
trust_dte = is_input_trusted_according_to_validation_context(info.context)
v = cl_sii.dte.parse.parse_dte_xml(v, trust_input=trust_dte)
return v

# @pydantic.validator('tmst_firma')
Expand Down Expand Up @@ -909,7 +910,7 @@ def parse_xml(cls, xml_doc: XmlElement, trust_input: bool = False) -> _Aec:
},
)

def as_aec_xml(self) -> data_models_aec.AecXml:
def as_aec_xml(self, trust_input: bool = False) -> data_models_aec.AecXml:
doc_aec_struct = self.documento_aec
signature_over_doc_aec_struct = self.signature

Expand All @@ -922,17 +923,22 @@ def as_aec_xml(self) -> data_models_aec.AecXml:
cesion_struct.as_cesion_aec_xml() for cesion_struct in cesion_struct_list
]

return data_models_aec.AecXml(
dte=dte,
cedente_rut=caratula_struct.rut_cedente,
cesionario_rut=caratula_struct.rut_cesionario,
fecha_firma_dt=caratula_struct.tmst_firmaenvio,
signature_value=signature_over_doc_aec_struct.signature_value,
signature_x509_cert_der=signature_over_doc_aec_struct.key_info_x509_data_x509_cert,
cesiones=aec_xml_cesion_list,
contacto_nombre=caratula_struct.nmb_contacto,
contacto_telefono=caratula_struct.fono_contacto,
contacto_email=caratula_struct.mail_contacto,
return data_models_aec.AEC_XML_PYDANTIC_TYPE_ADAPTER.validate_python(
dict(
dte=dte,
cedente_rut=caratula_struct.rut_cedente,
cesionario_rut=caratula_struct.rut_cesionario,
fecha_firma_dt=caratula_struct.tmst_firmaenvio,
signature_value=signature_over_doc_aec_struct.signature_value,
signature_x509_cert_der=signature_over_doc_aec_struct.key_info_x509_data_x509_cert,
cesiones=aec_xml_cesion_list,
contacto_nombre=caratula_struct.nmb_contacto,
contacto_telefono=caratula_struct.fono_contacto,
contacto_email=caratula_struct.mail_contacto,
),
context={
cl_sii.dte.data_models.VALIDATION_CONTEXT_TRUST_INPUT: trust_input,
},
)

@staticmethod
Expand Down
11 changes: 5 additions & 6 deletions src/tests/test_dte_data_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
TipoDte,
)
from cl_sii.dte.data_models import ( # noqa: F401
DTE_XML_DATA_PYDANTIC_TYPE_ADAPTER,
VALIDATION_CONTEXT_TRUST_INPUT,
DteDataL0,
DteDataL1,
Expand Down Expand Up @@ -1062,8 +1063,6 @@ def setUpClass(cls) -> None:
'test_data/sii-crypto/DTE--96670340-7--61--110616-cert.der'
)

cls.dte_xml_data_pydantic_type_adapter = pydantic.TypeAdapter(DteXmlData)

def setUp(self) -> None:
super().setUp()

Expand Down Expand Up @@ -1788,7 +1787,7 @@ def test_validate_referencias_rut_otro_is_consistent_with_tipo_dte_for_trusted_i
)

invalid_but_trusted_obj: Mapping[str, object] = {
**self.dte_xml_data_pydantic_type_adapter.dump_python(obj),
**DTE_XML_DATA_PYDANTIC_TYPE_ADAPTER.dump_python(obj),
**dict(
referencias=[obj_referencia],
),
Expand All @@ -1797,7 +1796,7 @@ def test_validate_referencias_rut_otro_is_consistent_with_tipo_dte_for_trusted_i

try:
with self.assertLogs('cl_sii.dte.data_models', level='WARNING') as assert_logs_cm:
self.dte_xml_data_pydantic_type_adapter.validate_python(
DTE_XML_DATA_PYDANTIC_TYPE_ADAPTER.validate_python(
invalid_but_trusted_obj, context=validation_context
)
except pydantic.ValidationError as exc:
Expand Down Expand Up @@ -1876,7 +1875,7 @@ def test_validate_referencias_rut_otro_is_consistent_with_emisor_rut_for_trusted
)

invalid_but_trusted_obj: Mapping[str, object] = {
**self.dte_xml_data_pydantic_type_adapter.dump_python(obj),
**DTE_XML_DATA_PYDANTIC_TYPE_ADAPTER.dump_python(obj),
**dict(
referencias=[obj_referencia],
),
Expand All @@ -1885,7 +1884,7 @@ def test_validate_referencias_rut_otro_is_consistent_with_emisor_rut_for_trusted

try:
with self.assertLogs('cl_sii.dte.data_models', level='WARNING') as assert_logs_cm:
self.dte_xml_data_pydantic_type_adapter.validate_python(
DTE_XML_DATA_PYDANTIC_TYPE_ADAPTER.validate_python(
invalid_but_trusted_obj, context=validation_context
)
except pydantic.ValidationError as exc:
Expand Down

0 comments on commit b773d27

Please sign in to comment.