fache/fe/fe.py(DianXMLExtensionCUDE): nuevo.
FossilOrigin-Name: edced6a3095b29e92295242a73ac4654498abe458d4037b21eb13a4b351d60fd
This commit is contained in:
parent
9ab8238736
commit
1429a01f91
@ -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
|
||||||
|
135
facho/fe/fe.py
135
facho/fe/fe.py
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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'
|
||||||
|
Loading…
Reference in New Issue
Block a user