Se adiciona xml de AllowanceCharge para documento
FossilOrigin-Name: 93cd9530bb2f63a2803b8a32a5aceeeda015eff2d26c96e95a13dbb9193cad82
This commit is contained in:
parent
e571009945
commit
1143b26988
@ -396,6 +396,43 @@ class InvoiceDocumentReference(BillingReference):
|
|||||||
date: fecha de emision de la nota credito relacionada
|
date: fecha de emision de la nota credito relacionada
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AllowanceChargeReason:
|
||||||
|
code: str
|
||||||
|
reason: str
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if self.code not in codelist.CodigoDescuento:
|
||||||
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AllowanceCharge:
|
||||||
|
#DIAN 1.7.-2020: FAQ03
|
||||||
|
charge_indicator: bool = True
|
||||||
|
amount: Amount = Amount(0.0)
|
||||||
|
reason: AllowanceChargeReason = None
|
||||||
|
|
||||||
|
def isCharge(self):
|
||||||
|
return self.charge_indicator == True
|
||||||
|
|
||||||
|
def isDiscount(self):
|
||||||
|
return self.charge_indicator == False
|
||||||
|
|
||||||
|
def asCharge(self):
|
||||||
|
self.charge_indicator = True
|
||||||
|
|
||||||
|
def asDiscount(self):
|
||||||
|
self.charge_indicator = False
|
||||||
|
|
||||||
|
def hasReason(self):
|
||||||
|
return self.reason is not None
|
||||||
|
|
||||||
|
class AllowanceChargeAsDiscount(AllowanceCharge):
|
||||||
|
def __init__(self, amount: Amount = Amount(0.0)):
|
||||||
|
self.charge_indicator = False
|
||||||
|
self.amount = amount
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class InvoiceLine:
|
class InvoiceLine:
|
||||||
# RESOLUCION 0004: pagina 155
|
# RESOLUCION 0004: pagina 155
|
||||||
@ -409,6 +446,13 @@ class InvoiceLine:
|
|||||||
# de subtotal
|
# de subtotal
|
||||||
tax: typing.Optional[TaxTotal]
|
tax: typing.Optional[TaxTotal]
|
||||||
|
|
||||||
|
allowance_charge = []
|
||||||
|
|
||||||
|
def add_allowance_charge(charge):
|
||||||
|
if not isinstance(charge, AllowanceCharge):
|
||||||
|
raise TypeError('charge invalid type expected AllowanceCharge')
|
||||||
|
self.allowance_charge.add(charge)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total_amount(self):
|
def total_amount(self):
|
||||||
return self.quantity * self.price.amount
|
return self.quantity * self.price.amount
|
||||||
@ -459,42 +503,6 @@ class LegalMonetaryTotal:
|
|||||||
- self.prepaid_amount
|
- self.prepaid_amount
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class AllowanceChargeReason:
|
|
||||||
code: str
|
|
||||||
reason: str
|
|
||||||
|
|
||||||
def __post_init__(self):
|
|
||||||
if self.code not in codelist.CodigoDescuento:
|
|
||||||
raise ValueError("code [%s] not found" % (self.code))
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class AllowanceCharge:
|
|
||||||
#DIAN 1.7.-2020: FAQ03
|
|
||||||
charge_indicator: bool = True
|
|
||||||
amount: Amount = Amount(0.0)
|
|
||||||
reason: AllowanceChargeReason = None
|
|
||||||
|
|
||||||
def isCharge(self):
|
|
||||||
return self.charge_indicator == True
|
|
||||||
|
|
||||||
def isDiscount(self):
|
|
||||||
return self.charge_indicator == False
|
|
||||||
|
|
||||||
def asCharge(self):
|
|
||||||
self.charge_indicator = True
|
|
||||||
|
|
||||||
def asDiscount(self):
|
|
||||||
self.charge_indicator = False
|
|
||||||
|
|
||||||
def hasReason(self):
|
|
||||||
return self.reason is not None
|
|
||||||
|
|
||||||
class AllowanceChargeAsDiscount(AllowanceCharge):
|
|
||||||
def __init__(self, amount: Amount = Amount(0.0)):
|
|
||||||
self.charge_indicator = False
|
|
||||||
self.amount = amount
|
|
||||||
|
|
||||||
class NationalSalesInvoiceDocumentType(str):
|
class NationalSalesInvoiceDocumentType(str):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -593,7 +601,7 @@ class Invoice:
|
|||||||
|
|
||||||
self.invoice_operation_type = operation
|
self.invoice_operation_type = operation
|
||||||
|
|
||||||
def add_allownace_charge(self, charge: AllowanceCharge):
|
def add_allowance_charge(self, charge: AllowanceCharge):
|
||||||
self.invoice_allowance_charge.append(charge)
|
self.invoice_allowance_charge.append(charge)
|
||||||
|
|
||||||
def add_invoice_line(self, line: InvoiceLine):
|
def add_invoice_line(self, line: InvoiceLine):
|
||||||
|
@ -543,6 +543,22 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
invoice_line.price.quantity,
|
invoice_line.price.quantity,
|
||||||
unitCode=invoice_line.quantity.code)
|
unitCode=invoice_line.quantity.code)
|
||||||
|
|
||||||
|
def set_allowance_charge(fexml, invoice):
|
||||||
|
for idx, charge in enumerate(invoice.invoice_allowance_charge):
|
||||||
|
next_append = idx > 0
|
||||||
|
fexml.append_allowance_charge(fexml, idx + 1, charge, append=next_append)
|
||||||
|
|
||||||
|
def append_allowance_charge(fexml, parent, idx, charge, append=False):
|
||||||
|
line = fexml.fragment('./cac:AllowanceCharge', append=append)
|
||||||
|
#DIAN 1.7.-2020: FAQ02
|
||||||
|
line.set_element('./cbc:ID', idx)
|
||||||
|
#DIAN 1.7.-2020: FAQ03
|
||||||
|
line.set_element('./cbc:ChargeIndicator', str(charge.charge_indicator).lower())
|
||||||
|
if charge.reason:
|
||||||
|
line.set_element('./cbc:AllowanceChargeReasonCode', charge.reason.code)
|
||||||
|
line.set_element('./cbc:allowanceChargeReason', charge.reason.reason)
|
||||||
|
fexml.set_element_amount_for(line, './cbc:Amount', charge.amount)
|
||||||
|
|
||||||
|
|
||||||
def attach_invoice(fexml, invoice):
|
def attach_invoice(fexml, invoice):
|
||||||
"""adiciona etiquetas a FEXML y retorna FEXML
|
"""adiciona etiquetas a FEXML y retorna FEXML
|
||||||
@ -579,6 +595,7 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
fexml.set_invoice_totals(invoice)
|
fexml.set_invoice_totals(invoice)
|
||||||
fexml.set_invoice_lines(invoice)
|
fexml.set_invoice_lines(invoice)
|
||||||
fexml.set_payment_mean(invoice)
|
fexml.set_payment_mean(invoice)
|
||||||
|
fexml.set_allowance_charge(invoice)
|
||||||
fexml.set_billing_reference(invoice)
|
fexml.set_billing_reference(invoice)
|
||||||
|
|
||||||
return fexml
|
return fexml
|
||||||
|
@ -61,7 +61,7 @@ def test_FAU10():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
inv.add_allownace_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
inv.add_allowance_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
||||||
|
|
||||||
inv.calculate()
|
inv.calculate()
|
||||||
assert inv.invoice_legal_monetary_total.line_extension_amount == form.Amount(100.0)
|
assert inv.invoice_legal_monetary_total.line_extension_amount == form.Amount(100.0)
|
||||||
@ -89,7 +89,7 @@ def test_FAU14():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
inv.add_allownace_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
inv.add_allowance_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
||||||
inv.add_prepaid_payment(form.PrePaidPayment(paid_amount = form.Amount(50.0)))
|
inv.add_prepaid_payment(form.PrePaidPayment(paid_amount = form.Amount(50.0)))
|
||||||
inv.calculate()
|
inv.calculate()
|
||||||
|
|
||||||
|
@ -6,9 +6,13 @@
|
|||||||
"""Tests for `facho` package."""
|
"""Tests for `facho` package."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from facho.fe import form
|
||||||
from facho.fe import form_xml
|
from facho.fe import form_xml
|
||||||
|
|
||||||
|
from fixtures import *
|
||||||
|
|
||||||
def test_import_DIANInvoiceXML():
|
def test_import_DIANInvoiceXML():
|
||||||
try:
|
try:
|
||||||
form_xml.DIANInvoiceXML
|
form_xml.DIANInvoiceXML
|
||||||
@ -27,3 +31,29 @@ def test_import_DIANCreditNoteXML():
|
|||||||
form_xml.DIANCreditNoteXML
|
form_xml.DIANCreditNoteXML
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pytest.fail("unexpected not found")
|
pytest.fail("unexpected not found")
|
||||||
|
|
||||||
|
def test_FAU10(simple_invoice_without_lines):
|
||||||
|
inv = simple_invoice_without_lines
|
||||||
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
|
quantity = form.Quantity(1, '94'),
|
||||||
|
description = 'producto facho',
|
||||||
|
item = form.StandardItem(9999),
|
||||||
|
price = form.Price(
|
||||||
|
amount = form.Amount(100.0),
|
||||||
|
type_code = '01',
|
||||||
|
type = 'x'
|
||||||
|
),
|
||||||
|
tax = form.TaxTotal(
|
||||||
|
subtotals = [
|
||||||
|
form.TaxSubTotal(
|
||||||
|
percent = 19.0,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
))
|
||||||
|
inv.add_allowance_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
||||||
|
|
||||||
|
xml = form_xml.DIANInvoiceXML(inv)
|
||||||
|
assert xml.get_element_text('./cac:AllowanceCharge/cbc:ID') == '1'
|
||||||
|
assert xml.get_element_text('./cac:AllowanceCharge/cbc:ChargeIndicator') == 'true'
|
||||||
|
assert xml.get_element_text('./cac:AllowanceCharge/cbc:Amount') == '19.0'
|
||||||
|
Loading…
Reference in New Issue
Block a user