tests/test_fe_form.py: se implementa prueba cude.
se implementa prueba para cude de nota debito segun ejemplo en pagina 614, pero el sha384 de la composicion difiere del generado tanto de facho como el sitio web que dan para generarlo. FossilOrigin-Name: 51b29990f6eaf4fc4f85dc51873957f41d9ba047889e4e4fe2ea4f0b1285e88c
This commit is contained in:
parent
4cc29bda4f
commit
a7eb945962
@ -13,6 +13,7 @@ import hashlib
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from .data.dian import codelist
|
from .data.dian import codelist
|
||||||
from . import form
|
from . import form
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code']
|
AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code']
|
||||||
AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code']
|
AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code']
|
||||||
@ -97,7 +98,7 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def build(self, fachoxml):
|
def build(self, fachoxml):
|
||||||
cufe = self._generate_cufe(fachoxml)
|
cufe = self._generate_cufe()
|
||||||
fachoxml.set_element('./cbc:UUID', cufe,
|
fachoxml.set_element('./cbc:UUID', cufe,
|
||||||
schemeID=self.tipo_ambiente,
|
schemeID=self.tipo_ambiente,
|
||||||
schemeName=self.schemeName())
|
schemeName=self.schemeName())
|
||||||
@ -122,7 +123,7 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
# PAG 601
|
# PAG 601
|
||||||
build_vars['ValorBruto'] = invoice.invoice_legal_monetary_total.line_extension_amount
|
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 = {}
|
ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0))
|
||||||
build_vars['CodImpuesto1'] = 1
|
build_vars['CodImpuesto1'] = 1
|
||||||
build_vars['CodImpuesto2'] = 4
|
build_vars['CodImpuesto2'] = 4
|
||||||
build_vars['CodImpuesto3'] = 3
|
build_vars['CodImpuesto3'] = 3
|
||||||
@ -139,9 +140,8 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
|
|
||||||
return build_vars
|
return build_vars
|
||||||
|
|
||||||
def _generate_cufe(self, fachoxml):
|
def _generate_cufe(self):
|
||||||
formatVars = self.formatVars()
|
cufe = "".join(self.formatVars())
|
||||||
cufe = "".join(formatVars)
|
|
||||||
|
|
||||||
# crear hash...
|
# crear hash...
|
||||||
h = hashlib.sha384()
|
h = hashlib.sha384()
|
||||||
|
@ -91,6 +91,7 @@ class Amount:
|
|||||||
def is_same_currency(self, other):
|
def is_same_currency(self, other):
|
||||||
return self.currency == other.currency
|
return self.currency == other.currency
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Item:
|
class Item:
|
||||||
description: str
|
description: str
|
||||||
@ -348,12 +349,19 @@ class AllowanceCharge:
|
|||||||
|
|
||||||
class NationalSalesInvoiceDocumentType(str):
|
class NationalSalesInvoiceDocumentType(str):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
# 6.1.3
|
||||||
return '01'
|
return '01'
|
||||||
|
|
||||||
class CreditNoteDocumentType(str):
|
class CreditNoteDocumentType(str):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
# 6.1.3
|
||||||
return '91'
|
return '91'
|
||||||
|
|
||||||
|
class DebitNoteDocumentType(str):
|
||||||
|
def __str__(self):
|
||||||
|
# 6.1.3
|
||||||
|
return '92'
|
||||||
|
|
||||||
class Invoice:
|
class Invoice:
|
||||||
def __init__(self, type_code: str):
|
def __init__(self, type_code: str):
|
||||||
if str(type_code) not in codelist.TipoDocumento:
|
if str(type_code) not in codelist.TipoDocumento:
|
||||||
@ -475,3 +483,12 @@ class CreditNote(Invoice):
|
|||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
class DebitNote(Invoice):
|
||||||
|
def __init__(self, invoice_document_reference: BillingReference):
|
||||||
|
super().__init__(DebitNoteDocumentType())
|
||||||
|
|
||||||
|
if not isinstance(invoice_document_reference, BillingReference):
|
||||||
|
raise TypeError('invoice_document_reference invalid type')
|
||||||
|
self.invoice_billing_reference = invoice_document_reference
|
||||||
|
@ -17,7 +17,7 @@ class DIANDebitNoteXML(fe.FeXML):
|
|||||||
ublextension = self.fragment('/fe:DebitNote/ext:UBLExtensions/ext:UBLExtension', append=True)
|
ublextension = self.fragment('/fe:DebitNote/ext:UBLExtensions/ext:UBLExtension', append=True)
|
||||||
extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent')
|
extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent')
|
||||||
self.attach_invoice(invoice)
|
self.attach_invoice(invoice)
|
||||||
|
|
||||||
def set_supplier(fexml, invoice):
|
def set_supplier(fexml, invoice):
|
||||||
fexml.placeholder_for('/fe:DebitNote/cac:AccountingSupplierParty')
|
fexml.placeholder_for('/fe:DebitNote/cac:AccountingSupplierParty')
|
||||||
#DIAN 1.7.-2020: DAJ02
|
#DIAN 1.7.-2020: DAJ02
|
||||||
@ -101,7 +101,7 @@ class DIANDebitNoteXML(fe.FeXML):
|
|||||||
invoice.invoice_customer.tax_scheme.code)
|
invoice.invoice_customer.tax_scheme.code)
|
||||||
#DIAN 1.7.-2020: DAJ41
|
#DIAN 1.7.-2020: DAJ41
|
||||||
fexml.set_element('/fe:DebitNote/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
|
fexml.set_element('/fe:DebitNote/cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
|
||||||
invoice.invoice_customer.tax_scheme.name)
|
invoice.invoice_customer.tax_scheme.name)
|
||||||
#DIAN 1.7.-2020: DAJ42
|
#DIAN 1.7.-2020: DAJ42
|
||||||
fexml.placeholder_for('/fe:DebitNote/cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity')
|
fexml.placeholder_for('/fe:DebitNote/cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity')
|
||||||
#DIAN 1.7.-2020: DAJ43
|
#DIAN 1.7.-2020: DAJ43
|
||||||
@ -229,7 +229,7 @@ class DIANDebitNoteXML(fe.FeXML):
|
|||||||
#DIAN 1.7.-2020: CAK51, CAK55
|
#DIAN 1.7.-2020: CAK51, CAK55
|
||||||
fexml.set_element('/fe:DebitNote/cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:ElectronicMail',
|
fexml.set_element('/fe:DebitNote/cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:ElectronicMail',
|
||||||
invoice.invoice_customer.email)
|
invoice.invoice_customer.email)
|
||||||
|
|
||||||
|
|
||||||
def set_payment_mean(fexml, invoice):
|
def set_payment_mean(fexml, invoice):
|
||||||
payment_mean = invoice.invoice_payment_mean
|
payment_mean = invoice.invoice_payment_mean
|
||||||
@ -275,10 +275,10 @@ class DIANDebitNoteXML(fe.FeXML):
|
|||||||
schemeName='CUFE-SHA384')
|
schemeName='CUFE-SHA384')
|
||||||
fexml.set_element('/fe:DebitNote/cac:BillingReference/cac:InvoiceDocumentReference/cbc:IssueDate',
|
fexml.set_element('/fe:DebitNote/cac:BillingReference/cac:InvoiceDocumentReference/cbc:IssueDate',
|
||||||
invoice.invoice_billing_reference.date)
|
invoice.invoice_billing_reference.date)
|
||||||
|
|
||||||
|
|
||||||
def set_invoice_totals(fexml, invoice):
|
def set_invoice_totals(fexml, invoice):
|
||||||
tax_amount_for = defaultdict(lambda: defaultdict(lambda: 0.0))
|
tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0)))
|
||||||
percent_for = defaultdict(lambda: None)
|
percent_for = defaultdict(lambda: None)
|
||||||
|
|
||||||
#requeridos para CUDE
|
#requeridos para CUDE
|
||||||
|
@ -416,7 +416,7 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
return fexml._set_invoice_document_reference(reference)
|
return fexml._set_invoice_document_reference(reference)
|
||||||
|
|
||||||
def set_invoice_totals(fexml, invoice):
|
def set_invoice_totals(fexml, invoice):
|
||||||
tax_amount_for = defaultdict(lambda: defaultdict(lambda: 0.0))
|
tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0)))
|
||||||
percent_for = defaultdict(lambda: None)
|
percent_for = defaultdict(lambda: None)
|
||||||
|
|
||||||
#requeridos para CUFE
|
#requeridos para CUFE
|
||||||
|
@ -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, DIANCreditNoteXML
|
from facho.fe.form_xml import DIANInvoiceXML, DIANCreditNoteXML, DIANDebitNoteXML
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def simple_debit_note_without_lines():
|
||||||
|
inv = form.DebitNote(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_credit_note_without_lines():
|
def simple_credit_note_without_lines():
|
||||||
@ -312,3 +344,54 @@ def test_credit_note_cude(simple_credit_note_without_lines):
|
|||||||
cude = xml_invoice.get_element_text('/fe:CreditNote/cbc:UUID')
|
cude = xml_invoice.get_element_text('/fe:CreditNote/cbc:UUID')
|
||||||
# pag 612
|
# pag 612
|
||||||
assert cude == '907e4444decc9e59c160a2fb3b6659b33dc5b632a5008922b9a62f83f757b1c448e47f5867f2b50dbdb96f48c7681168'
|
assert cude == '907e4444decc9e59c160a2fb3b6659b33dc5b632a5008922b9a62f83f757b1c448e47f5867f2b50dbdb96f48c7681168'
|
||||||
|
|
||||||
|
|
||||||
|
# pag 614
|
||||||
|
def test_debit_note_cude(simple_debit_note_without_lines):
|
||||||
|
simple_invoice = simple_debit_note_without_lines
|
||||||
|
simple_invoice.invoice_ident = 'ND1001'
|
||||||
|
simple_invoice.invoice_issue = datetime.strptime('2019-01-18 10:58:00-05:00', '%Y-%m-%d %H:%M:%S%z')
|
||||||
|
simple_invoice.invoice_supplier.ident = form.PartyIdentification('900197264', '5', '31')
|
||||||
|
simple_invoice.invoice_customer.ident = form.PartyIdentification('10254102', '5', '31')
|
||||||
|
simple_invoice.add_invoice_line(form.InvoiceLine(
|
||||||
|
quantity = 1,
|
||||||
|
description = 'producto',
|
||||||
|
item = form.StandardItem('test', 111),
|
||||||
|
price = form.Price(form.Amount(30_000), '01', ''),
|
||||||
|
tax = form.TaxTotal(
|
||||||
|
subtotals = [
|
||||||
|
form.TaxSubTotal(
|
||||||
|
tax_scheme_ident = '04',
|
||||||
|
percent = 8.0
|
||||||
|
)])
|
||||||
|
))
|
||||||
|
|
||||||
|
simple_invoice.calculate()
|
||||||
|
xml_invoice = DIANDebitNoteXML(simple_invoice)
|
||||||
|
|
||||||
|
cude_extension = fe.DianXMLExtensionCUDE(
|
||||||
|
simple_invoice,
|
||||||
|
'10201',
|
||||||
|
tipo_ambiente = fe.AMBIENTE_PRUEBAS,
|
||||||
|
)
|
||||||
|
build_vars = cude_extension.buildVars()
|
||||||
|
assert build_vars['NumFac'] == 'ND1001'
|
||||||
|
assert build_vars['FecFac'] == '2019-01-18'
|
||||||
|
assert build_vars['HoraFac'] == '10:58:00-05:00'
|
||||||
|
assert build_vars['ValorBruto'] == form.Amount(30_000)
|
||||||
|
assert build_vars['NitOFE'] == '900197264'
|
||||||
|
assert build_vars['NumAdq'] == '10254102'
|
||||||
|
assert build_vars['ValorImpuestoPara'][1] == form.Amount(0)
|
||||||
|
assert build_vars['ValorImpuestoPara'][4] == form.Amount(2400)
|
||||||
|
assert build_vars['ValorImpuestoPara'][3] == form.Amount(0)
|
||||||
|
assert build_vars['ValorTotalPagar'] == form.Amount(32400)
|
||||||
|
assert build_vars['Software-PIN'] == '10201'
|
||||||
|
assert build_vars['TipoAmb'] == 2
|
||||||
|
|
||||||
|
|
||||||
|
cude_composicion = "".join(cude_extension.formatVars())
|
||||||
|
assert cude_composicion == 'ND10012019-01-1810:58:00-05:0030000.00010.00042400.00030.0032400.0090019726410254102102012'
|
||||||
|
|
||||||
|
xml_invoice.add_extension(cude_extension)
|
||||||
|
cude = xml_invoice.get_element_text('/fe:DebitNote/cbc:UUID')
|
||||||
|
assert cude == 'b9483dc2a17167feedf37b6bd67c4204e7b601933e0e389cffbd545e4d0ec370b403cbb41ff656776cb6cb5d8348ecd4'
|
||||||
|
Loading…
Reference in New Issue
Block a user