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 DianXMLExtensionSoftwareSecurityCode
from .fe import DianXMLExtensionCUFE
from .fe import DianXMLExtensionCUDE
from .fe import DianXMLExtensionInvoiceAuthorization
from .fe import DianXMLExtensionSoftwareProvider
from .fe import DianXMLExtensionAuthorizationProvider
from .fe import DianZIP
from .fe import AMBIENTE_PRUEBAS
from .fe import AMBIENTE_PRODUCCION
from . import form_xml

View File

@ -14,6 +14,10 @@ from contextlib import contextmanager
from .data.dian import codelist
from . import form
AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code']
AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code']
SCHEME_AGENCY_ATTRS = {
'schemeAgencyName': 'CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)',
'schemeAgencyID': '195'
@ -76,20 +80,18 @@ class FeXML(FachoXML):
.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.clave_tecnica = clave_tecnica
self.invoice = invoice
def _tipo_ambiente(self):
return int(self.tipo_ambiente)
def build(self, fachoxml):
cufe = self._generate_cufe(self.invoice, fachoxml)
cufe = self._generate_cufe(fachoxml)
fachoxml.set_element('./cbc:UUID', cufe,
schemeID=self.tipo_ambiente,
schemeName='CUFE-SHA384')
@ -105,49 +107,38 @@ class DianXMLExtensionCUFE(FachoXMLExtension):
def issue_date(self, datetime_):
return datetime_.strftime('%Y-%m-%d')
def formatVars(self, invoice):
NumFac = invoice.invoice_ident
FecFac = self.issue_date(invoice.invoice_issue)
HoraFac = self.issue_time(invoice.invoice_issue)
def buildVars(self):
invoice = self.invoice
build_vars = {}
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
ValorBruto = invoice.invoice_legal_monetary_total.line_extension_amount
ValorTotalPagar = invoice.invoice_legal_monetary_total.payable_amount
build_vars['ValorBruto'] = invoice.invoice_legal_monetary_total.line_extension_amount
build_vars['ValorTotalPagar'] = invoice.invoice_legal_monetary_total.payable_amount
ValorImpuestoPara = {}
CodImpuesto1 = 1
CodImpuesto2 = 4
CodImpuesto3 = 3
build_vars['CodImpuesto1'] = 1
build_vars['CodImpuesto2'] = 4
build_vars['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, form.Amount(0.0))
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
NumAdq = invoice.invoice_customer.ident
TipoAmb = self._tipo_ambiente()
ClTec = str(self.clave_tecnica)
return build_vars
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):
formatVars = self.formatVars(invoice)
def formatVars(self, invoice):
raise NotImplementedError()
def _generate_cufe(self, fachoxml):
formatVars = self.formatVars()
cufe = "".join(formatVars)
# crear hash...
@ -156,6 +147,74 @@ class DianXMLExtensionCUFE(FachoXMLExtension):
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):
# RESOLUCION 0004: pagina 108
@ -300,7 +359,7 @@ class DianXMLExtensionInvoiceSource(FachoXMLExtension):
listAgencyID="6",
listAgencyName="United Nations Economic Commission for Europe",
listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1")
class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension):
# RESOLUCION 0004: pagina 106

View File

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

View File

@ -12,7 +12,39 @@ import zipfile
import facho.fe.form as form
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
def simple_invoice_without_lines():
@ -207,10 +239,10 @@ def test_invoice_cufe(simple_invoice_without_lines):
cufe_extension = fe.DianXMLExtensionCUFE(
simple_invoice,
tipo_ambiente = fe.DianXMLExtensionCUFE.AMBIENTE_PRODUCCION,
tipo_ambiente = fe.AMBIENTE_PRODUCCION,
clave_tecnica = '693ff6f2a553c3646a063436fd4dd9ded0311471'
)
formatVars = cufe_extension.formatVars(simple_invoice)
formatVars = cufe_extension.formatVars()
#NumFac
assert formatVars[0] == '323200000129', "NumFac"
#FecFac
@ -246,3 +278,37 @@ def test_invoice_cufe(simple_invoice_without_lines):
cufe = xml_invoice.get_element_text('/fe:Invoice/cbc:UUID')
# RESOLUCION 004: pagina 689
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'