fache/fe/fe.py(DianXMLExtensionCUDE): nuevo.

FossilOrigin-Name: edced6a3095b29e92295242a73ac4654498abe458d4037b21eb13a4b351d60fd
This commit is contained in:
bit4bit@riseup.net 2020-10-29 02:16:44 +00:00
parent 9ab8238736
commit 1429a01f91
4 changed files with 172 additions and 42 deletions

View File

@ -3,8 +3,11 @@ from .fe import NAMESPACES
from .fe import DianXMLExtensionSigner from .fe import DianXMLExtensionSigner
from .fe import DianXMLExtensionSoftwareSecurityCode from .fe import DianXMLExtensionSoftwareSecurityCode
from .fe import DianXMLExtensionCUFE from .fe import DianXMLExtensionCUFE
from .fe import DianXMLExtensionCUDE
from .fe import DianXMLExtensionInvoiceAuthorization from .fe import DianXMLExtensionInvoiceAuthorization
from .fe import DianXMLExtensionSoftwareProvider from .fe import DianXMLExtensionSoftwareProvider
from .fe import DianXMLExtensionAuthorizationProvider from .fe import DianXMLExtensionAuthorizationProvider
from .fe import DianZIP from .fe import DianZIP
from .fe import AMBIENTE_PRUEBAS
from .fe import AMBIENTE_PRODUCCION
from . import form_xml from . import form_xml

View File

@ -14,6 +14,10 @@ from contextlib import contextmanager
from .data.dian import codelist from .data.dian import codelist
from . import form from . import form
AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code']
AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code']
SCHEME_AGENCY_ATTRS = { SCHEME_AGENCY_ATTRS = {
'schemeAgencyName': 'CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)', 'schemeAgencyName': 'CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)',
'schemeAgencyID': '195' 'schemeAgencyID': '195'
@ -76,20 +80,18 @@ class FeXML(FachoXML):
.replace("xmlns:fe", "xmlns") .replace("xmlns:fe", "xmlns")
class DianXMLExtensionCUFE(FachoXMLExtension):
AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code']
AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code']
def __init__(self, invoice, tipo_ambiente = AMBIENTE_PRUEBAS, clave_tecnica = ''): class DianXMLExtensionCUDFE(FachoXMLExtension):
def __init__(self, invoice, tipo_ambiente = AMBIENTE_PRUEBAS):
self.tipo_ambiente = tipo_ambiente self.tipo_ambiente = tipo_ambiente
self.clave_tecnica = clave_tecnica
self.invoice = invoice self.invoice = invoice
def _tipo_ambiente(self): def _tipo_ambiente(self):
return int(self.tipo_ambiente) return int(self.tipo_ambiente)
def build(self, fachoxml): def build(self, fachoxml):
cufe = self._generate_cufe(self.invoice, fachoxml) cufe = self._generate_cufe(fachoxml)
fachoxml.set_element('./cbc:UUID', cufe, fachoxml.set_element('./cbc:UUID', cufe,
schemeID=self.tipo_ambiente, schemeID=self.tipo_ambiente,
schemeName='CUFE-SHA384') schemeName='CUFE-SHA384')
@ -105,49 +107,38 @@ class DianXMLExtensionCUFE(FachoXMLExtension):
def issue_date(self, datetime_): def issue_date(self, datetime_):
return datetime_.strftime('%Y-%m-%d') return datetime_.strftime('%Y-%m-%d')
def formatVars(self, invoice): def buildVars(self):
NumFac = invoice.invoice_ident invoice = self.invoice
FecFac = self.issue_date(invoice.invoice_issue) build_vars = {}
HoraFac = self.issue_time(invoice.invoice_issue) build_vars['NumFac'] = invoice.invoice_ident
build_vars['FecFac'] = self.issue_date(invoice.invoice_issue)
build_vars['HoraFac'] = self.issue_time(invoice.invoice_issue)
# PAG 601 # PAG 601
ValorBruto = invoice.invoice_legal_monetary_total.line_extension_amount build_vars['ValorBruto'] = invoice.invoice_legal_monetary_total.line_extension_amount
ValorTotalPagar = invoice.invoice_legal_monetary_total.payable_amount build_vars['ValorTotalPagar'] = invoice.invoice_legal_monetary_total.payable_amount
ValorImpuestoPara = {} ValorImpuestoPara = {}
CodImpuesto1 = 1 build_vars['CodImpuesto1'] = 1
CodImpuesto2 = 4 build_vars['CodImpuesto2'] = 4
CodImpuesto3 = 3 build_vars['CodImpuesto3'] = 3
for invoice_line in invoice.invoice_lines: for invoice_line in invoice.invoice_lines:
for subtotal in invoice_line.tax.subtotals: for subtotal in invoice_line.tax.subtotals:
# TODO cual es la naturaleza de tax_scheme_ident? # TODO cual es la naturaleza de tax_scheme_ident?
codigo_impuesto = int(subtotal.tax_scheme_ident) codigo_impuesto = int(subtotal.tax_scheme_ident)
ValorImpuestoPara.setdefault(codigo_impuesto, form.Amount(0.0)) ValorImpuestoPara.setdefault(codigo_impuesto, form.Amount(0.0))
ValorImpuestoPara[codigo_impuesto] += subtotal.tax_amount ValorImpuestoPara[codigo_impuesto] += subtotal.tax_amount
build_vars['ValorImpuestoPara'] = ValorImpuestoPara
build_vars['NitOFE'] = invoice.invoice_supplier.ident
build_vars['NumAdq'] = invoice.invoice_customer.ident
build_vars['TipoAmb'] = self._tipo_ambiente()
NitOFE = invoice.invoice_supplier.ident return build_vars
NumAdq = invoice.invoice_customer.ident
TipoAmb = self._tipo_ambiente()
ClTec = str(self.clave_tecnica)
return [
'%s' % NumFac,
'%s' % FecFac,
'%s' % HoraFac,
'%.02f' % round(ValorBruto, 2),
'%02d' % CodImpuesto1,
'%.02f' % round(ValorImpuestoPara.get(CodImpuesto1, 0.0), 2),
'%02d' % CodImpuesto2,
'%.02f' % round(ValorImpuestoPara.get(CodImpuesto2, 0.0), 2),
'%02d' % CodImpuesto3,
'%.02f' % round(ValorImpuestoPara.get(CodImpuesto3, 0.0), 2),
'%.02f' % round(ValorTotalPagar, 2),
'%s' % NitOFE,
'%s' % NumAdq,
'%s' % ClTec,
'%d' % TipoAmb,
]
def _generate_cufe(self, invoice, fachoxml): def formatVars(self, invoice):
formatVars = self.formatVars(invoice) raise NotImplementedError()
def _generate_cufe(self, fachoxml):
formatVars = self.formatVars()
cufe = "".join(formatVars) cufe = "".join(formatVars)
# crear hash... # crear hash...
@ -156,6 +147,74 @@ class DianXMLExtensionCUFE(FachoXMLExtension):
return h.hexdigest() return h.hexdigest()
class DianXMLExtensionCUFE(DianXMLExtensionCUDFE):
def __init__(self, invoice, tipo_ambiente = AMBIENTE_PRUEBAS, clave_tecnica = ''):
self.tipo_ambiente = tipo_ambiente
self.clave_tecnica = clave_tecnica
self.invoice = invoice
def buildVars(self):
build_vars = super().buildVars()
build_vars['ClTec'] = str(self.clave_tecnica)
return build_vars
def formatVars(self):
build_vars = self.buildVars()
CodImpuesto1 = build_vars['CodImpuesto1']
CodImpuesto2 = build_vars['CodImpuesto2']
CodImpuesto3 = build_vars['CodImpuesto3']
return [
'%s' % build_vars['NumFac'],
'%s' % build_vars['FecFac'],
'%s' % build_vars['HoraFac'],
'%.02f' % round(build_vars['ValorBruto'], 2),
'%02d' % CodImpuesto1,
'%.02f' % round(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0), 2),
'%02d' % CodImpuesto2,
'%.02f' % round(build_vars['ValorImpuestoPara'].get(CodImpuesto2, 0.0), 2),
'%02d' % CodImpuesto3,
'%.02f' % round(build_vars['ValorImpuestoPara'].get(CodImpuesto3, 0.0), 2),
'%.02f' % round(build_vars['ValorTotalPagar'], 2),
'%s' % build_vars['NitOFE'],
'%s' % build_vars['NumAdq'],
'%s' % build_vars['ClTec'],
'%d' % build_vars['TipoAmb'],
]
class DianXMLExtensionCUDE(DianXMLExtensionCUDFE):
def __init__(self, invoice, software_pin, tipo_ambiente = AMBIENTE_PRUEBAS):
self.tipo_ambiente = tipo_ambiente
self.software_pin = software_pin
self.invoice = invoice
def buildVars(self):
build_vars = super().buildVars()
build_vars['Software-PIN'] = str(self.software_pin)
return build_vars
def formatVars(self):
build_vars = self.buildVars()
CodImpuesto1 = build_vars['CodImpuesto1']
CodImpuesto2 = build_vars['CodImpuesto2']
CodImpuesto3 = build_vars['CodImpuesto3']
return [
'%s' % build_vars['NumFac'],
'%s' % build_vars['FecFac'],
'%s' % build_vars['HoraFac'],
'%.02f' % round(build_vars['ValorBruto'], 2),
'%02d' % CodImpuesto1,
'%.02f' % round(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0), 2),
'%02d' % CodImpuesto2,
'%.02f' % round(build_vars['ValorImpuestoPara'].get(CodImpuesto2, 0.0), 2),
'%02d' % CodImpuesto3,
'%.02f' % round(build_vars['ValorImpuestoPara'].get(CodImpuesto3, 0.0), 2),
'%.02f' % round(build_vars['ValorTotalPagar'], 2),
'%s' % build_vars['NitOFE'],
'%s' % build_vars['NumAdq'],
'%s' % build_vars['Software-PIN'],
'%d' % build_vars['TipoAmb'],
]
class DianXMLExtensionSoftwareProvider(FachoXMLExtension): class DianXMLExtensionSoftwareProvider(FachoXMLExtension):
# RESOLUCION 0004: pagina 108 # RESOLUCION 0004: pagina 108
@ -300,7 +359,7 @@ class DianXMLExtensionInvoiceSource(FachoXMLExtension):
listAgencyID="6", listAgencyID="6",
listAgencyName="United Nations Economic Commission for Europe", listAgencyName="United Nations Economic Commission for Europe",
listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1") listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1")
class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension): class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension):
# RESOLUCION 0004: pagina 106 # RESOLUCION 0004: pagina 106

View File

@ -470,6 +470,8 @@ class NationalSalesInvoice(Invoice):
class CreditNote(Invoice): class CreditNote(Invoice):
def __init__(self, invoice_document_reference: BillingReference): def __init__(self, invoice_document_reference: BillingReference):
super().__init__(CreditNoteDocumentType())
if not isinstance(invoice_document_reference, BillingReference): if not isinstance(invoice_document_reference, BillingReference):
raise TypeError('invoice_document_reference invalid type') raise TypeError('invoice_document_reference invalid type')
self.invoice_billing_reference = invoice_document_reference self.invoice_billing_reference = invoice_document_reference

View File

@ -12,7 +12,39 @@ import zipfile
import facho.fe.form as form import facho.fe.form as form
from facho import fe from facho import fe
from facho.fe.form_xml import DIANInvoiceXML from facho.fe.form_xml import DIANInvoiceXML, DIANCreditNoteXML
@pytest.fixture
def simple_credit_note_without_lines():
inv = form.CreditNote(form.InvoiceDocumentReference('1234', 'xx', datetime.now()))
inv.set_period(datetime.now(), datetime.now())
inv.set_issue(datetime.now())
inv.set_ident('ABC123')
inv.set_operation_type('10')
inv.set_payment_mean(form.PaymentMean(form.PaymentMean.DEBIT, '41', datetime.now(), '1234'))
inv.set_supplier(form.Party(
name = 'facho-supplier',
ident = form.PartyIdentification('123','', '31'),
responsability_code = form.Responsability(['O-07']),
responsability_regime_code = '48',
organization_code = '1',
address = form.Address(
'', '', form.City('05001', 'Medellín'),
form.Country('CO', 'Colombia'),
form.CountrySubentity('05', 'Antioquia'))
))
inv.set_customer(form.Party(
name = 'facho-customer',
ident = form.PartyIdentification('321', '', '31'),
responsability_code = form.Responsability(['O-07']),
responsability_regime_code = '48',
organization_code = '1',
address = form.Address(
'', '', form.City('05001', 'Medellín'),
form.Country('CO', 'Colombia'),
form.CountrySubentity('05', 'Antioquia'))
))
return inv
@pytest.fixture @pytest.fixture
def simple_invoice_without_lines(): def simple_invoice_without_lines():
@ -207,10 +239,10 @@ def test_invoice_cufe(simple_invoice_without_lines):
cufe_extension = fe.DianXMLExtensionCUFE( cufe_extension = fe.DianXMLExtensionCUFE(
simple_invoice, simple_invoice,
tipo_ambiente = fe.DianXMLExtensionCUFE.AMBIENTE_PRODUCCION, tipo_ambiente = fe.AMBIENTE_PRODUCCION,
clave_tecnica = '693ff6f2a553c3646a063436fd4dd9ded0311471' clave_tecnica = '693ff6f2a553c3646a063436fd4dd9ded0311471'
) )
formatVars = cufe_extension.formatVars(simple_invoice) formatVars = cufe_extension.formatVars()
#NumFac #NumFac
assert formatVars[0] == '323200000129', "NumFac" assert formatVars[0] == '323200000129', "NumFac"
#FecFac #FecFac
@ -246,3 +278,37 @@ def test_invoice_cufe(simple_invoice_without_lines):
cufe = xml_invoice.get_element_text('/fe:Invoice/cbc:UUID') cufe = xml_invoice.get_element_text('/fe:Invoice/cbc:UUID')
# RESOLUCION 004: pagina 689 # RESOLUCION 004: pagina 689
assert cufe == '8bb918b19ba22a694f1da11c643b5e9de39adf60311cf179179e9b33381030bcd4c3c3f156c506ed5908f9276f5bd9b4' assert cufe == '8bb918b19ba22a694f1da11c643b5e9de39adf60311cf179179e9b33381030bcd4c3c3f156c506ed5908f9276f5bd9b4'
def test_credit_note_cude(simple_credit_note_without_lines):
simple_invoice = simple_credit_note_without_lines
simple_invoice.invoice_ident = '8110007871'
simple_invoice.invoice_issue = datetime.strptime('2019-01-12 07:00:00-05:00', '%Y-%m-%d %H:%M:%S%z')
simple_invoice.invoice_supplier.ident = form.PartyIdentification('900373076', '5', '31')
simple_invoice.invoice_customer.ident = form.PartyIdentification('8355990', '5', '31')
simple_invoice.add_invoice_line(form.InvoiceLine(
quantity = 1,
description = 'producto',
item = form.StandardItem('test', 111),
price = form.Price(form.Amount(5_000), '01', ''),
tax = form.TaxTotal(
subtotals = [
form.TaxSubTotal(
tax_scheme_ident = '01',
percent = 19.0
)])
))
simple_invoice.calculate()
xml_invoice = DIANCreditNoteXML(simple_invoice)
cude_extension = fe.DianXMLExtensionCUDE(
simple_invoice,
'12301',
tipo_ambiente = fe.AMBIENTE_PRODUCCION,
)
xml_invoice.add_extension(cude_extension)
cude = xml_invoice.get_element_text('/fe:CreditNote/cbc:UUID')
# pag 612
assert cude == '907e4444decc9e59c160a2fb3b6659b33dc5b632a5008922b9a62f83f757b1c448e47f5867f2b50dbdb96f48c7681168'