InvoiceLine.tax y TaxTotal.subtotals se hacen opcionales.
Nuevo tipo form.TaxTotalOmit() para excluir de impuesto la linea. FossilOrigin-Name: 84fce4487c15e25724992b14663c2205e592380f2dd1ba99c10ebbc0acb909f6
This commit is contained in:
parent
5dc07a7b4a
commit
54382267ba
42
facho/fe/data/dian/codelist/TipoImpuesto-2.1.custom.gc
Normal file
42
facho/fe/data/dian/codelist/TipoImpuesto-2.1.custom.gc
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- DIAN Genericode listas de valores:: Ultima modificación 18-02-2019 - evb-->
|
||||
<gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/">
|
||||
<Identification>
|
||||
<ShortName>TipoImpuesto</ShortName>
|
||||
<LongName xml:lang="es">Tipo de Tributos</LongName>
|
||||
<Version>1</Version>
|
||||
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoImpuesto</CanonicalUri>
|
||||
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoImpuesto-2.1</CanonicalVersionUri>
|
||||
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TipoImpuesto-2.1.gc</LocationUri>
|
||||
<Agency>
|
||||
<LongName xml:lang="es">DIAN (Dirección de Impuestos y Aduanas Nacionales)</LongName>
|
||||
<Identifier>195</Identifier>
|
||||
</Agency>
|
||||
</Identification>
|
||||
<ColumnSet>
|
||||
<Column Id="code" Use="required">
|
||||
<ShortName>Code</ShortName>
|
||||
<LongName xml:lang="es">Codigo Comun</LongName>
|
||||
<Data Type="normalizedString"/>
|
||||
</Column>
|
||||
<Column Id="name" Use="required">
|
||||
<ShortName>Name</ShortName>
|
||||
<LongName xml:lang="es">Nombre</LongName>
|
||||
<Data Type="string"/>
|
||||
</Column>
|
||||
<Key Id="codeKey">
|
||||
<ShortName>CodeKey</ShortName>
|
||||
<ColumnRef Ref="code"/>
|
||||
</Key>
|
||||
</ColumnSet>
|
||||
<SimpleCodeList>
|
||||
<Row>
|
||||
<Value ColumnRef="code">
|
||||
<SimpleValue>ZY</SimpleValue>
|
||||
</Value>
|
||||
<Value ColumnRef="name">
|
||||
<SimpleValue>No causa</SimpleValue>
|
||||
</Value>
|
||||
</Row>
|
||||
</SimpleCodeList>
|
||||
</gc:CodeList>
|
@ -86,7 +86,8 @@ TipoResponsabilidad = CodeList(path_for_codelist('TipoResponsabilidad-2.1.gc'),
|
||||
.update(CodeList(path_for_codelist('TipoResponsabilidad-2.1.custom.gc'), 'code', 'name'))
|
||||
TipoAmbiente = CodeList(path_for_codelist('TipoAmbiente-2.1.gc'), 'code', 'name')
|
||||
TipoDocumento = CodeList(path_for_codelist('TipoDocumento-2.1.gc'), 'code', 'name')
|
||||
TipoImpuesto = CodeList(path_for_codelist('TipoImpuesto-2.1.gc'), 'code', 'name')
|
||||
TipoImpuesto = CodeList(path_for_codelist('TipoImpuesto-2.1.gc'), 'code', 'name')\
|
||||
.update(CodeList(path_for_codelist('TipoImpuesto-2.1.custom.gc'), 'code', 'name'))
|
||||
CodigoPrecioReferencia = CodeList(path_for_codelist('CodigoPrecioReferencia-2.1.gc'), 'code', 'name')
|
||||
MediosPago = CodeList(path_for_codelist('MediosPago-2.1.gc'), 'code', 'name')
|
||||
RegimenFiscal = CodeList(path_for_codelist('RegimenFiscal-2.1.custom.gc'), 'code', 'name')
|
||||
|
@ -135,15 +135,17 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
||||
build_vars['ValorBruto'] = invoice.invoice_legal_monetary_total.line_extension_amount
|
||||
build_vars['ValorTotalPagar'] = invoice.invoice_legal_monetary_total.payable_amount
|
||||
ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0))
|
||||
build_vars['CodImpuesto1'] = 1
|
||||
build_vars['CodImpuesto2'] = 4
|
||||
build_vars['CodImpuesto3'] = 3
|
||||
build_vars['CodImpuesto1'] = '01'
|
||||
build_vars['CodImpuesto2'] = '04'
|
||||
build_vars['CodImpuesto3'] = '03'
|
||||
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
|
||||
if subtotal.scheme is not None:
|
||||
# TODO cual es la naturaleza de tax_scheme_ident?
|
||||
codigo_impuesto = subtotal.scheme.code
|
||||
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
|
||||
@ -184,11 +186,11 @@ class DianXMLExtensionCUFE(DianXMLExtensionCUDFE):
|
||||
'%s' % build_vars['FecFac'],
|
||||
'%s' % build_vars['HoraFac'],
|
||||
form.Amount(build_vars['ValorBruto']).format('%.02f'),
|
||||
'%02d' % CodImpuesto1,
|
||||
CodImpuesto1,
|
||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0)).format('%.02f'),
|
||||
'%02d' % CodImpuesto2,
|
||||
CodImpuesto2,
|
||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto2, 0.0)).format('%.02f'),
|
||||
'%02d' % CodImpuesto3,
|
||||
CodImpuesto3,
|
||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto3, 0.0)).format('%.02f'),
|
||||
form.Amount(build_vars['ValorTotalPagar']).format('%.02f'),
|
||||
'%s' % build_vars['NitOFE'],
|
||||
@ -221,11 +223,11 @@ class DianXMLExtensionCUDE(DianXMLExtensionCUDFE):
|
||||
'%s' % build_vars['FecFac'],
|
||||
'%s' % build_vars['HoraFac'],
|
||||
form.Amount(build_vars['ValorBruto']).format('%.02f'),
|
||||
'%02d' % CodImpuesto1,
|
||||
CodImpuesto1,
|
||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0)).format('%.02f'),
|
||||
'%02d' % CodImpuesto2,
|
||||
CodImpuesto2,
|
||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto2, 0.0)).format('%.02f'),
|
||||
'%02d' % CodImpuesto3,
|
||||
CodImpuesto3,
|
||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto3, 0.0)).format('%.02f'),
|
||||
form.Amount(build_vars['ValorTotalPagar']).format('%.02f'),
|
||||
'%s' % build_vars['NitOFE'],
|
||||
|
@ -272,16 +272,29 @@ class Party:
|
||||
if self.organization_code not in codelist.TipoOrganizacion:
|
||||
raise ValueError("organization_code not found")
|
||||
|
||||
|
||||
@dataclass
|
||||
class TaxScheme:
|
||||
code: str = '01'
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return codelist.TipoImpuesto[self.code]['name']
|
||||
|
||||
def __post_init__(self):
|
||||
if self.code not in codelist.TipoImpuesto:
|
||||
raise ValueError("code [%s] not found" % (self.code))
|
||||
|
||||
|
||||
@dataclass
|
||||
class TaxSubTotal:
|
||||
percent: float
|
||||
tax_scheme_ident: str = '01'
|
||||
tax_scheme_name: str = 'IVA'
|
||||
|
||||
scheme: typing.Optional[TaxScheme] = None
|
||||
tax_amount: Amount = Amount(0.0)
|
||||
|
||||
def calculate(self, invline):
|
||||
self.tax_amount = invline.total_amount * Amount(self.percent / 100)
|
||||
if self.percent is not None:
|
||||
self.tax_amount = invline.total_amount * Amount(self.percent / 100)
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -298,6 +311,13 @@ class TaxTotal:
|
||||
self.tax_amount += subtax.tax_amount
|
||||
|
||||
|
||||
class TaxTotalOmit(TaxTotal):
|
||||
def __init__(self):
|
||||
super().__init__([])
|
||||
|
||||
def calculate(self, invline):
|
||||
pass
|
||||
|
||||
@dataclass
|
||||
class Price:
|
||||
amount: Amount
|
||||
@ -377,7 +397,8 @@ class InvoiceLine:
|
||||
|
||||
@property
|
||||
def total_tax_inclusive_amount(self):
|
||||
return self.tax.taxable_amount + self.tax.tax_amount
|
||||
# FAU06
|
||||
return self.total_amount + self.tax.tax_amount
|
||||
|
||||
@property
|
||||
def total_tax_exclusive_amount(self):
|
||||
|
@ -424,8 +424,8 @@ class DIANInvoiceXML(fe.FeXML):
|
||||
percent_for = defaultdict(lambda: None)
|
||||
|
||||
#requeridos para CUFE
|
||||
tax_amount_for['01']['tax_amount'] = Amount(0.0)
|
||||
tax_amount_for['01']['taxable_amount'] = Amount(0.0)
|
||||
#tax_amount_for['01']['tax_amount'] = Amount(0.0)
|
||||
#tax_amount_for['01']['taxable_amount'] = Amount(0.0)
|
||||
#DIAN 1.7.-2020: FAS07 => Se debe construir estrategia para su manejo
|
||||
#tax_amount_for['04']['tax_amount'] = 0.0
|
||||
#tax_amount_for['04']['taxable_amount'] = 0.0
|
||||
@ -435,13 +435,15 @@ class DIANInvoiceXML(fe.FeXML):
|
||||
total_tax_amount = Amount(0.0)
|
||||
|
||||
for invoice_line in invoice.invoice_lines:
|
||||
|
||||
for subtotal in invoice_line.tax.subtotals:
|
||||
tax_amount_for[subtotal.tax_scheme_ident]['tax_amount'] += subtotal.tax_amount
|
||||
tax_amount_for[subtotal.tax_scheme_ident]['taxable_amount'] += invoice_line.taxable_amount
|
||||
if subtotal.scheme is not None:
|
||||
tax_amount_for[subtotal.scheme.code]['tax_amount'] += subtotal.tax_amount
|
||||
tax_amount_for[subtotal.scheme.code]['taxable_amount'] += invoice_line.taxable_amount
|
||||
|
||||
# MACHETE ojo InvoiceLine.tax pasar a Invoice
|
||||
percent_for[subtotal.scheme.code] = subtotal.percent
|
||||
|
||||
total_tax_amount += subtotal.tax_amount
|
||||
# MACHETE ojo InvoiceLine.tax pasar a Invoice
|
||||
percent_for[subtotal.tax_scheme_ident] = subtotal.percent
|
||||
|
||||
fexml.placeholder_for('./cac:TaxTotal')
|
||||
fexml.set_element_amount('./cac:TaxTotal/cbc:TaxAmount',
|
||||
@ -491,6 +493,27 @@ class DIANInvoiceXML(fe.FeXML):
|
||||
def tag_document_concilied(fexml):
|
||||
return 'Invoiced'
|
||||
|
||||
def set_invoice_line_tax(fexml, line, invoice_line):
|
||||
fexml.set_element_amount_for(line,
|
||||
'./cac:TaxTotal/cbc:TaxAmount',
|
||||
invoice_line.tax_amount)
|
||||
|
||||
#DIAN 1.7.-2020: FAX05
|
||||
fexml.set_element_amount_for(line,
|
||||
'./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
||||
invoice_line.taxable_amount)
|
||||
|
||||
for subtotal in invoice_line.tax.subtotals:
|
||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP')
|
||||
|
||||
if subtotal.percent is not None:
|
||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', '%0.2f' % round(subtotal.percent, 2))
|
||||
|
||||
if subtotal.scheme is not None:
|
||||
#DIAN 1.7.-2020: FAX15
|
||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code)
|
||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name)
|
||||
|
||||
def set_invoice_lines(fexml, invoice):
|
||||
next_append = False
|
||||
for index, invoice_line in enumerate(invoice.invoice_lines):
|
||||
@ -502,20 +525,10 @@ class DIANInvoiceXML(fe.FeXML):
|
||||
fexml.set_element_amount_for(line,
|
||||
'./cbc:LineExtensionAmount',
|
||||
invoice_line.total_amount)
|
||||
fexml.set_element_amount_for(line,
|
||||
'./cac:TaxTotal/cbc:TaxAmount',
|
||||
invoice_line.tax_amount)
|
||||
|
||||
#DIAN 1.7.-2020: FAX05
|
||||
fexml.set_element_amount_for(line,
|
||||
'./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
||||
invoice_line.taxable_amount)
|
||||
if not isinstance(invoice_line.tax, TaxTotalOmit):
|
||||
fexml.set_invoice_line_tax(line, invoice_line)
|
||||
|
||||
for subtotal in invoice_line.tax.subtotals:
|
||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP')
|
||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', subtotal.percent)
|
||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.tax_scheme_ident)
|
||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.tax_scheme_name)
|
||||
line.set_element('./cac:Item/cbc:Description', invoice_line.item.description)
|
||||
|
||||
line.set_element('./cac:Item/cac:StandardItemIdentification/cbc:ID',
|
||||
|
Loading…
Reference in New Issue
Block a user