Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ ignore_missing_imports = True
[mypy-django_filters.*]
ignore_missing_imports = True

[mypy-lxml.*]
ignore_missing_imports = True

[mypy-rest_framework.*]
ignore_missing_imports = True

Expand Down
1 change: 1 addition & 0 deletions requirements-dev.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pip-tools==7.4.1
tox==4.20.0
twine==5.1.1
types-jsonschema==4.23.0.20240813
types-lxml==2024.9.16
types-pyOpenSSL==24.1.0.20240722
types-pytz==2024.2.0.20240913
wheel==0.44.0
9 changes: 9 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ cryptography==43.0.1
# -c requirements.txt
# secretstorage
# types-pyopenssl
cssselect==1.2.0
# via types-lxml
distlib==0.3.7
# via virtualenv
docutils==0.19
Expand Down Expand Up @@ -157,10 +159,16 @@ tox==4.20.0
# via -r requirements-dev.in
twine==5.1.1
# via -r requirements-dev.in
types-beautifulsoup4==4.12.0.20240907
# via types-lxml
types-cffi==1.16.0.20240331
# via types-pyopenssl
types-html5lib==1.1.11.20240806
# via types-beautifulsoup4
types-jsonschema==4.23.0.20240813
# via -r requirements-dev.in
types-lxml==2024.9.16
# via -r requirements-dev.in
types-pyopenssl==24.1.0.20240722
# via -r requirements-dev.in
types-pytz==2024.2.0.20240913
Expand All @@ -173,6 +181,7 @@ typing-extensions==4.12.2
# black
# mypy
# rich
# types-lxml
urllib3==1.26.19
# via
# requests
Expand Down
12 changes: 10 additions & 2 deletions src/cl_sii/dte/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteXmlData:
'ds:Signature', # "Firma Digital sobre Documento"
namespaces=xml_utils.XML_DSIG_NS_MAP,
)
assert signature_em is not None

if liquidacion_em is not None or exportaciones_em is not None:
raise NotImplementedError("XML element 'Documento' is the only one supported.")
Expand Down Expand Up @@ -191,6 +192,7 @@ def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteXmlData:
'sii-dte:Encabezado', # "Identificacion y Totales del Documento"
namespaces=DTE_XMLNS_MAP,
)
assert encabezado_em is not None
# note: excluded because currently it is not useful.
# ted_em = documento_em.find(
# 'sii-dte:TED', # "Timbre Electronico de DTE"
Expand All @@ -215,18 +217,22 @@ def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteXmlData:
'sii-dte:IdDoc', # "Identificacion del DTE"
namespaces=DTE_XMLNS_MAP,
)
assert id_doc_em is not None
emisor_em = encabezado_em.find(
'sii-dte:Emisor', # "Datos del Emisor"
namespaces=DTE_XMLNS_MAP,
)
assert emisor_em is not None
receptor_em = encabezado_em.find(
'sii-dte:Receptor', # "Datos del Receptor"
namespaces=DTE_XMLNS_MAP,
)
assert receptor_em is not None
totales_em = encabezado_em.find(
'sii-dte:Totales', # "Montos Totales del DTE"
namespaces=DTE_XMLNS_MAP,
)
assert totales_em is not None

# 'Documento.Encabezado.IdDoc'
# Excluded elements (optional according to the XML schema but the SII may require some of these
Expand Down Expand Up @@ -453,13 +459,15 @@ def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteXmlData:
'ds:KeyInfo', # "Informacion de Claves Publicas y Certificado"
namespaces=xml_utils.XML_DSIG_NS_MAP,
)
assert signature_key_info_em is not None
# signature_key_info_key_value_em = signature_key_info_em.find(
# 'ds:KeyValue',
# namespaces=xml_utils.XML_DSIG_NS_MAP)
signature_key_info_x509_data_em = signature_key_info_em.find(
'ds:X509Data', # "Informacion del Certificado Publico"
namespaces=xml_utils.XML_DSIG_NS_MAP,
)
assert signature_key_info_x509_data_em is not None
signature_key_info_x509_cert_em = signature_key_info_x509_data_em.find(
'ds:X509Certificate', # "Certificado Publico"
namespaces=xml_utils.XML_DSIG_NS_MAP,
Expand Down Expand Up @@ -523,7 +531,7 @@ def parse_dte_xml(xml_doc: XmlElement) -> data_models.DteXmlData:
)


def _text_strip_or_none(xml_em: XmlElement) -> Optional[str]:
def _text_strip_or_none(xml_em: Optional[XmlElement]) -> Optional[str]:
# note: we need the pair of functions '_text_strip_or_none' and '_text_strip_or_raise'
# because, under certain circumstances, an XML tag:
# - with no content -> `xml_em.text` is None instead of ''
Expand All @@ -539,7 +547,7 @@ def _text_strip_or_none(xml_em: XmlElement) -> Optional[str]:
return stripped_text


def _text_strip_or_raise(xml_em: XmlElement) -> str:
def _text_strip_or_raise(xml_em: Optional[XmlElement]) -> str:
# note: we need the pair of functions '_text_strip_or_none' and '_text_strip_or_raise'
# because, under certain circumstances, an XML tag:
# - with no content -> `xml_em.text` is None instead of ''
Expand Down
6 changes: 5 additions & 1 deletion src/cl_sii/libs/xml_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,11 @@ def verify_xml_signature(
trusted_x509_cert: Optional[Union[crypto_utils.X509Cert, crypto_utils._X509CertOpenSsl]] = None,
xml_verifier: Optional[signxml.verifier.XMLVerifier] = None,
xml_verifier_supports_multiple_signatures: bool = False,
) -> Tuple[bytes, XmlElementTree, XmlElementTree]:
) -> Tuple[
bytes,
Optional[Union[XmlElementTree, lxml.etree._Element]],
Union[XmlElementTree, lxml.etree._Element],
]:
"""
Verify the XML signature in ``xml_doc``.

Expand Down
12 changes: 12 additions & 0 deletions src/cl_sii/rtc/parse_aec.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,13 @@ def parse_xml_to_dict(xml_em: XmlElement) -> Mapping[str, object]:
"""
# XPath: //Signature/KeyInfo
key_info_em = xml_em.find('ds:KeyInfo', namespaces=xml_utils.XML_DSIG_NS_MAP)
assert key_info_em is not None

# XPath: //Signature/KeyInfo/X509Data
key_info_x509_data_em = key_info_em.find(
'ds:X509Data', namespaces=xml_utils.XML_DSIG_NS_MAP
)
assert key_info_x509_data_em is not None

# XPath: //Signature
return dict(
Expand Down Expand Up @@ -474,14 +476,17 @@ def parse_xml_to_dict(xml_em: XmlElement) -> Mapping[str, object]:
"""
# XPath: /AEC/DocumentoAEC/Cesiones/Cesion/DocumentoCesion/IdDTE
id_dte_em = xml_em.find('sii-dte:IdDTE', namespaces=DTE_XMLNS_MAP)
assert id_dte_em is not None
id_dte_dict = _IdDte.parse_xml_to_dict(id_dte_em)

# XPath: /AEC/DocumentoAEC/Cesiones/Cesion/DocumentoCesion/Cedente
cedente_em = xml_em.find('sii-dte:Cedente', namespaces=DTE_XMLNS_MAP)
assert cedente_em is not None
cedente_dict = _Cedente.parse_xml_to_dict(cedente_em)

# XPath: /AEC/DocumentoAEC/Cesiones/Cesion/DocumentoCesion/Cesionario
cesionario_em = xml_em.find('sii-dte:Cesionario', namespaces=DTE_XMLNS_MAP)
assert cesionario_em is not None
cesionario_dict = _Cesionario.parse_xml_to_dict(cesionario_em)

# XPath: /AEC/DocumentoAEC/Cesiones/Cesion/DocumentoCesion
Expand Down Expand Up @@ -543,6 +548,7 @@ def parse_xml_to_dict(xml_em: XmlElement) -> Mapping[str, object]:
"""
# XPath: /AEC/DocumentoAEC/Cesiones/Cesion/DocumentoCesion
doc_cesion_em = xml_em.find('sii-dte:DocumentoCesion', namespaces=DTE_XMLNS_MAP)
assert doc_cesion_em is not None
doc_cesion_dict = _DocumentoCesion.parse_xml_to_dict(doc_cesion_em)

# Signature over 'DocumentoCesion'
Expand Down Expand Up @@ -689,6 +695,7 @@ def parse_xml_to_dict(xml_em: XmlElement) -> Mapping[str, object]:
'sii-dte:DocumentoDTECedido',
namespaces=DTE_XMLNS_MAP,
)
assert doc_dte_cedido_em is not None

# Signature over 'DocumentoDTECedido'
# XPath: /AEC/DocumentoAEC/Cesiones/DTECedido/Signature
Expand Down Expand Up @@ -819,13 +826,16 @@ def parse_xml_to_dict(xml_em: XmlElement) -> Mapping[str, object]:
"""
# XPath: /AEC/DocumentoAEC/Caratula
caratula_em = xml_em.find('sii-dte:Caratula', namespaces=DTE_XMLNS_MAP)
assert caratula_em is not None
caratula_dict = _Caratula.parse_xml_to_dict(caratula_em)

# XPath: /AEC/DocumentoAEC/Cesiones
cesiones_em = xml_em.find('sii-dte:Cesiones', namespaces=DTE_XMLNS_MAP)
assert cesiones_em is not None

# XPath: /AEC/DocumentoAEC/Cesiones/DTECedido
dte_cedido_em = cesiones_em.find('sii-dte:DTECedido', namespaces=DTE_XMLNS_MAP)
assert dte_cedido_em is not None
dte_cedido_dict = _DteCedido.parse_xml_to_dict(dte_cedido_em)

# XPath: /AEC/DocumentoAEC/Cesiones/Cesion
Expand Down Expand Up @@ -919,6 +929,7 @@ def parse_xml_to_dict(xml_doc: XmlElement) -> Mapping[str, object]:

# XPath: /AEC/DocumentoAEC
doc_aec_em = aec_em.find('sii-dte:DocumentoAEC', namespaces=DTE_XMLNS_MAP)
assert doc_aec_em is not None
doc_aec_dict = _DocumentoAec.parse_xml_to_dict(doc_aec_em)

# Signature over 'DocumentoAEC'
Expand All @@ -927,6 +938,7 @@ def parse_xml_to_dict(xml_doc: XmlElement) -> Mapping[str, object]:
'ds:Signature',
namespaces=xml_utils.XML_DSIG_NS_MAP,
)
assert signature_over_doc_aec_em is not None
signature_over_doc_aec_dict = _XmlSignature.parse_xml_to_dict(signature_over_doc_aec_em)

# XPath: /AEC
Expand Down