se extrae generacion de CUFE a DianXMLExtensionCUFE

FossilOrigin-Name: 964ad19875edfc7f6990f795396eeeb4c66809eefe93303b1479d6c3ad2e2484
This commit is contained in:
bit4bit@riseup.net 2020-05-28 00:49:14 +00:00
parent 5d564ef149
commit 52632babb2
6 changed files with 93 additions and 72 deletions

View File

@ -80,12 +80,13 @@ def generate_invoice(private_key, passphrase, scriptname):
invoice = module.invoice()
invoice.calculate()
xml = form.DIANInvoiceXML(invoice)
params = module.params()
xml = form.DIANInvoiceXML(invoice, **params)
extensions = module.extensions(invoice)
for extension in extensions:
xml.add_extension(extension)
if private_key:
signer = fe.DianXMLExtensionSigner(private_key, passphrase=passphrase)
xml.add_extension(signer)

View File

@ -136,7 +136,7 @@ class FachoXML:
elem = self.set_element('/'+ root_tag + xpath, elements)
else:
for new_element in elements:
elem = self.find_or_create_element('/'+ root_tag + xpath)
elem = self.find_or_create_element('/' + root_tag + xpath)
self.builder.append(elem, new_element)
def fragment(self, xpath, append=False):

View File

@ -2,4 +2,5 @@ from .fe import FeXML
from .fe import NAMESPACES
from .fe import DianXMLExtensionSigner
from .fe import DianXMLExtensionSoftwareSecurityCode
from .fe import DianXMLExtensionCUFE
from .fe import DianZIP

View File

@ -10,6 +10,7 @@ import zipfile
import warnings
import hashlib
from contextlib import contextmanager
from .data import dian
NAMESPACES = {
'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
@ -39,7 +40,74 @@ class FeXML(FachoXML):
#self.find_or_create_element(self._cn)
class DianXMLExtensionCUFE(FachoXMLExtension):
AMBIENTE_PRUEBAS = 'Pruebas'
AMBIENTE_PRODUCCION = 'Producción'
def __init__(self, invoice, tipo_ambiente = AMBIENTE_PRUEBAS, clave_tecnica = ''):
self.tipo_ambiente = tipo_ambiente
self.clave_tecnica = clave_tecnica
self.invoice = invoice
def _tipo_ambiente(self):
return int(dian.TipoAmbiente[self.tipo_ambiente]['code'])
def build(self, fachoxml):
cufe = self._generate_cufe(self.invoice, fachoxml)
fachoxml.set_element('/fe:Invoice/cbc:UUID[schemaName="CUFE-SHA384"]', cufe)
fachoxml.set_element('/fe:Invoice/cbc:ProfileExecutionID', self._tipo_ambiente())
return '', []
def _generate_cufe(self, invoice, fachoxml):
NumFac = invoice.invoice_ident
FecFac = fachoxml.issue_date(invoice.invoice_issue)
HoraFac = fachoxml.issue_time(invoice.invoice_issue)
ValorBruto = invoice.invoice_legal_monetary_total.line_extension_amount
ValorTotalPagar = invoice.invoice_legal_monetary_total.payable_amount
ValorImpuestoPara = {}
ValorImpuesto1 = 0.0
CodImpuesto1 = 1
ValorImpuesto2 = 0.0
CodImpuesto2 = 4
ValorImpuesto3 = 0.0
CodImpuesto3 = 3
for invoice_line in invoice.invoice_lines:
for subtotal in invoice_line.tax.subtotals:
# TODO cual es la naturaleza de tax_scheme_ident?
codigo_impuesto = int(subtotal.tax_scheme_ident)
ValorImpuestoPara.setdefault(codigo_impuesto, 0.0)
ValorImpuestoPara[codigo_impuesto] += subtotal.tax_amount
NitOFE = invoice.invoice_supplier.ident
NumAdq = invoice.invoice_customer.ident
TipoAmb = self._tipo_ambiente()
ClTec = str(self.clave_tecnica)
formatVars = [
'%s' % NumFac,
'%s' % FecFac,
'%s' % HoraFac,
'%.02f' % ValorBruto,
'%02d' % CodImpuesto1,
'%.02f' % ValorImpuestoPara.get(CodImpuesto1, 0.0),
'%02d' % CodImpuesto2,
'%.02f' % ValorImpuestoPara.get(CodImpuesto2, 0.0),
'%02d' % CodImpuesto3,
'%.02f' % ValorImpuestoPara.get(CodImpuesto3, 0.0),
'%.02f' % ValorTotalPagar,
'%s' % NitOFE,
'%s' % NumAdq,
'%s' % ClTec,
'%d' % TipoAmb,
]
cufe = "".join(formatVars)
# crear hash...
h = hashlib.sha384()
h.update(cufe.encode('utf-8'))
return h.hexdigest()
class DianXMLExtensionSoftwareSecurityCode(FachoXMLExtension):
# RESOLUCION 0001: pagina 535

View File

@ -92,7 +92,6 @@ class Invoice:
self.invoice_period_end = None
self.invoice_issue = None
self.invoice_ident = None
self.invoice_cufe = None
self.invoice_legal_monetary_total = LegalMonetaryTotal(0, 0, 0, 0, 0)
self.invoice_customer = None
self.invoice_supplier = None
@ -168,19 +167,12 @@ class DianResolucion0001Validator:
def valid(self):
return not self.errors
class DIANInvoiceXML(fe.FeXML):
AMBIENTE_PRUEBAS = 'Pruebas'
AMBIENTE_PRODUCCION = 'Producción'
def __init__(self, invoice, tipo_ambiente = AMBIENTE_PRUEBAS, clave_tecnica = ''):
super().__init__('Invoice', 'http://www.dian.gov.co/contratos/facturaelectronica/v1')
self.tipo_ambiente = tipo_ambiente
self.clave_tecnica = clave_tecnica
self.attach_invoice(invoice)
def _tipo_ambiente(self):
return int(dian.TipoAmbiente[self.tipo_ambiente]['code'])
class DIANInvoiceXML(fe.FeXML):
def __init__(self, invoice):
super().__init__('Invoice', 'http://www.dian.gov.co/contratos/facturaelectronica/v1')
self.attach_invoice(invoice)
def attach_invoice(self, invoice):
"""adiciona etiquetas a FEXML y retorna FEXML
@ -189,11 +181,7 @@ class DIANInvoiceXML(fe.FeXML):
invoice.calculate()
cufe = self._generate_cufe(invoice)
fexml.set_element('/fe:Invoice/cbc:ProfileExecutionID', self._tipo_ambiente())
fexml.set_element('/fe:Invoice/cbc:ID', invoice.invoice_ident)
fexml.set_element('/fe:Invoice/cbc:UUID[schemaName="CUFE-SHA384"]', cufe)
fexml.set_element('/fe:Invoice/cbc:IssueDate', self.issue_date(invoice.invoice_issue))
fexml.set_element('/fe:Invoice/cbc:IssueTime', self.issue_time(invoice.invoice_issue))
fexml.set_element('/fe:Invoice/cac:InvoicePeriod/cbc:StartDate', invoice.invoice_period_start.strftime('%Y-%m-%d'))
@ -265,53 +253,4 @@ class DIANInvoiceXML(fe.FeXML):
return datetime_.strftime('%H:%M:%S%z')
def issue_date(self, datetime_):
return datetime_.strftime('%Y-%m-%d')
def _generate_cufe(self, invoice):
NumFac = invoice.invoice_ident
FecFac = self.issue_date(invoice.invoice_issue)
HoraFac = self.issue_time(invoice.invoice_issue)
ValorBruto = invoice.invoice_legal_monetary_total.line_extension_amount
ValorTotalPagar = invoice.invoice_legal_monetary_total.payable_amount
ValorImpuestoPara = {}
ValorImpuesto1 = 0.0
CodImpuesto1 = 1
ValorImpuesto2 = 0.0
CodImpuesto2 = 4
ValorImpuesto3 = 0.0
CodImpuesto3 = 3
for invoice_line in invoice.invoice_lines:
for subtotal in invoice_line.tax.subtotals:
# TODO cual es la naturaleza de tax_scheme_ident?
codigo_impuesto = int(subtotal.tax_scheme_ident)
ValorImpuestoPara.setdefault(codigo_impuesto, 0.0)
ValorImpuestoPara[codigo_impuesto] += subtotal.tax_amount
NitOFE = invoice.invoice_supplier.ident
NumAdq = invoice.invoice_customer.ident
TipoAmb = self._tipo_ambiente()
ClTec = str(self.clave_tecnica)
formatVars = [
'%s' % NumFac,
'%s' % FecFac,
'%s' % HoraFac,
'%.02f' % ValorBruto,
'%02d' % CodImpuesto1,
'%.02f' % ValorImpuestoPara.get(CodImpuesto1, 0.0),
'%02d' % CodImpuesto2,
'%.02f' % ValorImpuestoPara.get(CodImpuesto2, 0.0),
'%02d' % CodImpuesto3,
'%.02f' % ValorImpuestoPara.get(CodImpuesto3, 0.0),
'%.02f' % ValorTotalPagar,
'%s' % NitOFE,
'%s' % NumAdq,
'%s' % ClTec,
'%d' % TipoAmb,
]
cufe = "".join(formatVars)
# crear hash...
h = hashlib.sha384()
h.update(cufe.encode('utf-8'))
return h.hexdigest()

View File

@ -94,6 +94,9 @@ def test_invoicesimple_build_with_cufe(simple_invoice):
simple_invoice.validate(invoice_validator)
assert invoice_validator.valid() == True
xml = form.DIANInvoiceXML(simple_invoice)
cufe_extension = fe.DianXMLExtensionCUFE(simple_invoice)
xml.add_extension(cufe_extension)
xml.attach_extensions()
cufe = xml.get_element_text('/fe:Invoice/cbc:UUID')
assert cufe != ''
@ -139,6 +142,9 @@ def test_invoice_line_count_numeric(simple_invoice):
def test_invoice_profileexecutionid(simple_invoice):
xml_invoice = form.DIANInvoiceXML(simple_invoice)
cufe_extension = fe.DianXMLExtensionCUFE(simple_invoice)
xml_invoice.add_extension(cufe_extension)
xml_invoice.attach_extensions()
id_ = xml_invoice.get_element_text('/fe:Invoice/cbc:ProfileExecutionID', format_=int)
assert id_ == 2
@ -190,9 +196,15 @@ def test_invoice_cufe(simple_invoice_without_lines):
def issue_date(self, datetime_):
return '2019-01-16'
xml_invoice = FakeDIANInvoiceXML(simple_invoice,
tipo_ambiente = form.DIANInvoiceXML.AMBIENTE_PRODUCCION,
clave_tecnica = '693ff6f2a553c3646a063436fd4dd9ded0311471')
xml_invoice = FakeDIANInvoiceXML(simple_invoice)
cufe_extension = fe.DianXMLExtensionCUFE(
simple_invoice,
tipo_ambiente = fe.DianXMLExtensionCUFE.AMBIENTE_PRODUCCION,
clave_tecnica = '693ff6f2a553c3646a063436fd4dd9ded0311471'
)
xml_invoice.add_extension(cufe_extension)
xml_invoice.attach_extensions()
cufe = xml_invoice.get_element_text('/fe:Invoice/cbc:UUID')
# RESOLUCION 004: pagina 689
assert cufe == '8bb918b19ba22a694f1da11c643b5e9de39adf60311cf179179e9b33381030bcd4c3c3f156c506ed5908f9276f5bd9b4'