Fix: SigningTime tz='America/Bogota'
This commit is contained in:
		| @@ -1,6 +1,5 @@ | ||||
| # This file is part of facho.  The COPYRIGHT file at the top level of | ||||
| # this repository contains the full copyright notices and license terms. | ||||
|  | ||||
| from ..facho import FachoXML, FachoXMLExtension, LXMLBuilder | ||||
| import uuid | ||||
| import xmlsig | ||||
| @@ -15,6 +14,7 @@ from .data.dian import codelist | ||||
| from . import form | ||||
| from collections import defaultdict | ||||
| # from pathlib import Path | ||||
| from dateutil import tz | ||||
|  | ||||
| from cryptography.hazmat.primitives.serialization import pkcs12 | ||||
|  | ||||
| @@ -32,7 +32,7 @@ SCHEME_AGENCY_ATTRS = { | ||||
| POLICY_ID = 'https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf' | ||||
| POLICY_NAME = u'Política de firma para facturas electrónicas de la República de Colombia.' | ||||
|  | ||||
|  | ||||
| Bogota = tz.gettz('America/Bogota') | ||||
| # NAMESPACES = { | ||||
| #     'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2', | ||||
| #     'nomina': 'dian:gov:co:facturaelectronica:NominaIndividual', | ||||
| @@ -158,10 +158,12 @@ class DianXMLExtensionCUDFE(FachoXMLExtension): | ||||
|  | ||||
|         # #DIAN 1.8.-2021: FAD03 | ||||
|         # fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta') | ||||
|         fachoxml.set_element('./cbc:ProfileExecutionID', self._tipo_ambiente_int()) | ||||
|         fachoxml.set_element( | ||||
|             './cbc:ProfileExecutionID', self._tipo_ambiente_int()) | ||||
|         #DIAN 1.7.-2020: FAB36 | ||||
|         fachoxml.set_element('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode', | ||||
|                 self._get_qrcode(cufe)) | ||||
|         fachoxml.set_element( | ||||
|             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode', | ||||
|             self._get_qrcode(cufe)) | ||||
|  | ||||
|     def issue_time(self, datetime_): | ||||
|         return datetime_.strftime('%H:%M:%S-05:00') | ||||
| @@ -177,7 +179,8 @@ class DianXMLExtensionCUDFE(FachoXMLExtension): | ||||
|         build_vars['HoraFac'] = self.issue_time(invoice.invoice_issue) | ||||
|         # PAG 601 | ||||
|         build_vars['ValorBruto'] = invoice.invoice_legal_monetary_total.line_extension_amount | ||||
|         build_vars['ValorTotalPagar'] = invoice.invoice_legal_monetary_total.payable_amount | ||||
|         build_vars['ValorTotalPagar' | ||||
|                    ] = invoice.invoice_legal_monetary_total.payable_amount | ||||
|         ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0)) | ||||
|         build_vars['CodImpuesto1'] = '01' | ||||
|         build_vars['CodImpuesto2'] = '04' | ||||
| @@ -207,7 +210,8 @@ class DianXMLExtensionCUDFE(FachoXMLExtension): | ||||
|  | ||||
|  | ||||
| class DianXMLExtensionCUFE(DianXMLExtensionCUDFE): | ||||
|     def __init__(self, invoice,  clave_tecnica = '', tipo_ambiente = AMBIENTE_PRUEBAS): | ||||
|     def __init__( | ||||
|             self, invoice,  clave_tecnica='', tipo_ambiente=AMBIENTE_PRUEBAS): | ||||
|         self.tipo_ambiente = tipo_ambiente | ||||
|         self.clave_tecnica = clave_tecnica | ||||
|         self.invoice = invoice | ||||
| @@ -243,6 +247,7 @@ class DianXMLExtensionCUFE(DianXMLExtensionCUDFE): | ||||
|             '%d' % build_vars['TipoAmb'], | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class DianXMLExtensionCUDE(DianXMLExtensionCUDFE): | ||||
|     def __init__(self, invoice, software_pin, tipo_ambiente = AMBIENTE_PRUEBAS): | ||||
|         self.tipo_ambiente = tipo_ambiente | ||||
| @@ -280,6 +285,7 @@ class DianXMLExtensionCUDE(DianXMLExtensionCUDFE): | ||||
|             '%d' % build_vars['TipoAmb'], | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class DianXMLExtensionCUDS(DianXMLExtensionCUDFE): | ||||
|     def __init__(self, invoice, software_pin, tipo_ambiente = AMBIENTE_PRUEBAS): | ||||
|         self.tipo_ambiente = tipo_ambiente | ||||
| @@ -313,6 +319,7 @@ class DianXMLExtensionCUDS(DianXMLExtensionCUDFE): | ||||
|             '%d' % build_vars['TipoAmb'], | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class DianXMLExtensionSoftwareProvider(FachoXMLExtension): | ||||
|     # RESOLUCION 0004: pagina 108 | ||||
|  | ||||
| @@ -322,7 +329,8 @@ class DianXMLExtensionSoftwareProvider(FachoXMLExtension): | ||||
|         self.id_software = id_software | ||||
|  | ||||
|     def build(self, fexml): | ||||
|         software_provider = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider') | ||||
|         software_provider = fexml.fragment( | ||||
|             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider') | ||||
|         provider_id_attrs = SCHEME_AGENCY_ATTRS.copy() | ||||
|         provider_id_attrs.update({'schemeID': self.dv}) | ||||
|         #DIAN 1.7.-2020: FAB23 | ||||
| @@ -371,7 +379,9 @@ class DianXMLExtensionSigner: | ||||
|         return self | ||||
|  | ||||
|     def _element_extension_content(self, fachoxml): | ||||
|         return fachoxml.builder.xpath(fachoxml.root, './ext:UBLExtensions/ext:UBLExtension[2]/ext:ExtensionContent') | ||||
|         return fachoxml.builder.xpath( | ||||
|             fachoxml.root, | ||||
|             './ext:UBLExtensions/ext:UBLExtension[2]/ext:ExtensionContent') | ||||
|  | ||||
|     def sign_xml_string(self, document): | ||||
|         xml = LXMLBuilder.from_string(document) | ||||
| @@ -400,14 +410,16 @@ class DianXMLExtensionSigner: | ||||
|  | ||||
|         id_keyinfo = "xmldsig-%s-KeyInfo" % (id_uuid) | ||||
|         xmlsig.template.add_reference( | ||||
|             signature, xmlsig.constants.TransformSha256, uri="#%s" % (id_keyinfo), name="xmldsig-%s-ref1" % (id_uuid), | ||||
|             signature, xmlsig.constants.TransformSha256, uri="#%s" % ( | ||||
|                 id_keyinfo), name="xmldsig-%s-ref1" % (id_uuid), | ||||
|         ) | ||||
|         ki = xmlsig.template.ensure_key_info(signature, name=id_keyinfo) | ||||
|         data = xmlsig.template.add_x509_data(ki) | ||||
|         xmlsig.template.x509_data_add_certificate(data) | ||||
|         xmlsig.template.add_key_value(ki) | ||||
|  | ||||
|         qualifying = xades.template.create_qualifying_properties(signature, 'XadesObjects', 'xades') | ||||
|         qualifying = xades.template.create_qualifying_properties( | ||||
|             signature, 'XadesObjects', 'xades') | ||||
|         xades.utils.ensure_id(qualifying) | ||||
|  | ||||
|         id_props = "xmldsig-%s-signedprops" % (id_uuid) | ||||
| @@ -415,10 +427,12 @@ class DianXMLExtensionSigner: | ||||
|             signature, xmlsig.constants.TransformSha256, uri="#%s" % (id_props), | ||||
|             uri_type="http://uri.etsi.org/01903#SignedProperties" | ||||
|         ) | ||||
|         xmlsig.template.add_transform(props_ref, xmlsig.constants.TransformInclC14N) | ||||
|         xmlsig.template.add_transform( | ||||
|             props_ref, xmlsig.constants.TransformInclC14N) | ||||
|  | ||||
|         # TODO assert with http://www.sic.gov.co/hora-legal-colombiana | ||||
|         props = xades.template.create_signed_properties(qualifying, name=id_props, datetime=datetime.now()) | ||||
|         props = xades.template.create_signed_properties( | ||||
|             qualifying, name=id_props, datetime=datetime.now(tz=Bogota)) | ||||
|         xades.template.add_claimed_role(props, "supplier") | ||||
|  | ||||
|         policy = xades.policy.GenericPolicyId( | ||||
| @@ -456,22 +470,21 @@ class DianXMLExtensionAuthorizationProvider(FachoXMLExtension): | ||||
|     def build(self, fexml): | ||||
|         attrs = {'schemeID': '4', 'schemeName': '31'} | ||||
|         attrs.update(SCHEME_AGENCY_ATTRS) | ||||
|          | ||||
|         authorization_provider = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider') | ||||
|         authorization_provider.set_element('./sts:AuthorizationProviderID', | ||||
|                                            '800197268', | ||||
|                                            **attrs) | ||||
|  | ||||
|  | ||||
|  | ||||
| class DianXMLExtensionInvoiceSource(FachoXMLExtension): | ||||
|     # CAB13 | ||||
|     def build(self, fexml): | ||||
|         dian_path = '/fe:CreditNote/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode' | ||||
|         fexml.set_element(dian_path, 'CO', | ||||
|                           listAgencyID="6", | ||||
|                           listAgencyName="United Nations Economic Commission for Europe", | ||||
|                           listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1") | ||||
|         fexml.set_element( | ||||
|             dian_path, 'CO', | ||||
|             listAgencyID="6", | ||||
|             listAgencyName="United Nations Economic Commission for Europe", | ||||
|             listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1") | ||||
|  | ||||
|  | ||||
| class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension): | ||||
| @@ -501,16 +514,15 @@ class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension): | ||||
|         invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:To', | ||||
|                                     self.to) | ||||
|  | ||||
|         fexml.set_element('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode', | ||||
|                           'CO', | ||||
|                           #DIAN 1.7.-2020: FAB15 | ||||
|                           listAgencyID="6", | ||||
|                           #DIAN 1.7.-2020: FAB16 | ||||
|                           listAgencyName="United Nations Economic Commission for Europe", | ||||
|                           #DIAN 1.7.-2020: FAB17 | ||||
|                           listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1" | ||||
|                           ) | ||||
|  | ||||
|         fexml.set_element( | ||||
|             './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode', | ||||
|             'CO', | ||||
|             # DIAN 1.7.-2020: FAB15 | ||||
|             listAgencyID="6", | ||||
|             # DIAN 1.7.-2020: FAB16 | ||||
|             listAgencyName="United Nations Economic Commission for Europe", | ||||
|             # DIAN 1.7.-2020: FAB17 | ||||
|             listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1") | ||||
|  | ||||
|  | ||||
| class DianZIP: | ||||
| @@ -519,7 +531,8 @@ class DianZIP: | ||||
|     MAX_FILES = 50 | ||||
|  | ||||
|     def __init__(self, file_like): | ||||
|         self.zipfile = zipfile.ZipFile(file_like, mode='w', compression=zipfile.ZIP_DEFLATED) | ||||
|         self.zipfile = zipfile.ZipFile( | ||||
|             file_like, mode='w', compression=zipfile.ZIP_DEFLATED) | ||||
|         self.num_files = 0 | ||||
|  | ||||
|     def add_xml(self, name, xml_data): | ||||
| @@ -540,7 +553,6 @@ class DianZIP: | ||||
|     def __enter__(self): | ||||
|         """ | ||||
|         Facilita el uso de esta manera: | ||||
|          | ||||
|         f = open('xxx', 'rb') | ||||
|         with DianZIP(f) as zip: | ||||
|           zip.add_invoice_xml('name', 'data xml') | ||||
| @@ -563,7 +575,7 @@ class DianXMLExtensionSignerVerifier: | ||||
|     def verify_string(self, document): | ||||
|         # Obtener FachoXML | ||||
|         xml = LXMLBuilder.from_string(document) | ||||
|         fachoxml = FachoXML(xml,nsmap=NAMESPACES) | ||||
|         fachoxml = FachoXML(xml, nsmap=NAMESPACES) | ||||
|  | ||||
|         # Obtener Signature | ||||
|         signature = fachoxml.builder.xpath(fachoxml.root, '//ds:Signature') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user