Fix: SigningTime tz='America/Bogota'
This commit is contained in:
parent
9297be22e0
commit
d04596ed3a
@ -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
|
||||
@ -312,7 +318,8 @@ class DianXMLExtensionCUDS(DianXMLExtensionCUDFE):
|
||||
'%s' % build_vars['Software-PIN'],
|
||||
'%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
|
||||
@ -367,11 +375,13 @@ class DianXMLExtensionSigner:
|
||||
self._localpolicy = localpolicy
|
||||
if passphrase:
|
||||
self._passphrase = passphrase.encode('utf-8')
|
||||
|
||||
|
||||
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(
|
||||
@ -449,29 +463,28 @@ class DianXMLExtensionSigner:
|
||||
extcontent = self._element_extension_content(fachoxml)
|
||||
fachoxml.append_element(extcontent, signature)
|
||||
|
||||
|
||||
|
||||
class DianXMLExtensionAuthorizationProvider(FachoXMLExtension):
|
||||
# RESOLUCION 0004: pagina 176
|
||||
|
||||
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')
|
||||
|
Loading…
Reference in New Issue
Block a user