28 Commits

Author SHA1 Message Date
cosmos
c919d8e36c Add timestamp 2024-08-22 09:41:37 -05:00
c12d985f76 Fix: Se añade condición para Period in invoice.py 2024-05-17 14:01:28 -05:00
9c126d961b Fix: Se implementa estrategía para CreditNote 2024-05-15 16:02:56 -05:00
95f16b2842 Fix: Se actualiza DockerFile Con base en la rama Master 2024-05-15 16:01:25 -05:00
8f327f7abc feat: UPDATE Habilitacion RUSTIK 2024-03-12 17:05:55 -05:00
Rodia
b7c9f2b201 revert 7f974b7077
revert feat: Se actualizan dependencias para python3.11 issue #1
2023-12-05 09:09:40 -05:00
7f974b7077 feat: Se actualizan dependencias para python3.11 issue #1 2023-12-05 09:15:48 -05:00
78477de2c2 Se Cambia tipo de impuesto en linea de factura 2023-10-24 16:25:58 -05:00
sinergia
75b41379c4 add withholding tax to support document
FossilOrigin-Name: 203ecd7e08ef0c050f27059c09af894600a45cbed73b11710f4e598362a414b4
2023-03-30 19:47:50 +00:00
sinergia
d26cc2bef7 add RTE to invoice
FossilOrigin-Name: 8d9aa1694a61e0e358e4cc8c5ecb1b3544d18e353535491f5b8a576c5b5fe446
2023-02-19 22:32:36 +00:00
sinergia
1abf34d4f0 actualización de responsabilidades anexo 1.8
FossilOrigin-Name: f872310df40172344c5de9957e0db5800a34e2736e087878f785253e9c11540a
2022-10-25 19:15:15 +00:00
root
3862b3e934 Update files gc taxes
FossilOrigin-Name: 9bceb0c3494ecda7acffe86ebd9b4705078db1028fe62686c8f9010c4850959f
2022-09-07 17:11:39 +00:00
sinergia
5cf929cca9 supportDocument add files
FossilOrigin-Name: 13f3285cfe89ea2859463326536c23f60862112d70816d1c792e1e074edf6785
2022-08-31 19:51:38 +00:00
sinergia
7e51726a0d SupportDocumentCreditNote
FossilOrigin-Name: 7ac7f5bbd22e5ac381c21adf358b021182eac84ebfe38624a59355c79075d70b
2022-08-31 05:51:56 +00:00
cosmos
f05eb61d6e Add DIANXMLExtencionCUDS in __ini__.py
FossilOrigin-Name: a8b2f04c0805336c13516f63f1bbcac6490e7704019eb55caf90ddca548a0cd3
2022-08-28 22:10:17 +00:00
cosmos
5a045ccdef support document updates DSAZ13 DSAZ14
FossilOrigin-Name: 18a1849b96425974b7e53bc236a9484e7c064e960b90844675eb4fe02cf6ad8a
2022-08-28 16:42:54 +00:00
sinergia
bd0fe70f33 xml support document
FossilOrigin-Name: 4d1f4e81f2527a0c4ba735f4f5edc8bc8dfebff2365e8e2ee91d4cd435acecf8
2022-08-27 22:43:16 +00:00
sinergia
7c4c9648fe add new module support_document
FossilOrigin-Name: df52f8e96f61cf3fc6698ee840e64cd412cf4e2c899890def50f3bf4f48a2bb3
2022-08-27 17:00:40 +00:00
alnus
5eecae0740 Create new branch named "documento_soporte"
FossilOrigin-Name: 9a8d5c9f6240da5b4aaa46cea4305e0b673644bca7f6a42cbbfd9842e3092b60
2022-08-27 16:46:55 +00:00
bit4bit
a59df60fc2 se adiciona prueba para tipo xml ajusts en nomina de ajuste
FossilOrigin-Name: 8cb6aa07cdafad91fc13f0d3a4454ddcd26c4ce40feb7cde43a413c3bddf409f
2022-05-30 19:50:47 +00:00
bit4bit
19c5a5bca6 se usa __eq__ en vez de same
FossilOrigin-Name: 05cda833815fbceb23ea6356c71daa37e3cc0d53300c726b0ffacae63bf4ab41
2022-05-30 19:28:00 +00:00
bit4bit
c50f1df1e7 se usa __eq__ en vez de same
FossilOrigin-Name: 96875a241ba61f2072f531e8845ae7dd981c9739c5d322555035243214204e4f
2022-05-30 19:26:44 +00:00
bit4bit
2a1f3b6b43 se actualiza CONTRIBUTING.md
FossilOrigin-Name: a814f92dd0ebacac700618b48c0cc3d677918c1e461519461489dd14f4b98cca
2022-05-30 19:18:47 +00:00
bit4bit
a208d924dd se mueve pruebas nomina de ajuste a test_nomina_ajuste.py
FossilOrigin-Name: 5cf7c9d1ea339d30416076f0fa1f8d3dd89452ac2f8f955b8daa67dd351c8843
2022-05-30 19:17:15 +00:00
pingara
c3b0f7cfe8 Pruebas de nómina en Nómina Ajuste actualizadas
FossilOrigin-Name: d799f3660231a69b7483298e7c7d62d51933529190fff51fa3d5de1a3ac50304
2022-05-19 21:33:46 +00:00
pingara
005f90166e Actualizar para envío de Nómina Ajuste
FossilOrigin-Name: 98e5f9522b428c2e401b9fb5ba2f8a96157415ada89aef70d7b7900674a461b8
2022-05-19 21:27:55 +00:00
pingara
73bb90b74b Validación contiene errores en campos mandatorio en schemalocation
FossilOrigin-Name: 834a1cd8bca356b5794fcaf6cafe5b84adc2a70bc719a25085bae4379a58f038
2022-05-19 02:18:02 +00:00
bit4bit
6bed600dd4 mezcla machete
FossilOrigin-Name: 0ea0f8f6c5fe4b809abdb59e33163316a1794bc4571649ce5a1c89aa58a6f32e
2022-05-11 01:19:59 +00:00
24 changed files with 1633 additions and 1444 deletions

View File

@@ -94,6 +94,14 @@ Ready to contribute? Here's how to set up `facho` for local development.
7. Submit a pull request through the GitHub website.
Using docker
------------
1. make -f Makefile.dev build
2. make -f Makefile.dev dev-shell
3. make -f Makefile.dev python3.8 setup.py develop
4. make -f Makefile.dev python3.8 setup.py test
Pull Request Guidelines
-----------------------

View File

@@ -1,17 +1,24 @@
# DERIVADO DE https://alextereshenkov.github.io/run-python-tests-with-tox-in-docker.html
FROM ubuntu:18.04
FROM ubuntu:24.04
RUN apt-get -qq update
RUN apt install software-properties-common -y \
&& add-apt-repository ppa:deadsnakes/ppa
RUN apt-get install -y --no-install-recommends \
python3.7 python3.7-distutils python3.7-dev \
python3.8 python3.8-distutils python3.8-dev \
python3.9 python3.9-distutils python3.9-dev \
python3.10 python3.10-distutils python3.10-dev \
wget \
ca-certificates
RUN wget https://bootstrap.pypa.io/get-pip.py \
&& python3 get-pip.py pip==21.3 \
&& python3.7 get-pip.py pip==21.3 \
&& python3.8 get-pip.py pip==21.3 \
&& python3.7 get-pip.py pip==22.2.2 \
&& python3.8 get-pip.py pip==22.2.2 \
&& python3.9 get-pip.py pip==22.2.2 \
&& python3.10 get-pip.py pip==22.2.2 \
&& rm get-pip.py
RUN apt-get install -y --no-install-recommends \
@@ -20,12 +27,14 @@ RUN apt-get install -y --no-install-recommends \
build-essential \
zip
RUN python3.6 --version
RUN python3.7 --version
RUN python3.8 --version
RUN python3.9 --version
RUN python3.10 --version
RUN pip3.6 install setuptools setuptools-rust
RUN pip3.7 install setuptools setuptools-rust
RUN pip3.8 install setuptools setuptools-rust
RUN pip3.9 install setuptools setuptools-rust
RUN pip3.10 install setuptools setuptools-rust
RUN pip3 install tox pytest

View File

@@ -11,9 +11,6 @@
dev-setup:
docker build -t facho .
py-develop:
docker run -t -v $(PWD):/app -w /app facho sh -c 'python3.7 setup.py develop --user'
dev-shell:
docker run --rm -ti -v "$(PWD):/app" -w /app --name facho-cli facho bash

View File

@@ -259,14 +259,14 @@ def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=Tr
spec.loader.exec_module(module)
import facho.fe.form as form
from facho.fe.form_xml import DIANInvoiceXML, DIANWriteSigned,DIANWrite
from facho.fe.form_xml import DIANInvoiceXML, DIANWriteSigned, DIANWrite, DIANSupportDocumentXML
from facho import fe
try:
invoice_xml = module.document_xml()
except AttributeError:
invoice_xml = DIANInvoiceXML
#invoice_xml = DIANInvoiceXML
invoice_xml = DIANSupportDocumentXML
print("Using document xml:", invoice_xml)
invoice = module.invoice()
invoice.calculate()

View File

@@ -1,12 +1,11 @@
# This file is part of facho. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from lxml import etree
from lxml.etree import Element, SubElement, tostring
from lxml.etree import Element, tostring
import re
from collections import defaultdict
from copy import deepcopy
from pprint import pprint
class FachoValueInvalid(Exception):
def __init__(self, xpath):
@@ -32,7 +31,10 @@ class LXMLBuilder:
def __init__(self, nsmap):
self.nsmap = nsmap
self._re_node_expr = re.compile(r'^(?P<path>((?P<ns>\w+):)?(?P<tag>[a-zA-Z0-9_-]+))(?P<attrs>\[.+\])?')
self._re_node_expr = \
re.compile(
r'^(?P<path>((?P<ns>\w+):)?(?P<tag>[a-zA-Z0-9_-]+))'
r'(?P<attrs>\[.+\])?')
self._re_attrs = re.compile(r'(\w+)\s*=\s*\"?(\w+)\"?')
def match_expression(self, node_expr):
@@ -121,7 +123,7 @@ class LXMLBuilder:
elem.attrib[key] = value
@classmethod
def remove_attributes(cls, elem, keys, exclude = []):
def remove_attributes(cls, elem, keys, exclude=[]):
for key in keys:
if key in exclude:
continue
@@ -143,7 +145,8 @@ class LXMLBuilder:
self.remove_attributes(el, keys, exclude=['facho_optional'])
is_optional = el.get('facho_optional', 'False') == 'True'
if is_optional and el.getchildren() == [] and el.keys() == ['facho_optional']:
if is_optional and el.getchildren() == [] and el.keys() == [
'facho_optional']:
el.getparent().remove(el)
return tostring(elem, **attrs).decode('utf-8')
@@ -153,14 +156,15 @@ class FachoXML:
"""
Decora XML con funciones de consulta XPATH de un solo elemento
"""
def __init__(self, root, builder=None, nsmap=None, fragment_prefix='',fragment_root_element=None):
def __init__(self, root, builder=None, nsmap=None, fragment_prefix='',
fragment_root_element=None):
if builder is None:
self.builder = LXMLBuilder(nsmap)
else:
self.builder = builder
self.nsmap = nsmap
if isinstance(root, str):
self.root = self.builder.build_element_from_string(root, nsmap)
else:
@@ -180,16 +184,19 @@ class FachoXML:
def root_namespace(self):
return etree.QName(self.root).namespace
def root_localname(self):
return etree.QName(self.root).localname
def append_element(self, elem, new_elem):
#elem = self.find_or_create_element(xpath, append=append)
#self.builder.append(elem, new_elem)
# elem = self.find_or_create_element(xpath, append=append)
# self.builder.append(elem, new_elem)
self.builder.append(elem, new_elem)
def add_extension(self, extension):
extension.build(self)
def fragment(self, xpath, append=False, append_not_exists=False):
def fragment(
self, xpath, append=False, append_not_exists=False):
nodes = xpath.split('/')
nodes.pop()
root_prefix = '/'.join(nodes)
@@ -199,7 +206,9 @@ class FachoXML:
if parent is None:
parent = self.find_or_create_element(xpath, append=append)
return FachoXML(parent, nsmap=self.nsmap, fragment_prefix=root_prefix, fragment_root_element=self.root)
return FachoXML(
parent, nsmap=self.nsmap, fragment_prefix=root_prefix,
fragment_root_element=self.root)
def register_alias_xpath(self, alias, xpath):
self.xpath_for[alias] = xpath
@@ -235,7 +244,8 @@ class FachoXML:
"""
xpath = self._path_xpath_for(xpath)
node_paths = xpath.split('/')
node_paths.pop(0) #remove empty /
# remove empty /
node_paths.pop(0)
root_tag = node_paths.pop(0)
root_node = self.builder.build_from_expression(root_tag)
@@ -243,10 +253,10 @@ class FachoXML:
# restaurar ya que no es la raiz y asignar actual como raiz
node_paths.insert(0, root_tag)
root_node = self.root
if not self.builder.same_tag(root_node.tag, self.root.tag):
raise ValueError('xpath %s must be absolute to /%s' % (xpath, self.root.tag))
raise ValueError('xpath %s must be absolute to /%s' % (
xpath, self.root.tag))
# crea jerarquia segun xpath indicado
parent = None
@@ -256,8 +266,8 @@ class FachoXML:
for node_path in node_paths:
node_expr = self.builder.match_expression(node_path)
node = self.builder.build_from_expression(node_path)
child = self.builder.find_relative(current_elem, node_expr['path'], self.nsmap)
child = self.builder.find_relative(
current_elem, node_expr['path'], self.nsmap)
parent = current_elem
if child is not None:
@@ -268,11 +278,12 @@ class FachoXML:
node_expr = self.builder.match_expression(node_tag)
node = self.builder.build_from_expression(node_tag)
child = self.builder.find_relative(current_elem, node_expr['path'], self.nsmap)
child = self.builder.find_relative(
current_elem, node_expr['path'], self.nsmap)
parent = current_elem
if child is not None:
current_elem = child
if parent == current_elem:
self.builder.append(parent, node)
return node
@@ -289,9 +300,10 @@ class FachoXML:
self.builder.append(parent, node)
return node
if self.builder.is_attribute(last_slibing, 'facho_placeholder', 'True'):
if self.builder.is_attribute(
last_slibing, 'facho_placeholder', 'True'):
self._remove_facho_attributes(last_slibing)
return last_slibing
return last_slibing
self.builder.append_next(last_slibing, node)
return node
@@ -302,7 +314,8 @@ class FachoXML:
self._remove_facho_attributes(current_elem)
return current_elem
def set_element_validator(self, xpath, validator = False):
def set_element_validator(
self, xpath, validator=False):
"""
validador al asignar contenido a xpath indicado
@@ -315,8 +328,9 @@ class FachoXML:
self._validators[key] = lambda v, attrs: True
else:
self._validators[key] = validator
def set_element(self, xpath, content, **attrs):
def set_element(
self, xpath, content, **attrs):
"""
asigna contenido ubicado por ruta tipo XPATH.
@param xpath ruta tipo XPATH
@@ -358,7 +372,8 @@ class FachoXML:
self.builder.set_attribute(elem, k, str(v))
return self
def get_element_attribute(self, xpath, attribute, multiple=False):
def get_element_attribute(
self, xpath, attribute, multiple=False):
elem = self.get_element(xpath, multiple=multiple)
if elem is None:
@@ -395,14 +410,16 @@ class FachoXML:
return None
return format_(text)
def get_element_text_or_attribute(self, xpath, default=None, multiple=False, raise_on_fail=False):
def get_element_text_or_attribute(
self, xpath, default=None, multiple=False, raise_on_fail=False):
parts = xpath.split('/')
is_attribute = parts[-1].startswith('@')
is_attribute = parts[-1].startswith('@')
if is_attribute:
attribute_name = parts.pop(-1).lstrip('@')
element_path = "/".join(parts)
try:
val = self.get_element_attribute(element_path, attribute_name, multiple=multiple)
val = self.get_element_attribute(
element_path, attribute_name, multiple=multiple)
if val is None:
return default
return val
@@ -435,7 +452,8 @@ class FachoXML:
if isinstance(xpath, tuple):
val = xpath[0]
else:
val = self.get_element_text_or_attribute(xpath, raise_on_fail=raise_on_fail)
val = self.get_element_text_or_attribute(
xpath, raise_on_fail=raise_on_fail)
vals.append(val)
return vals
@@ -457,7 +475,8 @@ class FachoXML:
return True
def _remove_facho_attributes(self, elem):
self.builder.remove_attributes(elem, ['facho_optional', 'facho_placeholder'])
self.builder.remove_attributes(
elem, ['facho_optional', 'facho_placeholder'])
def tostring(self, **kw):
return self.builder.tostring(self.root, **kw)
@@ -469,15 +488,17 @@ class FachoXML:
root = self.root
if self.fragment_root_element is not None:
root = self.fragment_root_element
if isinstance(self.nsmap, dict):
nsmap = dict(map(reversed, self.nsmap.items()))
ns = nsmap[etree.QName(root).namespace] + ':'
if self.fragment_root_element is not None:
new_xpath = '/' + ns + etree.QName(root).localname + '/' + etree.QName(self.root).localname + '/' + xpath.lstrip('/')
new_xpath = '/' + ns + etree.QName(root).localname + '/' + \
etree.QName(self.root).localname + '/' + xpath.lstrip('/')
else:
new_xpath = '/' + ns + etree.QName(root).localname + '/' + xpath.lstrip('/')
new_xpath = '/' + ns + etree.QName(root).localname + '/' + \
xpath.lstrip('/')
return new_xpath
def __str__(self):

View File

@@ -5,6 +5,7 @@ from .fe import DianXMLExtensionSigner
from .fe import DianXMLExtensionSoftwareSecurityCode
from .fe import DianXMLExtensionCUFE
from .fe import DianXMLExtensionCUDE
from .fe import DianXMLExtensionCUDS
from .fe import DianXMLExtensionInvoiceAuthorization
from .fe import DianXMLExtensionSoftwareProvider
from .fe import DianXMLExtensionAuthorizationProvider

View File

@@ -234,9 +234,10 @@ def _append_timestamp(security, expires_dt=None):
if expires_dt is None:
expires_dt = timedelta(seconds=6000)
timestamp = datetime.now()
etimestamp = utils.WSU.Timestamp({'{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id': utils.get_unique_id()})
etimestamp.append(utils.WSU.Created(get_timestamp()))
etimestamp.append(utils.WSU.Expires(get_timestamp(delta=expires_dt)))
etimestamp.append(utils.WSU.Created(get_timestamp(timestamp=timestamp)))
etimestamp.append(utils.WSU.Expires(get_timestamp(timestamp=timestamp, delta=expires_dt)))
security.insert(0, etimestamp)
if etree.LXML_VERSION[:2] >= (3, 5):
etree.cleanup_namespaces(security,

View File

@@ -1,50 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- DIAN Genericode listas de validacion :: Ultima modificación 18-02-2019 - evb-->
<gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/">
<Identification>
<ShortName>TarifaImpuestos</ShortName>
<LongName xml:lang="es">Tarifas por Impuesto</LongName>
<Version>1</Version>
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TarifaImpuestos</CanonicalUri>
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TarifaImpuestos-2.1</CanonicalVersionUri>
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TarifaImpuestos-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>
<Column Id="description" Use="required">
<ShortName>Description</ShortName>
<LongName xml:lang="es">Descripcion</LongName>
<Data Type="string"/>
</Column>
<Key Id="codeKey">
<ShortName>CodeKey</ShortName>
<ColumnRef Ref="code"/>
</Key>
</ColumnSet>
<SimpleCodeList>
<Row>
<Value ColumnRef="code">
<SimpleValue>15.00</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteIVA</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>ReteIVA</SimpleValue>
</Value>
</Row>
</SimpleCodeList>
</gc:CodeList>
<?xml version="1.0" encoding="UTF-8"?>
<!-- DIAN Genericode listas de validacion :: Ultima modificación 18-02-2019 - evb-->
<gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/">
<Identification>
<ShortName>TarifaImpuestos</ShortName>
<LongName xml:lang="es">Tarifas por Impuesto</LongName>
<Version>1</Version>
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TarifaImpuestos</CanonicalUri>
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TarifaImpuestos-2.1</CanonicalVersionUri>
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TarifaImpuestos-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>
<Column Id="description" Use="required">
<ShortName>Description</ShortName>
<LongName xml:lang="es">Descripcion</LongName>
<Data Type="string"/>
</Column>
<Key Id="codeKey">
<ShortName>CodeKey</ShortName>
<ColumnRef Ref="code"/>
</Key>
</ColumnSet>
<SimpleCodeList>
<Row>
<Value ColumnRef="code">
<SimpleValue>15.00</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteIVA</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>ReteIVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>100.00</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteIVA</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>ReteIVA</SimpleValue>
</Value>
</Row>
</SimpleCodeList>
</gc:CodeList>

View File

@@ -1,74 +1,122 @@
<?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>TipoDocumento</ShortName>
<LongName xml:lang="es">Tipo de Documento</LongName>
<Version>1</Version>
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoDocumento</CanonicalUri>
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoDocumento-2.1</CanonicalVersionUri>
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TipoDocumento-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>01</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factura de Venta Nacional</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>02</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factura de Exportación </SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>03</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factura de Contingencia</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>91</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Nota Crédito</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>92</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Nota Débito</SimpleValue>
</Value>
</Row>
</SimpleCodeList>
<?xml version="1.0" encoding="UTF-8"?>
<!-- DIAN Genericode listas de valores: Ultima modificación 03-04-2022 - wcbr-->
<gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/">
<Identification>
<ShortName>TipoDocumento</ShortName>
<LongName xml:lang="es">Tipo de Documento</LongName>
<Version>1</Version>
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoDocumento</CanonicalUri>
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoDocumento-2.1</CanonicalVersionUri>
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TipoDocumento-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>01</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factura electrónica de Venta</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>Tipos de factura</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>02</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factura electrónica de venta con propósito de exportación</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>Tipos de factura</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>03</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factura de talonario o papel con numeración de contingencia.</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>Tipos de factura</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>04</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factura electrónica de Venta por Contingencia DIAN</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>Tipos de factura</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>91</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Nota Crédito</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>Exclusivo en referencias a documentos (elementos DocumentReference)</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>92</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Nota Débito</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>Exclusivo en referencias a documentos (elementos DocumentReference)</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>05</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Documento soporte en adquisiciones efectuadas a sujetos no obligados a expedir factura o documento equivalente</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>Tipo de documento</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>95</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Nota de ajuste al documento soporte en adquisiciones efectuadas a sujetos no obligados a expedir factura o documento equivalente</SimpleValue>
</Value>
<Value ColumnRef="description">
<SimpleValue>Exclusivo en referencias a documentos (elementos DocumentReference)</SimpleValue>
</Value>
</Row>
</SimpleCodeList>
</gc:CodeList>

View File

@@ -1,162 +1,171 @@
<?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>01</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>IVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>02</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>IC</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>03</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ICA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>04</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>INC</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>05</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteIVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>06</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteFuente</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>07</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteICA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>08</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteCREE</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>20</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>FtoHorticultura</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>21</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Timbre</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>22</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Bolsas</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>23</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>INCarbono</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>24</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>INCombustibles</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>25</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Sobretasa Combustibles</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>26</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Sordicom</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>ZZ</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Nombre de la figura tributaria</SimpleValue>
</Value>
</Row>
</SimpleCodeList>
<?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>01</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>IVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>02</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>IC</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>03</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ICA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>04</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>INC</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>05</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteIVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>06</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteRenta</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>07</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteICA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>08</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>ReteCREE</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>20</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>FtoHorticultura</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>21</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Timbre</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>22</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Bolsas</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>23</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>INCarbono</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>24</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>INCombustibles</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>25</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Sobretasa Combustibles</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>26</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Sordicom</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>30</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Impuesto al Consumo de Datos</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>ZZ</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Nombre de la figura tributaria</SimpleValue>
</Value>
</Row>
</SimpleCodeList>
</gc:CodeList>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/">
<Identification>
<ShortName>TipoOperacion</ShortName>
<LongName xml:lang="es">Tipo de operacion</LongName>
<Version>1</Version>
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoOperacion</CanonicalUri>
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoOperacion-2.1</CanonicalVersionUri>
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TipoOperacion-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>
<Data Type="normalizedString"/>
</Column>
<Column Id="name" Use="required">
<ShortName>Nombre</ShortName>
<Data Type="normalizedString"/>
</Column>
<Key Id="codeKey">
<ShortName>CodeKey</ShortName>
<ColumnRef Ref="code"/>
</Key>
</ColumnSet>
<SimpleCodeList>
<Row>
<Value ColumnRef="code">
<SimpleValue>10</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Residente</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>11</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>No Residente</SimpleValue>
</Value>
</Row>
</SimpleCodeList>
</gc:CodeList>

View File

@@ -30,46 +30,6 @@
</Key>
</ColumnSet>
<SimpleCodeList>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-99</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Otro tipo de obligado</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-06</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Ingresos y patrimonio</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-07</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Retención en la fuente a título de renta</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-08</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Retención timbre nacional</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-09</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Retención en la fuente en el impuesto sobre las ventas</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-13</SimpleValue>
@@ -78,14 +38,6 @@
<SimpleValue>Gran contribuyente</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-14</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Informante de exógena</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-15</SimpleValue>
@@ -94,38 +46,6 @@
<SimpleValue>Autorretenedor</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-16</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Obligación de facturar por ingresos de bienes y/o servicios excluidos</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-17</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Profesionales de compra y venta de divisas</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-19</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Productor y/o exportador de bienes exentos</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-22</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Obligado a cumplir deberes formales a nombre de terceros</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-23</SimpleValue>
@@ -134,62 +54,6 @@
<SimpleValue>Agente de retención en el impuesto sobre las ventas</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-32</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Impuesto Nacional a la Gasolina y al ACPM</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-33</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Impuesto Nacional al consumo</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-34</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Régimen simplificado impuesto nacional consumo rest y bares</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-36</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Establecimiento Permanente</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-37</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Obligado a Facturar Electrónicamente Modelo 2242</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-38</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Facturación Electrónica Voluntaria Modelo 2242</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-39</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Proveedor de Servicios Tecnológicos PST Modelo 2242</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-47</SimpleValue>
@@ -214,782 +78,6 @@
<SimpleValue>No responsable de IVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-52</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Facturador electrónico</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-99</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Otro tipo de obligado</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-00-PN</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Clientes del Exterior</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-12-PN</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factor PN</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-16-PN</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Mandatario</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-25-PN</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agente Interventor</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-99-PN</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>No responsable</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-06-PJ</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Apoderado especial</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-07-PJ</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Apoderado general</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-12-PJ</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Factor</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-16-PJ</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Mandatario</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-99-PJ</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Otro tipo de responsable</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-01</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agente de carga internacional</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-02</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agente marítimo</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-03</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Almacén general de depósito</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-04</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Comercializadora internacional (C.I.)</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-05</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Comerciante de la zona aduanera especial de Inírida, Puerto Carreño, Cumaribo y Primavera</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-06</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Comerciantes de la zona de régimen aduanero especial de Leticia</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-07</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Comerciantes de la zona de régimen aduanero especial de Maicao, Uribia y Manaure</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-08</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Comerciantes de la zona de régimen aduanero especial de Urabá, Tumaco y Guapí</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-09</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Comerciantes del puerto libre de San Andrés, Providencia y Santa Catalina</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-10</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito público de apoyo logístico internacional</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-11</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito privado para procesamiento industrial</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-12</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito privado de transformación o ensamble</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-13</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito franco</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-14</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito privado aeronáutico</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-15</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito privado para distribución internacional</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-16</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito privado de provisiones de a bordo para consumo y para llevar</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-17</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito privado para envíos urgentes</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-18</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito privado</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-19</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito público</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-20</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósito público para distribución internacional</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-21</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Exportador de café</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-22</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Exportador</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-23</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Importador</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-24</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Intermediario de tráfico postal y envíos urgentes</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-25</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Operador de transporte multimodal</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-26</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Sociedad de intermediación aduanera</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-27</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Titular de puertos y muelles de servicio público o privado</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-28</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Transportador 263nfor régimen de importación y/o exportación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-29</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Transportista nacional para operaciones del régimen de tránsito aduanero</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-30</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario comercial zona franca</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-32</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario industrial de bienes zona franca</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-34</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario industrial de servicios zona franca</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-36</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario operador de zona franca</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-37</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario aduanero permanente</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-38</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario altamente exportador</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-39</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario de zonas económicas especiales de exportación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-40</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Deposito privado de instalaciones industriales</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-41</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Beneficiarios de programas especiales de exportación PEX</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-42</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Depósitos privados para mercancías en tránsito San Andrés</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-43</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Observadores de las operaciones de importación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-44</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuarios sistemas especiales Importación exportación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-46</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Transportador 263nformac régimen de importación y/o exportación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-47</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Transportador terrestre régimen de importación y/o exportación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-48</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Aeropuerto de servicio publico o privado</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-49</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Transportador fluvial régimen de importación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-50</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario industrial zona franca especial</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-53</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agencias de aduanas 1</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-54</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Usuario Operador Zona Franca Especial</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-55</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agencias de aduanas 2</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-56</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agencias de aduanas 3</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-57</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agencias de aduanas 4</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-58</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Transportador aéreo nacional</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-60</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Transportador aéreo, marítimo o fluvial modalidad Cabotaje</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-61</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Importador de alimentos de consumo humano y animal</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-62</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Importador Ocasional</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-63</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Importador de maquinaría y sus partes Decreto 2261 de 2012</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-64</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Beneficiario Programa de Fomento Industria Automotriz-PROFIA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>A-99</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Otro tipo de agente aduanero</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-01</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agencia</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-02</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Establecimiento de comercio</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-03</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Centro de explotación agrícola</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-04</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Centro de explotación animal</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-05</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Centro de explotación minera</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-06</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Centro de explotación de transformación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-07</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Centro de explotación de servicios</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-08</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Oficina</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-09</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Sede</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-10</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Sucursal</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-11</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Consultorio</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-12</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Administraciones</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-13</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Seccionales</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-14</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Regionales</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-15</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Intendencias</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-16</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Local o negocio</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-17</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Punto de venta</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-18</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Fábrica</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-19</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Taller</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-20</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Cantera</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-21</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Pozo de Petróleo y Gas</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-22</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Otro lug de tipo de extrac explotación de recursos naturales</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>E-99</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Otro tipo de establecimiento</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-13</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Gran contribuyente</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-15</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Autorretenedor</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-23</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Agente de retención IVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-47</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Régimen simple de tributación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-99-PN</SimpleValue>

View File

@@ -61,6 +61,30 @@
<Value ColumnRef="name">
<SimpleValue>Régimen simple de tributación</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-48</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>Impuesto sobre las ventas IVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>O-49</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>No responsable de IVA</SimpleValue>
</Value>
</Row>
<Row>
<Value ColumnRef="code">
<SimpleValue>R-99-PN</SimpleValue>
</Value>
<Value ColumnRef="name">
<SimpleValue>No responsable</SimpleValue>
</Value>
</Row>
</SimpleCodeList>
</gc:CodeList>

View File

@@ -82,11 +82,16 @@ 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')\
.update(CodeList(path_for_codelist('TipoImpuesto-2.1.custom.gc'), 'code', 'name'))
TarifaImpuesto = CodeList(path_for_codelist('TarifaImpuestoINC-2.1.gc'), 'code', 'name')\
.update(CodeList(path_for_codelist('TarifaImpuestoIVA-2.1.gc'), 'code', 'name'))\
.update(CodeList(path_for_codelist('TarifaImpuestoReteIVA-2.1.gc'), 'code', 'name'))\
.update(CodeList(path_for_codelist('TarifaImpuestoReteRenta-2.1.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')
FormasPago = CodeList(path_for_codelist('FormasPago-2.1.gc'), 'code', 'name')
RegimenFiscal = CodeList(path_for_codelist('RegimenFiscal-2.1.custom.gc'), 'code', 'name')
TipoOperacionNC = CodeList(path_for_codelist('TipoOperacionNC-2.1.gc'), 'code', 'name')
TipoOperacionNCDS = CodeList(path_for_codelist('TipoOperacionNCDS-2.1.gc'), 'code', 'name')
TipoOperacionND = CodeList(path_for_codelist('TipoOperacionND-2.1 - copia.gc'), 'code', 'name')
TipoOperacionF = CodeList(path_for_codelist('TipoOperacionF-2.1.gc'), 'code', 'name')\
.update(CodeList(path_for_codelist('TipoOperacionF-2.1.custom.gc'), 'code', 'name'))

View File

@@ -31,27 +31,44 @@ POLICY_ID = 'https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicad
POLICY_NAME = u'Política de firma para facturas electrónicas de la República de Colombia.'
# NAMESPACES = {
# 'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2',
# 'nomina': 'dian:gov:co:facturaelectronica:NominaIndividual',
# 'nominaajuste': 'dian:gov:co:facturaelectronica:NominaIndividualDeAjuste',
# 'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
# 'xs': 'http://www.w3.org/2001/XMLSchema-instance',
# 'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
# 'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
# 'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1',
# 'clm54217': 'urn:un:unece:uncefact:codelist:specification:54217:2001',
# 'clmIANAMIMEMediaType': 'urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003',
# 'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2',
# 'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2',
# 'sts': 'dian:gov:co:facturaelectronica:Structures-2-1',
# 'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2',
# 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
# 'xades': 'http://uri.etsi.org/01903/v1.3.2#',
# 'xades141': 'http://uri.etsi.org/01903/v1.4.1#',
# 'ds': 'http://www.w3.org/2000/09/xmldsig#',
# 'sig': 'http://www.w3.org/2000/09/xmldsig#',
# }
NAMESPACES = {
'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2',
'nomina': 'dian:gov:co:facturaelectronica:NominaIndividual',
'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
'xs': 'http://www.w3.org/2001/XMLSchema-instance',
'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1',
'clm54217': 'urn:un:unece:uncefact:codelist:specification:54217:2001',
'clmIANAMIMEMediaType': 'urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003',
'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2',
'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2',
'sts': 'dian:gov:co:facturaelectronica:Structures-2-1',
'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2',
'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'xades': 'http://uri.etsi.org/01903/v1.3.2#',
'xades141': 'http://uri.etsi.org/01903/v1.4.1#',
'ds': 'http://www.w3.org/2000/09/xmldsig#',
'sig': 'http://www.w3.org/2000/09/xmldsig#',
'xades': 'http://uri.etsi.org/01903/v1.3.2#',
}
def fe_from_string(document: str) -> FachoXML:
return FeXML.from_string(document)
@@ -77,21 +94,28 @@ def mock_xades_policy():
class FeXML(FachoXML):
def __init__(self, root, namespace):
# raise Exception(namespace)
super().__init__("{%s}%s" % (namespace, root),
nsmap=NAMESPACES)
@classmethod
def from_string(cls, document: str) -> 'FeXML':
return super().from_string(document, namespaces=NAMESPACES)
def tostring(self, **kw):
# MACHETE(bit4bit) la DIAN espera que la etiqueta raiz no este en un namespace
root_namespace = self.root_namespace()
root_localname = self.root_localname()
xmlns_name = {v: k for k, v in NAMESPACES.items()}[root_namespace]
if root_localname == 'Invoice':
urn_oasis = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'
if root_localname == 'CreditNote':
urn_oasis = 'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2'
return super().tostring(**kw)\
.replace(xmlns_name + ':', '')\
.replace('xmlns:'+xmlns_name, 'xmlns')
.replace(xmlns_name + ':', '')\
.replace('xmlns:'+xmlns_name, 'xmlns')\
.replace(root_namespace, urn_oasis)
class DianXMLExtensionCUDFE(FachoXMLExtension):
@@ -120,8 +144,19 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
fachoxml.set_element('./cbc:UUID', cufe,
schemeID=self.tipo_ambiente,
schemeName=self.schemeName())
#DIAN 1.8.-2021: FAD03
fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta')
if self.schemeName() == "CUDS-SHA384":
if fachoxml.tag_document() == 'Invoice':
fachoxml.set_element('./cbc:ProfileID',
'DIAN 2.1: documento soporte en adquisiciones efectuadas a no obligados a facturar.')
else:
fachoxml.set_element('./cbc:ProfileID',
'DIAN 2.1: Nota de ajuste al documento soporte en adquisiciones efectuadas a sujetos no obligados a expedir factura o documento equivalente')
else:
fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta')
# #DIAN 1.8.-2021: FAD03
# fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta')
fachoxml.set_element('./cbc:ProfileExecutionID', self._tipo_ambiente_int())
#DIAN 1.7.-2020: FAB36
fachoxml.set_element('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode',
@@ -244,6 +279,39 @@ class DianXMLExtensionCUDE(DianXMLExtensionCUDFE):
'%d' % build_vars['TipoAmb'],
]
class DianXMLExtensionCUDS(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 schemeName(self):
return 'CUDS-SHA384'
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'],
form.Amount(build_vars['ValorBruto']).truncate_as_string(2),
CodImpuesto1,
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0)).truncate_as_string(2),
form.Amount(build_vars['ValorTotalPagar']).truncate_as_string(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

View File

@@ -1,6 +1,5 @@
# This file is part of facho. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import hashlib
from functools import reduce
import copy
@@ -11,7 +10,6 @@ from collections import defaultdict
import decimal
from decimal import Decimal
import typing
from ..data.dian import codelist
DECIMAL_PRECISION = 6
@@ -163,10 +161,10 @@ class Item:
class StandardItem(Item):
def __init__(self, id_: str, description: str = ''):
def __init__(self, id_: str, description: str = '', name: str = ''):
super().__init__(id=id_,
description=description,
scheme_name='',
scheme_name=name,
scheme_id='999',
scheme_agency_id='')
@@ -210,6 +208,10 @@ class City:
raise ValueError("code [%s] not found" % (self.code))
self.name = codelist.Municipio[self.code]['name']
@dataclass
class PostalZone:
code: str = ''
@dataclass
class Address:
name: str
@@ -217,6 +219,7 @@ class Address:
city: City = City('05001')
country: Country = Country('CO')
countrysubentity: CountrySubentity = CountrySubentity('05')
postalzone: PostalZone = PostalZone('')
@dataclass
class PartyIdentification:
@@ -261,7 +264,6 @@ class TaxScheme:
code: str
name: str = ''
def __post_init__(self):
if self.code not in codelist.TipoImpuesto:
raise ValueError("code not found")
@@ -320,7 +322,6 @@ class TaxTotal:
def calculate(self, invline):
self.taxable_amount = invline.total_amount
for subtax in self.subtotals:
subtax.calculate(invline)
self.tax_amount += subtax.tax_amount
@@ -333,6 +334,36 @@ class TaxTotalOmit(TaxTotal):
def calculate(self, invline):
pass
@dataclass
class WithholdingTaxSubTotal:
percent: float
scheme: typing.Optional[TaxScheme] = None
tax_amount: Amount = Amount(0.0)
def calculate(self, invline):
if self.percent is not None:
self.tax_amount = invline.total_amount * Amount(self.percent / 100)
@dataclass
class WithholdingTaxTotal:
subtotals: list
tax_amount: Amount = Amount(0.0)
taxable_amount: Amount = Amount(0.0)
def calculate(self, invline):
self.taxable_amount = invline.total_amount
for subtax in self.subtotals:
subtax.calculate(invline)
self.tax_amount += subtax.tax_amount
class WithholdingTaxTotalOmit(WithholdingTaxTotal):
def __init__(self):
super().__init__([])
def calculate(self, invline):
pass
@dataclass
class Price:
amount: Amount
@@ -368,6 +399,21 @@ class PrePaidPayment:
#DIAN 1.7.-2020: FBD03
paid_amount: Amount = Amount(0.0)
@dataclass
class BillingResponse:
id: str
code: str
description: str
class SupportDocumentCreditNoteResponse(BillingResponse):
"""
ReferenceID: Identifica la sección del Documento
Soporte original a la cual se aplica la corrección.
ResponseCode: Código de descripción de la corrección.
Description: Descripción de la naturaleza de la corrección.
"""
@dataclass
class BillingReference:
@@ -382,7 +428,6 @@ class CreditNoteDocumentReference(BillingReference):
date: fecha de emision de la factura relacionada
"""
class DebitNoteDocumentReference(BillingReference):
"""
ident: Prefijo + Numero de la factura relacionada
@@ -455,7 +500,7 @@ class InvoiceLine:
# la factura y el percent es unico por type_code
# de subtotal
tax: typing.Optional[TaxTotal]
withholding: typing.Optional[WithholdingTaxTotal]
allowance_charge: typing.List[AllowanceCharge] = dataclasses.field(default_factory=list)
def add_allowance_charge(self, charge):
@@ -499,8 +544,17 @@ class InvoiceLine:
def taxable_amount(self):
return self.tax.taxable_amount
@property
def withholding_amount(self):
return self.withholding.tax_amount
@property
def withholding_taxable_amount(self):
return self.withholding.taxable_amount
def calculate(self):
self.tax.calculate(self)
self.withholding.calculate(self)
def __post_init__(self):
if not isinstance(self.quantity, Quantity):
@@ -508,6 +562,9 @@ class InvoiceLine:
if self.tax is None:
self.tax = TaxTotalOmit()
if self.withholding is None:
self.withholding = WithholdingTaxTotalOmit()
@dataclass
class LegalMonetaryTotal:
@@ -544,6 +601,10 @@ class DebitNoteDocumentType(str):
# 6.1.3
return '92'
class CreditNoteSupportDocumentType(str):
def __str__(self):
return '95'
class Invoice:
def __init__(self, type_code: str):
if str(type_code) not in codelist.TipoDocumento:
@@ -563,6 +624,7 @@ class Invoice:
self.invoice_allowance_charge = []
self.invoice_prepaid_payment = []
self.invoice_billing_reference = None
self.invoice_discrepancy_response = None
self.invoice_type_code = str(type_code)
self.invoice_ident_prefix = None
@@ -638,6 +700,10 @@ class Invoice:
def set_billing_reference(self, billing_reference: BillingReference):
self.invoice_billing_reference = billing_reference
def set_discrepancy_response(self, billing_response: BillingResponse):
self.invoice_discrepancy_response = billing_response
def accept(self, visitor):
visitor.visit_payment_mean(self.invoice_payment_mean)
visitor.visit_customer(self.invoice_customer)
@@ -735,3 +801,27 @@ class DebitNote(Invoice):
if not self.invoice_ident_prefix:
self.invoice_ident_prefix = self.invoice_ident[0:6]
class SupportDocument(Invoice):
pass
class SupportDocumentCreditNote(SupportDocument):
def __init__(self, invoice_document_reference: BillingReference,
invoice_discrepancy_response: BillingResponse):
super().__init__(CreditNoteSupportDocumentType())
if not isinstance(invoice_document_reference, BillingReference):
raise TypeError('invoice_document_reference invalid type')
self.invoice_billing_reference = invoice_document_reference
self.invoice_discrepancy_response = invoice_discrepancy_response
def _get_codelist_tipo_operacion(self):
return codelist.TipoOperacionNCDS
def _check_ident_prefix(self, prefix):
if len(prefix) != 6:
raise ValueError('prefix must be 6 length')
def _set_ident_prefix_automatic(self):
if not self.invoice_ident_prefix:
self.invoice_ident_prefix = self.invoice_ident[0:6]
pass

View File

@@ -3,3 +3,5 @@ from .credit_note import *
from .debit_note import *
from .utils import *
from .attached_document import *
from .support_document import *
from .support_document_credit_note import *

View File

@@ -147,7 +147,6 @@ class DIANInvoiceXML(fe.FeXML):
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
invoice.invoice_customer.tax_scheme.code)
#DIAN 1.7.-2020: CAJ41
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
invoice.invoice_customer.tax_scheme.name)
@@ -421,6 +420,7 @@ class DIANInvoiceXML(fe.FeXML):
def set_invoice_totals(fexml, invoice):
tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0)))
withholding_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0)))
percent_for = defaultdict(lambda: None)
#requeridos para CUFE
@@ -433,23 +433,35 @@ class DIANInvoiceXML(fe.FeXML):
#tax_amount_for['03']['taxable_amount'] += 0.0
total_tax_amount = Amount(0.0)
total_withholding_amount = Amount(0.0)
for invoice_line in invoice.invoice_lines:
for subtotal in invoice_line.tax.subtotals:
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
tax_amount_for[subtotal.scheme.code]['name'] = subtotal.scheme.name
# MACHETE ojo InvoiceLine.tax pasar a Invoice
percent_for[subtotal.scheme.code] = subtotal.percent
total_tax_amount += subtotal.tax_amount
for subtotal_withholding in invoice_line.withholding.subtotals:
if subtotal_withholding.scheme is not None:
withholding_amount_for[subtotal_withholding.scheme.code]['tax_amount'] += subtotal_withholding.tax_amount
withholding_amount_for[subtotal_withholding.scheme.code]['taxable_amount'] += invoice_line.withholding_taxable_amount
# MACHETE ojo InvoiceLine.tax pasar a Invoice
percent_for[subtotal_withholding.scheme.code] = subtotal_withholding.percent
total_withholding_amount += subtotal_withholding.tax_amount
if total_tax_amount != Amount(0.0):
fexml.placeholder_for('./cac:TaxTotal')
fexml.set_element_amount('./cac:TaxTotal/cbc:TaxAmount',
total_tax_amount)
for index, item in enumerate(tax_amount_for.items()):
cod_impuesto, amount_of = item
@@ -486,8 +498,45 @@ class DIANInvoiceXML(fe.FeXML):
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
cod_impuesto)
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name',
'IVA')
amount_of['name'])
for index, item in enumerate(withholding_amount_for.items()):
cod_impuesto, amount_of = item
next_append = index > 0
#DIAN 1.7.-2020: FAS01
line = fexml.fragment('./cac:WithholdingTaxTotal', append=next_append)
#DIAN 1.7.-2020: FAU06
tax_amount = amount_of['tax_amount']
fexml.set_element_amount_for(line,
'/cac:WithholdingTaxTotal/cbc:TaxAmount',
tax_amount)
#DIAN 1.7.-2020: FAS05
fexml.set_element_amount_for(line,
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
amount_of['taxable_amount'])
#DIAN 1.7.-2020: FAU06
fexml.set_element_amount_for(line,
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount',
amount_of['tax_amount'])
#DIAN 1.7.-2020: FAS07
if percent_for[cod_impuesto]:
line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:Percent',
percent_for[cod_impuesto])
if percent_for[cod_impuesto]:
line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent',
percent_for[cod_impuesto])
line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
cod_impuesto)
line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name',
'ReteRenta')
# abstract method
def tag_document(fexml):
return 'Invoice'
@@ -515,7 +564,29 @@ class DIANInvoiceXML(fe.FeXML):
#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_line_withholding(fexml, line, invoice_line):
fexml.set_element_amount_for(line,
'./cac:WithholdingTaxTotal/cbc:TaxAmount',
invoice_line.withholding_amount)
#DIAN 1.7.-2020: FAX05
fexml.set_element_amount_for(line,
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
invoice_line.withholding_taxable_amount)
for subtotal in invoice_line.withholding.subtotals:
line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP')
if subtotal.percent is not None:
line.set_element('./cac:WithholdingTaxTotal/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:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code)
line.set_element('./cac:WithholdingTaxTotal/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):
@@ -531,6 +602,9 @@ class DIANInvoiceXML(fe.FeXML):
if not isinstance(invoice_line.tax, TaxTotalOmit):
fexml.set_invoice_line_tax(line, invoice_line)
if not isinstance(invoice_line.withholding, WithholdingTaxTotalOmit):
fexml.set_invoice_line_withholding(line, invoice_line)
line.set_element('./cac:Item/cbc:Description', invoice_line.item.description)
line.set_element('./cac:Item/cac:StandardItemIdentification/cbc:ID',
@@ -578,7 +652,6 @@ class DIANInvoiceXML(fe.FeXML):
fexml.placeholder_for('./cbc:ProfileExecutionID')
fexml.set_element('./cbc:ID', invoice.invoice_ident)
fexml.placeholder_for('./cbc:UUID')
fexml.set_element('./cbc:DocumentCurrencyCode', 'COP')
fexml.set_element('./cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d'))
#DIAN 1.7.-2020: FAD10
fexml.set_element('./cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S-05:00'))
@@ -587,24 +660,25 @@ class DIANInvoiceXML(fe.FeXML):
listAgencyID='195',
listAgencyName='No matching global declaration available for the validation root',
listURI='http://www.dian.gov.co')
fexml.set_element('./cbc:DocumentCurrencyCode', 'COP')
fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines))
fexml.set_element('./cac:%sPeriod/cbc:StartDate' % (fexml.tag_document()),
invoice.invoice_period_start.strftime('%Y-%m-%d'))
fexml.set_element('./cac:%sPeriod/cbc:EndDate' % (fexml.tag_document()),
invoice.invoice_period_end.strftime('%Y-%m-%d'))
if fexml.tag_document() == 'Invoice':
fexml.set_element('./cac:%sPeriod/cbc:StartDate' % (
fexml.tag_document()),
invoice.invoice_period_start.strftime('%Y-%m-%d'))
fexml.set_element('./cac:%sPeriod/cbc:EndDate' % (
fexml.tag_document()),
invoice.invoice_period_end.strftime('%Y-%m-%d'))
fexml.set_billing_reference(invoice)
fexml.customize(invoice)
fexml.set_supplier(invoice)
fexml.set_customer(invoice)
fexml.set_legal_monetary(invoice)
fexml.set_invoice_totals(invoice)
fexml.set_invoice_lines(invoice)
fexml.set_payment_mean(invoice)
fexml.set_invoice_totals(invoice)
fexml.set_legal_monetary(invoice)
fexml.set_invoice_lines(invoice)
fexml.set_allowance_charge(invoice)
fexml.set_billing_reference(invoice)
return fexml
def customize(fexml, invoice):

View File

@@ -0,0 +1,529 @@
from .. import fe
from ..form import *
from datetime import datetime, date
from .attached_document import *
__all__ = ['DIANSupportDocumentXML']
class DIANSupportDocumentXML(fe.FeXML):
"""
DianSupportDocumentXML mapea objeto form.Invoice a XML segun
lo indicado para él Documento soporte en adquisiciones efectuadas con sujetos no obligados a expedir factura de venta o documento equivalente.
"""
def __init__(self, invoice, tag_document = 'Invoice'):
super().__init__(tag_document, 'http://www.dian.gov.co/contratos/facturaelectronica/v1')
#DIAN 1.1.-2021: DSAB03
#DIAN 1.1.-2021: NSAB03
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceControl')
#DIAN 1.1.-2021: DSAB13
#DIAN 1.1.-2021: NSAB13
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource')
#DIAN 1.1.-2021: DSAB18
#DIAN 1.1.-2021: NSAB18
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider')
#DIAN 1.1.-2021: DSAB27
#DIAN 1.1.-2021: NSAB27
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareSecurityCode')
#DIAN 1.1.-2021: DSAB30 DSAB31
#DIAN 1.1.-2021: NSAB30 NSAB31
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider/sts:AuthorizationProviderID')
#ZE02 se requiere existencia para firmar
#DIAN 1.1.-2021: DSAA02 DSAB01
#DIAN 1.1.-2021: NSAA02 NSAB01
ublextension = self.fragment('./ext:UBLExtensions/ext:UBLExtension', append=True)
#DIAN 1.1.-2021: DSAB02
#DIAN 1.1.-2021: NSAB02
extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent')
self.attach_invoice(invoice)
def set_supplier(fexml, invoice):
#DIAN 1.1.-2021: DSAJ01
#DIAN 1.1.-2021: NSAB01
fexml.placeholder_for('./cac:AccountingSupplierParty')
#DIAN 1.1.-2021: DSAJ02
#DIAN 1.1.-2021: NSAJ02
fexml.set_element('./cac:AccountingSupplierParty/cbc:AdditionalAccountID',
invoice.invoice_supplier.organization_code)
#DIAN 1.1.-2021: DSAJ07 DSAJ08
#DIAN 1.1.-2021: NSAJ07 NSAJ08
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address')
#DIAN 1.1.-2021: DSAJ09
#DIAN 1.1.-2021: NSAJ09
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID',
invoice.invoice_supplier.address.city.code)
#DIAN 1.1.-2021: DSAJ10
#DIAN 1.1.-2021: NSAJ10
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName',
invoice.invoice_supplier.address.city.name)
#DIAN 1.1.-2021: DSAJ73
#DIAN 1.1.-2021: NSAJ73
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:PostalZone',
invoice.invoice_supplier.address.postalzone.code)
#DIAN 1.1.-2021: DSAJ11
#DIAN 1.1.-2021: NSAJ11
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity',
invoice.invoice_supplier.address.countrysubentity.name)
#DIAN 1.1.-2021: DSAJ12
#DIAN 1.1.-2021: NSAJ12
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode',
invoice.invoice_supplier.address.countrysubentity.code)
#DIAN 1.1.-2021: NSAJ13 NSAJ14
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line',
invoice.invoice_supplier.address.street)
#DIAN 1.1.-2021: DSAJ15 DSAJ16
#DIAN 1.1.-2021: NSAJ15 NSAJ16
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode',
invoice.invoice_supplier.address.country.code)
#DIAN 1.1.-2021: DSAJ17
#DIAN 1.1.-2021: NSAJ17
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name',
invoice.invoice_supplier.address.country.name,
#DIAN 1.1.-2021: DSAJ18
#DIAN 1.1.-2021: NSAJ18
languageID = 'es')
supplier_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy()
supplier_company_id_attrs.update({'schemeID': invoice.invoice_supplier.ident.dv,
'schemeName': invoice.invoice_supplier.ident.type_fiscal})
#DIAN 1.1.-2021: DSAJ19
#DIAN 1.1.-2021: NSAJ19
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme')
#DIAN 1.1.-2021: DSAJ20
#DIAN 1.1.-2021: NSAJ20
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName',
invoice.invoice_supplier.legal_name)
#DIAN 1.1.-2021: DSAJ21
#DIAN 1.1.-2021: NSAJ21
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID',
invoice.invoice_supplier.ident,
#DIAN 1.1.-2021: DSAJ22 DSAJ23 DSAJ24 DSAJ25
#DIAN 1.1.-2021: NSAJ22 NSAJ23 NSAJ24 NSAJ25
**supplier_company_id_attrs)
#DIAN 1.1.-2021: DSAJ26
#DIAN 1.1.-2021: NSAJ26
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode',
invoice.invoice_supplier.responsability_code,
listName=invoice.invoice_supplier.responsability_regime_code)
#DIAN 1.1.-2021: DSAJ39
#DIAN 1.1.-2021: NSAJ39
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme')
#DIAN 1.1.-2021: DSAJ40
#DIAN 1.1.-2021: NSAJ40
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
invoice.invoice_customer.tax_scheme.code)
#DIAN 1.1.-2021: DSAJ41
#DIAN 1.1.-2021: NSAJ41
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
invoice.invoice_customer.tax_scheme.name)
def set_customer(fexml, invoice):
#DIAN 1.1.-2021: DSAK01
#DIAN 1.1.-2021: NSAK01
fexml.placeholder_for('./cac:AccountingCustomerParty')
#DIAN 1.1.-2021: DSAK02
#DIAN 1.1.-2021: NSAK02
fexml.set_element('./cac:AccountingCustomerParty/cbc:AdditionalAccountID',
invoice.invoice_customer.organization_code)
#DIAN 1.1.-2021: DSAK03
#DIAN 1.1.-2021: NSAK03
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party')
#DIAN 1.1.-2021: DSAK19
#DIAN 1.1.-2021: NSAK19
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme')
#DIAN 1.1.-2021: DSAK20
#DIAN 1.1.-2021: NSAK20
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName',
invoice.invoice_customer.legal_name)
customer_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy()
customer_company_id_attrs.update({'schemeID': invoice.invoice_customer.ident.dv,
'schemeName': invoice.invoice_customer.ident.type_fiscal})
#DIAN 1.1.-2021: DSAK21
#DIAN 1.1.-2021: NSAK21
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID',
invoice.invoice_customer.ident,
#DIAN 1.1.-2021: DSAK22 DSAK23 DSAK24 DSAK25
#DIAN 1.1.-2021: NSAK22 NSAK23 NSAK24 NSAK25
**customer_company_id_attrs)
#DIAN 1.1.-2021: DSAK26
#DIAN 1.1.-2021: NSAK26
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode',
invoice.invoice_customer.responsability_code)
#DIAN 1.1.-2021: DSAK39
#DIAN 1.1.-2021: NSAK39
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme')
#DIAN 1.1.-2021: DSAK40
#DIAN 1.1.-2021: NSAK40
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
invoice.invoice_customer.tax_scheme.code)
#DIAN 1.1.-2021: DSAK41
#DIAN 1.1.-2021: NSAK41
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
invoice.invoice_customer.tax_scheme.name)
def set_payment_mean(fexml, invoice):
payment_mean = invoice.invoice_payment_mean
#DIAN 1.1.-2021: DSAN01 DSAN02
#DIAN 1.1.-2021: NSAN02 NSAN02
fexml.set_element('./cac:PaymentMeans/cbc:ID', payment_mean.id)
#DIAN 1.1.-2021: DSAN03
#DIAN 1.1.-2021: NSAN03
fexml.set_element('./cac:PaymentMeans/cbc:PaymentMeansCode', payment_mean.code)
#DIAN 1.1.-2021: DSAN04
#DIAN 1.1.-2021: NSAN04
fexml.set_element('./cac:PaymentMeans/cbc:PaymentDueDate', payment_mean.due_at.strftime('%Y-%m-%d'))
#DIAN 1.1.-2021: DSAN05
#DIAN 1.1.-2021: NSAN05
fexml.set_element('./cac:PaymentMeans/cbc:PaymentID', payment_mean.payment_id)
def set_element_amount_for(fexml, xml, xpath, amount):
if not isinstance(amount, Amount):
raise TypeError("amount not is Amount")
xml.set_element(xpath, amount, currencyID=amount.currency.code)
def set_element_amount(fexml, xpath, amount):
if not isinstance(amount, Amount):
raise TypeError("amount not is Amount")
fexml.set_element(xpath, amount, currencyID=amount.currency.code)
def set_legal_monetary(fexml, invoice):
#DIAN 1.1.-2021: DSAU01 DSAU02 DSAU03
#DIAN 1.1.-2021: NSAU01 NSAU02 NSAU03
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:LineExtensionAmount',
invoice.invoice_legal_monetary_total.line_extension_amount)
#DIAN 1.1.-2021: DSAU04 DSAU05
#DIAN 1.1.-2021: NSAU04 NSAU05
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount',
invoice.invoice_legal_monetary_total.tax_exclusive_amount)
#DIAN 1.1.-2021: DSAU06 DSAU07
#DIAN 1.1.-2021: NSAU06 DSAU07
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount',
invoice.invoice_legal_monetary_total.tax_inclusive_amount)
#DIAN 1.1.-2021: DSAU10 DSAU11
#DIAN 1.1.-2021: NSAU10 DSAU11
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:ChargeTotalAmount',
invoice.invoice_legal_monetary_total.charge_total_amount)
#DIAN 1.1.-2021: DSAU14 DSAU15
#DIAN 1.1.-2021: NSAU14 DSAU15
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:PayableAmount',
invoice.invoice_legal_monetary_total.payable_amount)
def _set_invoice_document_reference(fexml, reference):
fexml._do_set_billing_reference(reference, 'cac:InvoiceDocumentReference')
def _set_credit_note_document_reference(fexml, reference):
fexml._do_set_billing_reference(reference, 'cac:CreditNoteDocumentReference')
def _set_debit_note_document_reference(fexml, reference):
fexml._do_set_billing_reference(reference, 'cac:DebitNoteDocumentReference')
def _do_set_billing_reference(fexml, reference, tag_document):
if tag_document == 'Invoice':
schemeName = 'CUFE-SHA384'
else:
schemeName = 'CUDS-SHA384'
fexml.set_element('./cac:BillingReference/%s/cbc:ID' %(tag_document),
reference.ident)
fexml.set_element('./cac:BillingReference/cac:InvoiceDocumentReference/cbc:UUID',
reference.uuid,
schemeName=schemeName)
fexml.set_element('./cac:BillingReference/cac:InvoiceDocumentReference/cbc:IssueDate',
reference.date.strftime("%Y-%m-%d"))
def set_billing_reference(fexml, invoice):
reference = invoice.invoice_billing_reference
if reference is None:
return
if isinstance(reference, DebitNoteDocumentReference):
return fexml._set_debit_note_document_reference(reference)
if isinstance(reference, CreditNoteDocumentReference):
return fexml._set_credit_note_document_reference(reference)
if isinstance(reference, InvoiceDocumentReference):
return fexml._set_invoice_document_reference(reference)
def set_discrepancy_response(fexml, invoice):
reference = invoice.invoice_discrepancy_response
if reference is None:
return
if isinstance(reference, DebitNoteDocumentReference):
return fexml._set_debit_note_document_reference(reference)
if isinstance(reference, CreditNoteDocumentReference):
return fexml._set_credit_note_document_reference(reference)
if isinstance(reference, InvoiceDocumentReference):
return fexml._set_invoice_document_reference(reference)
fexml.set_element('./cac:DiscrepancyResponse/cbc:ReferenceID',
reference.id)
fexml.set_element('./cac:DiscrepancyResponse/cbc:ResponseCode',
reference.code)
fexml.set_element('./cac:DiscrepancyResponse/cbc:Description',
reference.description)
def set_invoice_totals(fexml, invoice):
tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0)))
percent_for = defaultdict(lambda: None)
total_tax_amount = Amount(0.0)
for invoice_line in invoice.invoice_lines:
for subtotal in invoice_line.tax.subtotals:
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
if total_tax_amount != Amount(0.0):
fexml.placeholder_for('./cac:TaxTotal')
fexml.set_element_amount('./cac:TaxTotal/cbc:TaxAmount',
total_tax_amount)
for index, item in enumerate(tax_amount_for.items()):
cod_impuesto, amount_of = item
next_append = index > 0
#DIAN 1.7.-2020: FAS01
line = fexml.fragment('./cac:TaxTotal', append=next_append)
#DIAN 1.7.-2020: FAU06
tax_amount = amount_of['tax_amount']
fexml.set_element_amount_for(line,
'/cac:TaxTotal/cbc:TaxAmount',
tax_amount)
#DIAN 1.7.-2020: FAS05
fexml.set_element_amount_for(line,
'/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
amount_of['taxable_amount'])
#DIAN 1.7.-2020: FAU06
fexml.set_element_amount_for(line,
'/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount',
amount_of['tax_amount'])
#DIAN 1.7.-2020: FAS07
if percent_for[cod_impuesto]:
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cbc:Percent',
percent_for[cod_impuesto])
if percent_for[cod_impuesto]:
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent',
percent_for[cod_impuesto])
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
cod_impuesto)
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name',
'IVA')
# abstract method
def tag_document(fexml):
return 'Invoice'
# abstract method
def tag_document_concilied(fexml):
return 'Invoiced'
def set_invoice_line_withholding(fexml, line, invoice_line):
fexml.set_element_amount_for(line,
'./cac:WithholdingTaxTotal/cbc:TaxAmount',
invoice_line.withholding_amount)
#DIAN 1.7.-2020: FAX05
fexml.set_element_amount_for(line,
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
invoice_line.withholding_taxable_amount)
for subtotal in invoice_line.withholding.subtotals:
line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP')
if subtotal.percent is not None:
line.set_element('./cac:WithholdingTaxTotal/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:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code)
line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name)
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):
line = fexml.fragment('./cac:%sLine' % (fexml.tag_document()), append=next_append)
next_append = True
line.set_element('./cbc:ID', index + 1)
line.set_element('./cbc:%sQuantity' % (fexml.tag_document_concilied()), invoice_line.quantity, unitCode = 'NAR')
fexml.set_element_amount_for(line,
'./cbc:LineExtensionAmount',
invoice_line.total_amount)
period = line.fragment('./cac:InvoicePeriod')
period.set_element('./cbc:StartDate',
datetime.now().strftime('%Y-%m-%d'))
period.set_element('./cbc:DescriptionCode',
'1')
period.set_element('./cbc:Description',
'Por operación')
if not isinstance(invoice_line.tax, TaxTotalOmit):
fexml.set_invoice_line_tax(line, invoice_line)
if not isinstance(invoice_line.withholding, WithholdingTaxTotalOmit):
fexml.set_invoice_line_withholding(line, invoice_line)
line.set_element('./cac:Item/cbc:Description', invoice_line.item.description)
line.set_element('./cac:Item/cac:StandardItemIdentification/cbc:ID',
invoice_line.item.id,
schemeID=invoice_line.item.scheme_id,
schemeName=invoice_line.item.scheme_name,
schemeAgencyID=invoice_line.item.scheme_agency_id)
line.set_element('./cac:Price/cbc:PriceAmount', invoice_line.price.amount, currencyID=invoice_line.price.amount.currency.code)
#DIAN 1.7.-2020: FBB04
line.set_element('./cac:Price/cbc:BaseQuantity',
invoice_line.quantity,
unitCode=invoice_line.quantity.code)
for idx, charge in enumerate(invoice_line.allowance_charge):
next_append_charge = idx > 0
fexml.append_allowance_charge(line, index + 1, charge, append=next_append_charge)
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 = parent.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)
line.set_element('./cbc:MultiplierFactorNumeric', str(round(charge.multiplier_factor_numeric, 2)))
fexml.set_element_amount_for(line, './cbc:Amount', charge.amount)
fexml.set_element_amount_for(line, './cbc:BaseAmount', charge.base_amount)
def attach_invoice(fexml, invoice):
"""adiciona etiquetas a FEXML y retorna FEXML
en caso de fallar validacion retorna None"""
fexml.placeholder_for('./ext:UBLExtensions')
fexml.set_element('./cbc:UBLVersionID', 'UBL 2.1')
fexml.set_element('./cbc:CustomizationID', invoice.invoice_operation_type)
fexml.placeholder_for('./cbc:ProfileID')
fexml.placeholder_for('./cbc:ProfileExecutionID')
fexml.set_element('./cbc:ID', invoice.invoice_ident)
fexml.placeholder_for('./cbc:UUID')
fexml.set_element('./cbc:DocumentCurrencyCode', 'COP')
fexml.set_element('./cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d'))
#DIAN 1.7.-2020: FAD10
fexml.set_element('./cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S-05:00'))
fexml.set_element('./cbc:%sTypeCode' % (fexml.tag_document()),
invoice.invoice_type_code,
listAgencyID='195',
listAgencyName='No matching global declaration available for the validation root',
listURI='http://www.dian.gov.co')
fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines))
fexml.set_element('./cac:%sPeriod/cbc:StartDate' % (fexml.tag_document()),
invoice.invoice_period_start.strftime('%Y-%m-%d'))
fexml.set_element('./cac:%sPeriod/cbc:EndDate' % (fexml.tag_document()),
invoice.invoice_period_end.strftime('%Y-%m-%d'))
fexml.customize(invoice)
fexml.set_supplier(invoice)
fexml.set_customer(invoice)
fexml.set_legal_monetary(invoice)
fexml.set_invoice_totals(invoice)
fexml.set_invoice_lines(invoice)
fexml.set_payment_mean(invoice)
fexml.set_allowance_charge(invoice)
fexml.set_discrepancy_response(invoice)
fexml.set_billing_reference(invoice)
return fexml
def customize(fexml, invoice):
"""adiciona etiquetas a FEXML y retorna FEXML
en caso de fallar validacion retorna None"""

View File

@@ -0,0 +1,21 @@
from .. import fe
from ..form import *
from .support_document import DIANSupportDocumentXML
__all__ = ['DIANSupportDocumentCreditNoteXML']
class DIANSupportDocumentCreditNoteXML(DIANSupportDocumentXML):
"""
DianInvoiceXML mapea objeto form.Invoice a XML segun
lo indicado para la facturacion electronica.
"""
def __init__(self, invoice):
super(DIANSupportDocumentCreditNoteXML, self).__init__(invoice, 'CreditNote')
def tag_document(fexml):
return 'CreditNote'
def tag_document_concilied(fexml):
return 'Credited'

View File

@@ -144,13 +144,12 @@ class Proveedor:
ambiente = fexml.get_element_attribute(scopexml.xpath_from_root('/InformacionGeneral'), 'Ambiente')
codigo_qr = f"https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey={cune}"
if InformacionGeneral.AMBIENTE_PRUEBAS.same(ambiente):
if InformacionGeneral.AMBIENTE_PRUEBAS == ambiente:
codigo_qr = f"https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey={cune}"
elif ambiente is None:
raise RuntimeError('fail to get InformacionGeneral/@Ambiente')
scopexml.set_element('./CodigoQR', codigo_qr)
scopexml.set_element('./Novedad', "false")
# NIE020
software_code = self._software_security_code(fexml, scopexml)
@@ -183,14 +182,16 @@ class Metadata:
proveedor: Proveedor
def apply(self, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml):
self.novedad.apply(novedad)
if novedad:
self.novedad.apply(novedad)
self.secuencia.apply(numero_secuencia_xml)
self.lugar_generacion.apply(lugar_generacion_xml, './LugarGeneracionXML')
self.proveedor.apply(proveedor_xml)
def post_apply(self, fexml, scopexml, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml):
self.proveedor.post_apply(fexml, scopexml, proveedor_xml)
self.novedad.post_apply(fexml, scopexml, proveedor_xml)
if novedad:
self.novedad.post_apply(fexml, scopexml, proveedor_xml)
@dataclass
class PeriodoNomina:
@@ -218,9 +219,8 @@ class InformacionGeneral:
class TIPO_AMBIENTE:
valor: str
@classmethod
def same(cls, value):
return cls.valor == str(value)
def __eq__(self, other):
return self.valor == str(other)
# TABLA 5.1.1
@dataclass
@@ -234,6 +234,28 @@ class InformacionGeneral:
class AMBIENTE_PRUEBAS(TIPO_AMBIENTE):
valor: str = '2'
def __str__(self):
self.valor
# TABLA 5.5.7
@dataclass
class TIPO_XML:
valor: str
def __eq__(self, other):
return self.valor == str(other)
@dataclass
class TIPO_XML_NORMAL(TIPO_XML):
valor: str = '102'
def __str__(self):
self.valor
@dataclass
class TIPO_XML_AJUSTES(TIPO_XML):
valor: str = '103'
def __str__(self):
self.valor
@@ -242,6 +264,7 @@ class InformacionGeneral:
periodo_nomina: PeriodoNomina
tipo_moneda: TipoMoneda
tipo_ambiente: TIPO_AMBIENTE
tipo_xml: TIPO_XML
software_pin: str
def __post_init__(self):
@@ -256,7 +279,7 @@ class InformacionGeneral:
# NIE202
# TABLA 5.5.2
# TODO(bit4bit) solo NominaIndividual
TipoXML = '102',
TipoXML = self.tipo_xml.valor,
# NIE024
CUNE = None,
# NIE025
@@ -315,14 +338,18 @@ class DianXMLExtensionSigner(fe.DianXMLExtensionSigner):
class DIANNominaXML:
def __init__(self, tag_document, xpath_ajuste=None,schemaLocation=None):
def __init__(self, tag_document, xpath_ajuste=None, schemaLocation=None, namespace_ajuste=None):
self.informacion_general_version = None
self.tag_document = tag_document
self.fexml = fe.FeXML(tag_document, 'dian:gov:co:facturaelectronica:NominaIndividual')
if schemaLocation is not None:
self.fexml.root.set("SchemaLocation", schemaLocation)
if namespace_ajuste:
self.fexml = fe.FeXML(tag_document, namespace_ajuste)
else:
self.fexml = fe.FeXML(tag_document, 'dian:gov:co:facturaelectronica:NominaIndividual')
self.fexml.root.set("SchemaLocation", "")
self.fexml.root.set("schemaLocation", schemaLocation)
# layout, la dian requiere que los elementos
# esten ordenados segun el anexo tecnico
@@ -334,7 +361,8 @@ class DIANNominaXML:
self.root_fragment = self.fexml.fragment(xpath_ajuste)
self.root_fragment.placeholder_for('./ReemplazandoPredecesor', optional=True)
self.root_fragment.placeholder_for('./EliminandoPredecesor', optional=True)
self.root_fragment.placeholder_for('./Novedad', optional=False)
if not namespace_ajuste:
self.root_fragment.placeholder_for('./Novedad', optional=False)
self.root_fragment.placeholder_for('./Periodo')
self.root_fragment.placeholder_for('./NumeroSecuenciaXML')
self.root_fragment.placeholder_for('./LugarGeneracionXML')
@@ -347,8 +375,10 @@ class DIANNominaXML:
self.root_fragment.placeholder_for('./FechasPagos')
self.root_fragment.placeholder_for('./Devengados/Basico')
self.root_fragment.placeholder_for('./Devengados/Transporte', optional=True)
self.novedad = self.root_fragment.fragment('./Novedad')
if not namespace_ajuste:
self.novedad = self.root_fragment.fragment('./Novedad')
else:
self.novedad = None
self.informacion_general_xml = self.root_fragment.fragment('./InformacionGeneral')
self.periodo_xml = self.root_fragment.fragment('./Periodo')
self.fecha_pagos_xml = self.root_fragment.fragment('./FechasPagos')
@@ -368,6 +398,7 @@ class DIANNominaXML:
if not isinstance(metadata, Metadata):
raise ValueError('se espera tipo Metadata')
self.metadata = metadata
self.metadata.apply(self.novedad, self.numero_secuencia_xml, self.lugar_generacion_xml, self.proveedor_xml)
def asignar_informacion_general(self, general):
@@ -545,7 +576,7 @@ class DIANNominaXML:
class DIANNominaIndividual(DIANNominaXML):
def __init__(self):
schema = "dian:gov:co:facturaelectronica:NominaIndividual"
schema = "dian:gov:co:facturaelectronica:NominaIndividual NominaIndividualElectronicaXSD.xsd"
super().__init__('NominaIndividual', schemaLocation=schema)
self.informacion_general_version = 'V1.0: Documento Soporte de Pago de Nómina Electrónica'
@@ -561,6 +592,8 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
fecha_generacion: str
def apply(self, fragment):
# NIAE214
fragment.set_element('./TipoNota', '1')
fragment.set_element('./Reemplazar/ReemplazandoPredecesor', None,
# NIAE090
NumeroPred = self.numero,
@@ -571,9 +604,11 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
)
def __init__(self):
super().__init__('NominaIndividualDeAjuste', './Reemplazar')
# NIAE214
self.root_fragment.set_element('./TipoNota', '1')
schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
super().__init__('NominaIndividualDeAjuste', './Reemplazar', schemaLocation=schema, namespace_ajuste='dian:gov:co:facturaelectronica:NominaIndividualDeAjuste')
self.informacion_general_version = 'V1.0: Nota de Ajuste de Documento Soporte de Pago de Nómina Electrónica'
def asignar_predecesor(self, predecesor):
if not isinstance(predecesor, self.Predecesor):
@@ -590,6 +625,7 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
fecha_generacion: str
def apply(self, fragment):
fragment.set_element('./TipoNota', '2')
fragment.set_element('./Eliminar/EliminandoPredecesor', None,
# NIAE090
NumeroPred = self.numero,
@@ -600,9 +636,9 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
)
def __init__(self):
super().__init__('NominaIndividualDeAjuste', './Eliminar')
schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
super().__init__('NominaIndividualDeAjuste', './Eliminar', schemaLocation=schema, namespace_ajuste='dian:gov:co:facturaelectronica:NominaIndividualDeAjuste')
self.root_fragment.set_element('./TipoNota', '2')
self.informacion_general_version = "V1.0: Nota de Ajuste de Documento Soporte de Pago de Nómina Electrónica"
def asignar_predecesor(self, predecesor):

View File

@@ -156,6 +156,7 @@ def test_nomina_xml():
hora_generacion = '1053:10-05:00',
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRODUCCION,
software_pin = '693',
tipo_xml = fe.nomina.InformacionGeneral.TIPO_XML_NORMAL,
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
))
@@ -214,6 +215,7 @@ def test_nomina_xml():
xml = nomina.toFachoXML()
expected_cune = 'b8f9b6c24de07ffd92ea5467433a3b69357cfaffa7c19722db94b2e0eca41d057085a54f484b5da15ff585e773b0b0ab'
assert xml.get_element_attribute('/nomina:NominaIndividual/InformacionGeneral', 'CUNE') == expected_cune
assert xml.get_element_attribute('/nomina:NominaIndividual/InformacionGeneral', 'TipoXML') == '102'
assert xml.get_element_text_or_attribute('/nomina:NominaIndividual/NumeroSecuenciaXML/@Numero') == 'N00001'
assert xml.get_element_text_or_attribute('/nomina:NominaIndividual/NumeroSecuenciaXML/@Consecutivo') == '00001'
assert xml.get_element_text_or_attribute('/nomina:NominaIndividual/LugarGeneracionXML/@Pais') == 'CO'
@@ -251,143 +253,6 @@ def test_nomina_xmlsign(monkeypatch):
assert elem is not None
def atest_nomina_ajuste_reemplazar():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
xml = nomina.toFachoXML()
print(xml)
assert False
def test_adicionar_reemplazar_devengado_comprobante_total():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
dias_trabajados = 60,
sueldo_trabajado = fe.nomina.Amount(2_000_000)
))
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
porcentaje = fe.nomina.Amount(19),
deduccion = fe.nomina.Amount(1_000_000)
))
xml = nomina.toFachoXML()
assert xml.get_element_text('/nomina:NominaIndividualDeAjuste/Reemplazar/ComprobanteTotal') == '1000000.00'
def test_adicionar_reemplazar_asignar_predecesor():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar.Predecesor(
numero = '123456',
cune = 'ABC123456',
fecha_generacion = '2021-11-16'
))
xml = nomina.toFachoXML()
print(xml.tostring())
assert xml.get_element_text_or_attribute('/nomina:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor/@NumeroPred') == '123456'
assert xml.get_element_text_or_attribute('/nomina:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor/@CUNEPred') == 'ABC123456'
assert xml.get_element_text_or_attribute('/nomina:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor/@FechaGenPred') == '2021-11-16'
def test_adicionar_reemplazar_eliminar_predecesor_opcional():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar.Predecesor(
numero = '123456',
cune = 'ABC123456',
fecha_generacion = '2021-11-16'
))
xml = nomina.toFachoXML()
print(xml.tostring())
assert xml.get_element('/nomina:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor') is not None
assert xml.get_element('/nomina:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor') is None
def test_adicionar_eliminar_reemplazar_predecesor_opcional():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Eliminar.Predecesor(
numero = '123456',
cune = 'ABC123456',
fecha_generacion = '2021-11-16'
))
xml = nomina.toFachoXML()
print(xml.tostring())
assert xml.get_element('/nomina:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor') is not None
assert xml.get_element('/nomina:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor') is None
def test_adicionar_eliminar_devengado_comprobante_total():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
dias_trabajados = 60,
sueldo_trabajado = fe.nomina.Amount(2_000_000)
))
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
porcentaje = fe.nomina.Amount(19),
deduccion = fe.nomina.Amount(1_000_000)
))
xml = nomina.toFachoXML()
assert xml.get_element_text('/nomina:NominaIndividualDeAjuste/Eliminar/ComprobanteTotal') == '1000000.00'
def test_adicionar_eliminar_asignar_predecesor():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Eliminar.Predecesor(
numero = '123456',
cune = 'ABC123456',
fecha_generacion = '2021-11-16'
))
xml = nomina.toFachoXML()
print(xml.tostring())
assert xml.get_element_text_or_attribute('/nomina:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor/@NumeroPred') == '123456'
assert xml.get_element_text_or_attribute('/nomina:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor/@CUNEPred') == 'ABC123456'
assert xml.get_element_text_or_attribute('/nomina:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor/@FechaGenPred') == '2021-11-16'
def test_nomina_devengado_horas_extras_diarias():
nomina = fe.nomina.DIANNominaIndividual()
nomina.adicionar_devengado(fe.nomina.DevengadoHorasExtrasDiarias(
horas_extras=[
fe.nomina.DevengadoHoraExtra(
hora_inicio='2021-11-30T19:09:55',
hora_fin='2021-11-30T20:09:55',
cantidad=1,
porcentaje=fe.nomina.Amount(1),
pago=fe.nomina.Amount(100)
),
fe.nomina.DevengadoHoraExtra(
hora_inicio='2021-11-30T18:09:55',
hora_fin='2021-11-30T19:09:55',
cantidad=2,
porcentaje=fe.nomina.Amount(2),
pago=fe.nomina.Amount(200)
)
]
))
xml = nomina.toFachoXML()
extras = xml.get_element('/nomina:NominaIndividual/Devengados/HEDs/HED', multiple=True)
assert extras[0].get('HoraInicio') == '2021-11-30T19:09:55'
assert extras[0].get('HoraFin') == '2021-11-30T20:09:55'
assert extras[0].get('Cantidad') == '1'
assert extras[0].get('Porcentaje') == '1.00'
assert extras[0].get('Pago') == '100.00'
assert extras[1].get('HoraInicio') == '2021-11-30T18:09:55'
assert extras[1].get('HoraFin') == '2021-11-30T19:09:55'
assert extras[1].get('Cantidad') == '2'
assert extras[1].get('Porcentaje') == '2.00'
assert extras[1].get('Pago') == '200.00'
def test_nomina_devengado_horas_extras_nocturnas():
nomina = fe.nomina.DIANNominaIndividual()

235
tests/test_nomina_ajuste.py Normal file
View File

@@ -0,0 +1,235 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of facho. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
"""Tests for `facho` package."""
import re
import pytest
from facho import fe
import helpers
def atest_nomina_ajuste_reemplazar():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
xml = nomina.toFachoXML()
print(xml)
assert False
def test_nomina_ajuste_reemplazar_asignacion_tipo_xml():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
nomina.asignar_metadata(fe.nomina.Metadata(
novedad=fe.nomina.Novedad(
activa = True,
cune = "N0111"
),
secuencia=fe.nomina.NumeroSecuencia(
prefijo = 'N',
consecutivo='00001'
),
lugar_generacion=fe.nomina.Lugar(
pais = fe.nomina.Pais(
code = 'CO'
),
departamento = fe.nomina.Departamento(
code = '05'
),
municipio = fe.nomina.Municipio(
code = '05001'
),
),
proveedor=fe.nomina.Proveedor(
nit='999999',
dv=2,
software_id='xx',
software_pin='12',
razon_social='facho'
)
))
nomina.asignar_empleador(fe.nomina.Empleador(
razon_social='facho',
nit = '700085371',
dv = '1',
pais = fe.nomina.Pais(
code = 'CO'
),
departamento = fe.nomina.Departamento(
code = '05'
),
municipio = fe.nomina.Municipio(
code = '05001'
),
direccion = 'calle etrivial'
))
nomina.asignar_trabajador(fe.nomina.Trabajador(
tipo_contrato = fe.nomina.TipoContrato(
code = '1'
),
alto_riesgo = False,
tipo_documento = fe.nomina.TipoDocumento(
code = '11'
),
primer_apellido = 'gnu',
segundo_apellido = 'emacs',
primer_nombre = 'facho',
lugar_trabajo = fe.nomina.LugarTrabajo(
pais = fe.nomina.Pais(code='CO'),
departamento = fe.nomina.Departamento(code='05'),
municipio = fe.nomina.Municipio(code='05001'),
direccion = 'calle facho'
),
numero_documento = '800199436',
tipo = fe.nomina.TipoTrabajador(
code = '01'
),
salario_integral = True,
sueldo = fe.nomina.Amount(1_500_000)
))
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
fecha_generacion = '2020-01-16',
hora_generacion = '1053:10-05:00',
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRODUCCION,
software_pin = '693',
tipo_xml = fe.nomina.InformacionGeneral.TIPO_XML_AJUSTES,
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
))
xml = nomina.toFachoXML()
assert xml.get_element_attribute('/nominaajuste:NominaIndividualDeAjuste/Reemplazar/InformacionGeneral', 'TipoXML') == '103'
def test_adicionar_reemplazar_devengado_comprobante_total():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
dias_trabajados = 60,
sueldo_trabajado = fe.nomina.Amount(2_000_000)
))
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
porcentaje = fe.nomina.Amount(19),
deduccion = fe.nomina.Amount(1_000_000)
))
xml = nomina.toFachoXML()
assert xml.get_element_text('/nominaajuste:NominaIndividualDeAjuste/Reemplazar/ComprobanteTotal') == '1000000.00'
def test_adicionar_reemplazar_asignar_predecesor():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar.Predecesor(
numero = '123456',
cune = 'ABC123456',
fecha_generacion = '2021-11-16'
))
xml = nomina.toFachoXML()
print(xml.tostring())
assert xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor/@NumeroPred') == '123456'
assert xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor/@CUNEPred') == 'ABC123456'
assert xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor/@FechaGenPred') == '2021-11-16'
def test_adicionar_reemplazar_eliminar_predecesor_opcional():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar.Predecesor(
numero = '123456',
cune = 'ABC123456',
fecha_generacion = '2021-11-16'
))
xml = nomina.toFachoXML()
print(xml.tostring())
assert xml.get_element('/nominaajuste:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor') is not None
assert xml.get_element('/nominaajuste:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor') is None
def test_adicionar_eliminar_reemplazar_predecesor_opcional():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Eliminar.Predecesor(
numero = '123456',
cune = 'ABC123456',
fecha_generacion = '2021-11-16'
))
xml = nomina.toFachoXML()
print(xml.tostring())
assert xml.get_element('/nominaajuste:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor') is not None
assert xml.get_element('/nominaajuste:NominaIndividualDeAjuste/Reemplazar/ReemplazandoPredecesor') is None
def test_adicionar_eliminar_devengado_comprobante_total():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
dias_trabajados = 60,
sueldo_trabajado = fe.nomina.Amount(2_000_000)
))
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
porcentaje = fe.nomina.Amount(19),
deduccion = fe.nomina.Amount(1_000_000)
))
xml = nomina.toFachoXML()
assert xml.get_element_text('/nominaajuste:NominaIndividualDeAjuste/Eliminar/ComprobanteTotal') == '1000000.00'
def test_adicionar_eliminar_asignar_predecesor():
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Eliminar.Predecesor(
numero = '123456',
cune = 'ABC123456',
fecha_generacion = '2021-11-16'
))
xml = nomina.toFachoXML()
print(xml.tostring())
assert xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor/@NumeroPred') == '123456'
assert xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor/@CUNEPred') == 'ABC123456'
assert xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/Eliminar/EliminandoPredecesor/@FechaGenPred') == '2021-11-16'
def test_nomina_devengado_horas_extras_diarias():
nomina = fe.nomina.DIANNominaIndividual()
nomina.adicionar_devengado(fe.nomina.DevengadoHorasExtrasDiarias(
horas_extras=[
fe.nomina.DevengadoHoraExtra(
hora_inicio='2021-11-30T19:09:55',
hora_fin='2021-11-30T20:09:55',
cantidad=1,
porcentaje=fe.nomina.Amount(1),
pago=fe.nomina.Amount(100)
),
fe.nomina.DevengadoHoraExtra(
hora_inicio='2021-11-30T18:09:55',
hora_fin='2021-11-30T19:09:55',
cantidad=2,
porcentaje=fe.nomina.Amount(2),
pago=fe.nomina.Amount(200)
)
]
))
xml = nomina.toFachoXML()
extras = xml.get_element('/nomina:NominaIndividual/Devengados/HEDs/HED', multiple=True)
assert extras[0].get('HoraInicio') == '2021-11-30T19:09:55'
assert extras[0].get('HoraFin') == '2021-11-30T20:09:55'
assert extras[0].get('Cantidad') == '1'
assert extras[0].get('Porcentaje') == '1.00'
assert extras[0].get('Pago') == '100.00'
assert extras[1].get('HoraInicio') == '2021-11-30T18:09:55'
assert extras[1].get('HoraFin') == '2021-11-30T19:09:55'
assert extras[1].get('Cantidad') == '2'
assert extras[1].get('Porcentaje') == '2.00'
assert extras[1].get('Pago') == '200.00'