Compare commits
15 Commits
feature/py
...
Habilitaci
| Author | SHA1 | Date | |
|---|---|---|---|
| f97b3d8317 | |||
| e539f1e0a7 | |||
| 7972a3f59c | |||
| 20d8f4284f | |||
| c49e67b8a6 | |||
| 7672ae4b7f | |||
| 25c5fda3f0 | |||
| a758b8678b | |||
| 3a385c63e3 | |||
| 9b33b4486c | |||
| 612aae1f86 | |||
| 4fe82daac6 | |||
| e237d1b45f | |||
| 8cc6146be2 | |||
|
|
c919d8e36c |
@@ -69,7 +69,7 @@ Ready to contribute? Here's how to set up `facho` for local development.
|
|||||||
$ python3 -mvenv facho-venv && source facho-venv/bin/activate
|
$ python3 -mvenv facho-venv && source facho-venv/bin/activate
|
||||||
$ cd facho/
|
$ cd facho/
|
||||||
$ pre-commit install
|
$ pre-commit install
|
||||||
$ pip install -e .
|
$ python setup.py develop
|
||||||
|
|
||||||
4. Create a branch for local development::
|
4. Create a branch for local development::
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ Ready to contribute? Here's how to set up `facho` for local development.
|
|||||||
tests, including testing other Python versions with tox::
|
tests, including testing other Python versions with tox::
|
||||||
|
|
||||||
$ flake8 facho tests
|
$ flake8 facho tests
|
||||||
$ py.test
|
$ python setup.py test or py.test
|
||||||
$ tox
|
$ tox
|
||||||
|
|
||||||
To get flake8 and tox, just pip install them into your virtualenv.
|
To get flake8 and tox, just pip install them into your virtualenv.
|
||||||
@@ -94,14 +94,6 @@ Ready to contribute? Here's how to set up `facho` for local development.
|
|||||||
|
|
||||||
7. Submit a pull request through the GitHub website.
|
7. Submit a pull request through the GitHub website.
|
||||||
|
|
||||||
Using docker
|
|
||||||
------------
|
|
||||||
|
|
||||||
1. make -f Makefile.dev dev-setup
|
|
||||||
2. make -f Makefile.dev dev-shell
|
|
||||||
3. make -f Makefile.dev test
|
|
||||||
4. make -f Makefile.dev tox
|
|
||||||
|
|
||||||
Pull Request Guidelines
|
Pull Request Guidelines
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
|||||||
52
Dockerfile
52
Dockerfile
@@ -1,51 +1,31 @@
|
|||||||
# DERIVADO DE https://alextereshenkov.github.io/run-python-tests-with-tox-in-docker.html
|
# DERIVADO DE https://alextereshenkov.github.io/run-python-tests-with-tox-in-docker.html
|
||||||
FROM ubuntu:24.04
|
FROM ubuntu:18.04
|
||||||
|
|
||||||
RUN apt-get -qq update
|
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 \
|
RUN apt-get install -y --no-install-recommends \
|
||||||
python3.10 python3.10-distutils python3.10-dev \
|
python3.7 python3.7-distutils python3.7-dev \
|
||||||
python3.11 python3.11-distutils python3.11-dev \
|
python3.8 python3.8-distutils python3.8-dev \
|
||||||
python3.12 python3-setuptools python3.12-dev \
|
|
||||||
python3.13 python3-setuptools python3.13-dev \
|
|
||||||
wget \
|
wget \
|
||||||
ca-certificates
|
ca-certificates
|
||||||
|
|
||||||
RUN wget https://bootstrap.pypa.io/get-pip.py \
|
RUN wget https://bootstrap.pypa.io/get-pip.py \
|
||||||
&& python3.10 get-pip.py pip==23.2.1 --break-system-packages \
|
&& python3 get-pip.py pip==21.3 \
|
||||||
&& python3.11 get-pip.py pip==23.2.1 --break-system-packages \
|
&& python3.7 get-pip.py pip==21.3 \
|
||||||
&& python3.12 get-pip.py pip==23.2.1 --break-system-packages \
|
&& python3.8 get-pip.py pip==21.3 \
|
||||||
&& python3.13 get-pip.py pip==23.2.1 --break-system-packages \
|
|
||||||
&& rm get-pip.py
|
&& rm get-pip.py
|
||||||
|
|
||||||
RUN apt-get install -y --no-install-recommends \
|
RUN apt-get install -y --no-install-recommends \
|
||||||
gcc \
|
libxml2-dev \
|
||||||
build-essential \
|
libxmlsec1-dev \
|
||||||
pkg-config \
|
build-essential \
|
||||||
libxml2-dev \
|
|
||||||
libxmlsec1-dev \
|
|
||||||
xmlsec1 \
|
|
||||||
libxml2-dev \
|
|
||||||
libxslt-dev \
|
|
||||||
zip
|
zip
|
||||||
|
|
||||||
RUN python3.10 --version
|
RUN python3.6 --version
|
||||||
RUN python3.11 --version
|
RUN python3.7 --version
|
||||||
RUN python3.12 --version
|
RUN python3.8 --version
|
||||||
RUN python3.13 --version
|
|
||||||
|
|
||||||
|
RUN pip3.6 install setuptools setuptools-rust
|
||||||
|
RUN pip3.7 install setuptools setuptools-rust
|
||||||
|
RUN pip3.8 install setuptools setuptools-rust
|
||||||
|
|
||||||
RUN pip3.10 install setuptools setuptools-rust
|
RUN pip3 install tox pytest
|
||||||
RUN pip3.11 install setuptools setuptools-rust --break-system-packages
|
|
||||||
RUN pip3.12 install setuptools setuptools-rust --break-system-packages
|
|
||||||
RUN pip3.13 install setuptools setuptools-rust --break-system-packages
|
|
||||||
|
|
||||||
RUN pip3 install tox pytest --break-system-packages
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
COPY pyproject.toml README.rst ./
|
|
||||||
COPY facho ./facho
|
|
||||||
RUN pip3.13 install -e . --break-system-packages
|
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -80,8 +80,9 @@ release: dist ## package and upload a release
|
|||||||
twine upload dist/*
|
twine upload dist/*
|
||||||
|
|
||||||
dist: clean ## builds source and wheel package
|
dist: clean ## builds source and wheel package
|
||||||
python -m build
|
python setup.py sdist
|
||||||
|
python setup.py bdist_wheel
|
||||||
ls -l dist
|
ls -l dist
|
||||||
|
|
||||||
install: clean ## install the package to the active Python's site-packages
|
install: clean ## install the package to the active Python's site-packages
|
||||||
pip install .
|
python setup.py install
|
||||||
|
|||||||
@@ -11,11 +11,14 @@
|
|||||||
dev-setup:
|
dev-setup:
|
||||||
docker build -t facho .
|
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:
|
dev-shell:
|
||||||
docker run --rm -ti -v "$(PWD):/app" -w /app --name facho-cli facho bash
|
docker run --rm -ti -v "$(PWD):/app" -w /app --name facho-cli facho bash
|
||||||
|
|
||||||
test:
|
test:
|
||||||
docker run -t -v $(PWD):/app -w /app facho sh -c 'cd /app; python3.13 -m pytest -vv'
|
docker run -t -v $(PWD):/app -w /app facho sh -c 'cd /app; python3.7 setup.py test'
|
||||||
|
|
||||||
tox:
|
tox:
|
||||||
docker run -it -v $(PWD)/:/app -w /app facho tox
|
docker run -it -v $(PWD)/:/app -w /app facho tox
|
||||||
|
|||||||
@@ -18,11 +18,11 @@
|
|||||||
# relative to the documentation root, use os.path.abspath to make it
|
# relative to the documentation root, use os.path.abspath to make it
|
||||||
# absolute, like shown here.
|
# absolute, like shown here.
|
||||||
#
|
#
|
||||||
import facho
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, os.path.abspath('..'))
|
sys.path.insert(0, os.path.abspath('..'))
|
||||||
|
|
||||||
|
import facho
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------
|
# -- General configuration ---------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ Once you have a copy of the source, you can install it with:
|
|||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
$ pip install .
|
$ python setup.py install
|
||||||
|
|
||||||
|
|
||||||
.. _Github repo: https://github.com/bit4bit/facho
|
.. _Github repo: https://github.com/bit4bit/facho
|
||||||
|
|||||||
@@ -11,18 +11,13 @@ from facho.fe import form_xml
|
|||||||
from facho.fe import fe
|
from facho.fe import fe
|
||||||
|
|
||||||
# importar otras necesarias
|
# importar otras necesarias
|
||||||
from datetime import datetime
|
from datetime import datetime, date
|
||||||
|
|
||||||
# Datos del fomulario del SET de pruebas
|
# Datos del fomulario del SET de pruebas
|
||||||
# Número suministrado por la Dian en el momento de la creación del SET de
|
INVOICE_AUTHORIZATION = '181360000001' #Número suministrado por la Dian en el momento de la creación del SET de Pruebas
|
||||||
# Pruebas
|
ID_SOFTWARE = '57bcb6d1-c591-5a90-b80a-cb030ec91440' #Id suministrado por la Dian en el momento de la creación del SET de Pruebas
|
||||||
INVOICE_AUTHORIZATION = '181360000001'
|
PIN = '19642' #Número creado por la empresa para poder crear el SET de pruebas
|
||||||
# Id suministrado por la Dian en el momento de la creación del SET de Pruebas
|
CLAVE_TECNICA = 'fc9eac422eba16e21ffd8c5f94b3f30a6e38162d' ##Id suministrado por la Dian en el momento de la creación del SET de Pruebas
|
||||||
ID_SOFTWARE = '57bcb6d1-c591-5a90-b80a-cb030ec91440'
|
|
||||||
# Número creado por la empresa para poder crear el SET de pruebas
|
|
||||||
PIN = '19642'
|
|
||||||
# Id suministrado por la Dian en el momento de la creación del SET de Pruebas
|
|
||||||
CLAVE_TECNICA = 'fc9eac422eba16e21ffd8c5f94b3f30a6e38162d'
|
|
||||||
|
|
||||||
|
|
||||||
# callback que retonar las extensiones XML necesarias
|
# callback que retonar las extensiones XML necesarias
|
||||||
@@ -31,25 +26,15 @@ CLAVE_TECNICA = 'fc9eac422eba16e21ffd8c5f94b3f30a6e38162d'
|
|||||||
# muchos de los valores usados son obtenidos
|
# muchos de los valores usados son obtenidos
|
||||||
# del servicio web de la DIAN.
|
# del servicio web de la DIAN.
|
||||||
def extensions(inv):
|
def extensions(inv):
|
||||||
security_code = fe.DianXMLExtensionSoftwareSecurityCode(
|
security_code = fe.DianXMLExtensionSoftwareSecurityCode(ID_SOFTWARE, PIN, inv.invoice_ident)
|
||||||
ID_SOFTWARE, PIN, inv.invoice_ident)
|
|
||||||
authorization_provider = fe.DianXMLExtensionAuthorizationProvider()
|
authorization_provider = fe.DianXMLExtensionAuthorizationProvider()
|
||||||
cufe = fe.DianXMLExtensionCUFE(inv, CLAVE_TECNICA, fe.AMBIENTE_PRUEBAS)
|
cufe = fe.DianXMLExtensionCUFE(inv, CLAVE_TECNICA, fe.AMBIENTE_PRUEBAS)
|
||||||
software_provider = fe.DianXMLExtensionSoftwareProvider(
|
software_provider = fe.DianXMLExtensionSoftwareProvider('nit_empresa', 'dígito_verificación', ID_SOFTWARE)
|
||||||
'nit_empresa', 'dígito_verificación', ID_SOFTWARE)
|
inv_authorization = fe.DianXMLExtensionInvoiceAuthorization(INVOICE_AUTHORIZATION,
|
||||||
inv_authorization = fe.DianXMLExtensionInvoiceAuthorization(
|
datetime(2019, 1, 19),#Datos toamdos de
|
||||||
INVOICE_AUTHORIZATION,
|
datetime(2030, 1, 19),#la configuración
|
||||||
# Datos tomados de la configuración
|
'SETP', 990000000, 995000000)#del SET de pruebas
|
||||||
datetime(2019, 1, 19),
|
return [security_code, authorization_provider, cufe, software_provider, inv_authorization]
|
||||||
datetime(2030, 1, 19),
|
|
||||||
'SETP', 990000000, 995000000) # del SET de pruebas
|
|
||||||
return [
|
|
||||||
security_code,
|
|
||||||
authorization_provider,
|
|
||||||
cufe,
|
|
||||||
software_provider,
|
|
||||||
inv_authorization]
|
|
||||||
|
|
||||||
|
|
||||||
def invoice():
|
def invoice():
|
||||||
# factura de venta nacional
|
# factura de venta nacional
|
||||||
@@ -63,72 +48,70 @@ def invoice():
|
|||||||
# asignar tipo de operacion ver DIAN:6.1.5
|
# asignar tipo de operacion ver DIAN:6.1.5
|
||||||
inv.set_operation_type('10')
|
inv.set_operation_type('10')
|
||||||
inv.set_supplier(form.Party(
|
inv.set_supplier(form.Party(
|
||||||
legal_name='Nombre registrado de la empresa',
|
legal_name = 'Nombre registrado de la empresa',
|
||||||
name='Nombre comercial o él mismo nombre registrado',
|
name = 'Nombre comercial o él mismo nombre registrado',
|
||||||
ident=form.PartyIdentification(
|
ident = form.PartyIdentification('nit_empresa', 'digito_verificación', '31'),
|
||||||
'nit_empresa', 'digito_verificación', '31'),
|
|
||||||
# obligaciones del contribuyente ver DIAN:FAK26
|
# obligaciones del contribuyente ver DIAN:FAK26
|
||||||
responsability_code=form.Responsability(['ZZ', 'O-14', 'O-48']),
|
responsability_code = form.Responsability(['O-07', 'O-14', 'O-48']),
|
||||||
# ver DIAN:FAJ28
|
# ver DIAN:FAJ28
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
# tipo de organizacion juridica ver DIAN:6.2.3
|
# tipo de organizacion juridica ver DIAN:6.2.3
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
email="correoempresa@correoempresa.correo",
|
email = "correoempresa@correoempresa.correo",
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia')),
|
form.CountrySubentity('05', 'Antioquia')),
|
||||||
))
|
))
|
||||||
# Tercero a quien se le factura
|
#Tercero a quien se le factura
|
||||||
inv.set_customer(form.Party(
|
inv.set_customer(form.Party(
|
||||||
legal_name='consumidor final',
|
legal_name = 'consumidor final',
|
||||||
name='consumidor final',
|
name = 'consumidor final',
|
||||||
ident=form.PartyIdentification('222222222222', '', '13'),
|
ident = form.PartyIdentification('222222222222', '', '13'),
|
||||||
responsability_code=form.Responsability(['R-99-PN']),
|
responsability_code = form.Responsability(['R-99-PN']),
|
||||||
responsability_regime_code='49',
|
responsability_regime_code = '49',
|
||||||
organization_code='2',
|
organization_code = '2',
|
||||||
email="consumidor_final0final.final",
|
email = "consumidor_final0final.final",
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia')),
|
form.CountrySubentity('05', 'Antioquia')),
|
||||||
# tax_scheme = form.TaxScheme('01', 'IVA')
|
#tax_scheme = form.TaxScheme('01', 'IVA')
|
||||||
))
|
))
|
||||||
# asignar metodo de pago
|
# asignar metodo de pago
|
||||||
inv.set_payment_mean(form.PaymentMean(
|
inv.set_payment_mean(form.PaymentMean(
|
||||||
# metodo de pago ver DIAN:3.4.1
|
# metodo de pago ver DIAN:3.4.1
|
||||||
id='1',
|
id = '1',
|
||||||
# codigocorrespondientealmediodepagoverDIAN:3.4.2
|
# codigo correspondiente al medio de pago ver DIAN:3.4.2
|
||||||
code='20',
|
code = '20',
|
||||||
# fechadevencimientodelafactura
|
# fecha de vencimiento de la factura
|
||||||
due_at=datetime.now(),
|
due_at = datetime.now(),
|
||||||
# identificadornumerico
|
# identificador numerico
|
||||||
payment_id='2'
|
payment_id = '2'
|
||||||
))
|
))
|
||||||
# adicionar una linea al documento
|
# adicionar una linea al documento
|
||||||
inv.add_invoice_line(
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
form.InvoiceLine(
|
quantity = form.Quantity(int(20.5), '94'),
|
||||||
quantity=form.Quantity(int(20.5), '94'),
|
# item general de codigo 999
|
||||||
# item general de codigo 999
|
description = 'productO3',
|
||||||
description='productO3',
|
item = form.StandardItem('test', 9999),
|
||||||
sitem=form.StandardItem('test', 9999),
|
price = form.Price(
|
||||||
price=form.Price(
|
# precio base del item (sin iva)
|
||||||
# precio base del item (sin iva)
|
amount = form.Amount(200.00),
|
||||||
amount=form.Amount(200.00),
|
# ver DIAN:6.3.5.1
|
||||||
# ver DIAN:6.3.5.1
|
type_code = '01',
|
||||||
type_code='01',
|
type = 'x'
|
||||||
type='x'
|
),
|
||||||
),
|
tax = form.TaxTotal(
|
||||||
tax=form.TaxTotal(
|
subtotals = [
|
||||||
subtotals=[
|
form.TaxSubTotal(
|
||||||
form.TaxSubTotal(
|
percent = 19.00,
|
||||||
percent=19.00,
|
scheme=form.TaxScheme('01')
|
||||||
scheme=form.TaxScheme('01')
|
)
|
||||||
)]
|
]
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
return inv
|
return inv
|
||||||
|
|
||||||
|
|
||||||
def document_xml():
|
def document_xml():
|
||||||
return form_xml.DIANInvoiceXML
|
return form_xml.DIANInvoiceXML
|
||||||
|
|||||||
@@ -1,28 +1,26 @@
|
|||||||
|
|
||||||
from facho import fe
|
from facho import fe
|
||||||
|
|
||||||
|
|
||||||
def extensions(nomina):
|
def extensions(nomina):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def nomina():
|
def nomina():
|
||||||
nomina = fe.nomina.DIANNominaIndividual()
|
nomina = fe.nomina.DIANNominaIndividual()
|
||||||
|
|
||||||
nomina.asignar_metadata(fe.nomina.Metadata(
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
secuencia=fe.nomina.NumeroSecuencia(
|
secuencia=fe.nomina.NumeroSecuencia(
|
||||||
numero='N00001',
|
numero = 'N00001',
|
||||||
consecutivo=232
|
consecutivo=232
|
||||||
),
|
),
|
||||||
lugar_generacion=fe.nomina.Lugar(
|
lugar_generacion=fe.nomina.Lugar(
|
||||||
pais=fe.nomina.Pais(
|
pais = fe.nomina.Pais(
|
||||||
code='CO'
|
code = 'CO'
|
||||||
),
|
),
|
||||||
departamento=fe.nomina.Departamento(
|
departamento = fe.nomina.Departamento(
|
||||||
code='05'
|
code = '05'
|
||||||
),
|
),
|
||||||
municipio=fe.nomina.Municipio(
|
municipio = fe.nomina.Municipio(
|
||||||
code='05001'
|
code = '05001'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
proveedor=fe.nomina.Proveedor(
|
proveedor=fe.nomina.Proveedor(
|
||||||
@@ -34,62 +32,62 @@ def nomina():
|
|||||||
))
|
))
|
||||||
|
|
||||||
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
fecha_generacion='2020-01-16',
|
fecha_generacion = '2020-01-16',
|
||||||
hora_generacion='1053:10-05:00',
|
hora_generacion = '1053:10-05:00',
|
||||||
tipo_ambiente=fe.nomina.InformacionGeneral.AMBIENTE_PRODUCCION,
|
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRODUCCION,
|
||||||
software_pin='693',
|
software_pin = '693',
|
||||||
periodo_nomina=fe.nomina.PeriodoNomina(code='1'),
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
tipo_moneda=fe.nomina.TipoMoneda(code='COP')
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.asignar_empleador(fe.nomina.Empleador(
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
nit='700085371',
|
nit = '700085371',
|
||||||
dv='1',
|
dv = '1',
|
||||||
pais=fe.nomina.Pais(
|
pais = fe.nomina.Pais(
|
||||||
code='CO'
|
code = 'CO'
|
||||||
),
|
),
|
||||||
departamento=fe.nomina.Departamento(
|
departamento = fe.nomina.Departamento(
|
||||||
code='05'
|
code = '05'
|
||||||
),
|
),
|
||||||
municipio=fe.nomina.Municipio(
|
municipio = fe.nomina.Municipio(
|
||||||
code='05001'
|
code = '05001'
|
||||||
),
|
),
|
||||||
direccion='calle etrivial'
|
direccion = 'calle etrivial'
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.asignar_trabajador(fe.nomina.Trabajador(
|
nomina.asignar_trabajador(fe.nomina.Trabajador(
|
||||||
tipo_contrato=fe.nomina.TipoContrato(
|
tipo_contrato = fe.nomina.TipoContrato(
|
||||||
code='1'
|
code = '1'
|
||||||
),
|
),
|
||||||
alto_riesgo=False,
|
alto_riesgo = False,
|
||||||
tipo_documento=fe.nomina.TipoDocumento(
|
tipo_documento = fe.nomina.TipoDocumento(
|
||||||
code='11'
|
code = '11'
|
||||||
),
|
),
|
||||||
primer_apellido='gnu',
|
primer_apellido = 'gnu',
|
||||||
segundo_apellido='emacs',
|
segundo_apellido = 'emacs',
|
||||||
primer_nombre='facho',
|
primer_nombre = 'facho',
|
||||||
lugar_trabajo=fe.nomina.LugarTrabajo(
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
pais=fe.nomina.Pais(code='CO'),
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
departamento=fe.nomina.Departamento(code='05'),
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
municipio=fe.nomina.Municipio(code='05001'),
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
direccion='calle facho'
|
direccion = 'calle facho'
|
||||||
),
|
),
|
||||||
numero_documento='800199436',
|
numero_documento = '800199436',
|
||||||
tipo=fe.nomina.TipoTrabajador(
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
code='01'
|
code = '01'
|
||||||
),
|
),
|
||||||
salario_integral=True,
|
salario_integral = True,
|
||||||
sueldo=fe.nomina.Amount(1_500_000)
|
sueldo = fe.nomina.Amount(1_500_000)
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
dias_trabajados=60,
|
dias_trabajados = 60,
|
||||||
sueldo_trabajado=fe.nomina.Amount(3_500_000)
|
sueldo_trabajado = fe.nomina.Amount(3_500_000)
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
porcentaje=fe.nomina.Amount(19),
|
porcentaje = fe.nomina.Amount(19),
|
||||||
deduccion=fe.nomina.Amount(1_000_000)
|
deduccion = fe.nomina.Amount(1_000_000)
|
||||||
))
|
))
|
||||||
|
|
||||||
return nomina
|
return nomina
|
||||||
|
|||||||
123
examples/habilitacion/N000001.py
Normal file
123
examples/habilitacion/N000001.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
from facho import fe
|
||||||
|
|
||||||
|
SOFTWARE_PIN='20234'
|
||||||
|
SOFTWARE_ID='100b0d10-0ca0-4ad4-a894-b704a568cbf3'
|
||||||
|
NIT='901575528'
|
||||||
|
DV='2'
|
||||||
|
|
||||||
|
def extensions(nomina):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def nomina():
|
||||||
|
nomina = fe.nomina.DIANNominaIndividual()
|
||||||
|
|
||||||
|
nomina.asignar_fecha_pago('2024-04-30')
|
||||||
|
|
||||||
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
|
novedad=fe.nomina.Novedad(value='false'),
|
||||||
|
secuencia=fe.nomina.NumeroSecuencia(
|
||||||
|
prefijo='N',
|
||||||
|
consecutivo='000001'
|
||||||
|
),
|
||||||
|
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(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit=NIT,
|
||||||
|
dv=DV,
|
||||||
|
software_id=SOFTWARE_ID,
|
||||||
|
software_pin=SOFTWARE_PIN
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_periodo(fe.nomina.Periodo(
|
||||||
|
fecha_ingreso= '2022-01-05',
|
||||||
|
fecha_liquidacion_inicio='2024-04-01',
|
||||||
|
fecha_liquidacion_fin='2024-04-30',
|
||||||
|
fecha_generacion='2024-04-30'
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
|
fecha_generacion = '2024-04-30',
|
||||||
|
hora_generacion = '08:01:00-05:00',
|
||||||
|
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
||||||
|
software_pin = SOFTWARE_PIN,
|
||||||
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_pago(fe.nomina.Pago(
|
||||||
|
forma=fe.nomina.FormaPago(
|
||||||
|
code='1',
|
||||||
|
),
|
||||||
|
metodo=fe.nomina.MetodoPago(
|
||||||
|
code='10'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit = NIT,
|
||||||
|
dv = DV,
|
||||||
|
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 = 'GONZALEZ',
|
||||||
|
segundo_apellido = '',
|
||||||
|
primer_nombre = 'JUAN',
|
||||||
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
|
direccion = 'CL 35C 102-17 BL 7 AP 101'
|
||||||
|
),
|
||||||
|
numero_documento = NIT,
|
||||||
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
|
code = '01'
|
||||||
|
),
|
||||||
|
salario_integral = False,
|
||||||
|
sueldo = fe.nomina.Amount(2400000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
|
dias_trabajados = 30,
|
||||||
|
sueldo_trabajado = fe.nomina.Amount(2400000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
|
porcentaje = fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(96000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||||
|
porcentaje=fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(96000)
|
||||||
|
))
|
||||||
|
return nomina
|
||||||
|
|
||||||
89
examples/habilitacion/N000001.xml
Normal file
89
examples/habilitacion/N000001.xml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<NominaIndividual xmlns:atd="urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2" xmlns="dian:gov:co:facturaelectronica:NominaIndividual" xmlns:fe="http://www.dian.gov.co/contratos/facturaelectronica/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cdt="urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1" xmlns:clm54217="urn:un:unece:uncefact:codelist:specification:54217:2001" xmlns:clmIANAMIMEMediaType="urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2" xmlns:sts="dian:gov:co:facturaelectronica:Structures-2-1" xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:sig="http://www.w3.org/2000/09/xmldsig#" SchemaLocation="" xsi:schemaLocation="dian:gov:co:facturaelectronica:NominaIndividual NominaIndividualElectronicaXSD.xsd"><ext:UBLExtensions><ext:UBLExtension><ext:ExtensionContent><ds:Signature Id="xmlsig-2e62ccd5-82d2-4922-90a0-31af30fc44c0">
|
||||||
|
<ds:SignedInfo>
|
||||||
|
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||||
|
<ds:Reference Id="xmldsig-2e62ccd5-82d2-4922-90a0-31af30fc44c0-ref0" URI="">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>HS3rmJgPKyCNLNO3TXfP0s1zIGvJTjq40JfMm/muHLA=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference Id="xmldsig-2e62ccd5-82d2-4922-90a0-31af30fc44c0-ref1" URI="#xmldsig-2e62ccd5-82d2-4922-90a0-31af30fc44c0-KeyInfo">
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>88R+0zjb6NIUiHhT8EE1ale8bO+TR6SSQBtVQUYkZ6c=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference URI="#xmldsig-2e62ccd5-82d2-4922-90a0-31af30fc44c0-signedprops" Type="http://uri.etsi.org/01903#SignedProperties">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>QF0d+RznylwnbFaGclqPWLndUo35HVDouEYoS1wfVO8=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
</ds:SignedInfo>
|
||||||
|
<ds:SignatureValue>0JBFsBhyo4r/9m5vuBXbKirHOgniDNeGW3RNXpCE/sgXvrV3E4K8/M4HeO0VYtM0
|
||||||
|
G4bHvvkP2NCkdrKgZ9gB+XG8E/rEmJnwKpHm2kaNnpM1pYGoqBNWpqCa5FnUsEk4
|
||||||
|
c4BmBaKjmBSUrz+2JoOg1RKaaJumqGWm83IjWWJq9b4l40imL0XIgoTmWUtIGOA0
|
||||||
|
swm5rokLFldHv9T9CQvuYqCQIb6GAb2HB/GzNcPVO6quCqNVI6K9+Zh6vNpWpnCW
|
||||||
|
crP8iCn4T3jo2PxU56dwA63xOtkTdYWphaGL4J63flsZysPQ817uuHV/XLu1VwHE
|
||||||
|
cBpcTWyXL9LB7rgqrVSIzw==</ds:SignatureValue>
|
||||||
|
<ds:KeyInfo Id="xmldsig-2e62ccd5-82d2-4922-90a0-31af30fc44c0-KeyInfo">
|
||||||
|
<ds:X509Data>
|
||||||
|
<ds:X509Certificate>MIIH8TCCBdmgAwIBAgIIQxaPJd4YTlMwDQYJKoZIhvcNAQELBQAwgbYxIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMSYwJAYDVQQDEx1DQSBBTkRF
|
||||||
|
UyBTQ0QgUy5BLiBDbGFzZSBJSSB2MzEwMC4GA1UECxMnRGl2aXNpb24gZGUgY2Vy
|
||||||
|
dGlmaWNhY2lvbiBlbnRpZGFkIGZpbmFsMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDAS
|
||||||
|
BgNVBAcTC0JvZ290YSBELkMuMQswCQYDVQQGEwJDTzAeFw0yNDA1MTYwNTAwMDBa
|
||||||
|
Fw0yNTA1MTYwNDU5MDBaMIIBQDEtMCsGA1UECRMkVFYgNDYgQyA0MiBFU1RFIDc4
|
||||||
|
OSBDT1JSIFNBTlRBIEVMRU5BMSIwIAYJKoZIhvcNAQkBFhNiaWNpcGl6emFAZ21h
|
||||||
|
aWwuY29tMRowGAYDVQQDExFCSUNJIFBJWlpBIFMuQS5TLjETMBEGA1UEBRMKOTAx
|
||||||
|
NTc1NTI4MjE2MDQGA1UEDBMtRW1pc29yIEZhY3R1cmEgRWxlY3Ryb25pY2EgLSBQ
|
||||||
|
ZXJzb25hIEp1cmlkaWNhMTswOQYDVQQLEzJFbWl0aWRvIHBvciBBbmRlcyBTQ0Qg
|
||||||
|
QWMgMjYgNjkgQyAwMyBUb3JyZSBCIE9mIDcwMTEQMA4GA1UEChMHR0VSRU5URTES
|
||||||
|
MBAGA1UEBwwJTUVERUxMw41OMRIwEAYDVQQIEwlBTlRJT1FVSUExCzAJBgNVBAYT
|
||||||
|
AkNPMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5J1O+4ZedrSBUsb+
|
||||||
|
9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5/wra04OU57cS1/+/
|
||||||
|
yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/PbswnrKukFU2acxISwT
|
||||||
|
Lu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SIiqqPwHKh+6EDIoou
|
||||||
|
jo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891KBA9Yebdw7m/+ufu
|
||||||
|
+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWnspvDK97D8YG0MeifP
|
||||||
|
YveIPwIDAQABo4ICdDCCAnAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRA/iZp
|
||||||
|
RzInMtGsIcgu7M+N1TVo6DBvBggrBgEFBQcBAQRjMGEwNgYIKwYBBQUHMAKGKmh0
|
||||||
|
dHA6Ly9jZXJ0cy5hbmRlc3NjZC5jb20uY28vQ2xhc2VJSXYzLmNydDAnBggrBgEF
|
||||||
|
BQcwAYYbaHR0cDovL29jc3AuYW5kZXNzY2QuY29tLmNvMB4GA1UdEQQXMBWBE2Jp
|
||||||
|
Y2lwaXp6YUBnbWFpbC5jb20wggEjBgNVHSAEggEaMIIBFjCBwQYNKwYBBAGB9EgB
|
||||||
|
AgYIADCBrzCBrAYIKwYBBQUHAgIwgZ8MgZxMYSB1dGlsaXphY2nDs24gZGUgZXN0
|
||||||
|
ZSBjZXJ0aWZpY2FkbyBlc3TDoSBzdWpldGEgYSBsYSBQQyBkZSBGYWN0dXJhY2nD
|
||||||
|
s24gRWxlY3Ryw7NuaWNhIHkgRFBDIGVzdGFibGVjaWRhcyBwb3IgQW5kZXMgU0NE
|
||||||
|
LiBDw7NkaWdvIGRlIEFjcmVkaXRhY2nDs246IDE2LUVDRC0wMDQwUAYNKwYBBAGB
|
||||||
|
9EgBAQEKADA/MD0GCCsGAQUFBwIBFjFodHRwczovL3d3dy5hbmRlc3NjZC5jb20u
|
||||||
|
Y28vZG9jcy9EUENfQW5kZXNTQ0QucGRmMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
|
||||||
|
BgEFBQcDBDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLmFuZGVzc2NkLmNv
|
||||||
|
bS5jby9DbGFzZUlJdjMuY3JsMB0GA1UdDgQWBBRKPoh3BJM7SxEL0UXkSne2MyFO
|
||||||
|
jjAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQELBQADggIBAA6Zzor3kpJ6vNKv
|
||||||
|
TAeHaMfmJ/PaghQ1+Lab7Pwk+lsPsMETFu/IpEK5qij2bV54UNnqyLYOZtIbnWTG
|
||||||
|
qgT7QxQvy+/of/I3zzF+kH4/Lp2TSlHaDEb/airCZ3I2G23M9iaZzSwYuOsOaGwp
|
||||||
|
4ovkXlYwQ7FVNfIIoAq95m9cBAigb06bRIlVBVTQq44hQFQQG6aSIT7SSPtCwPhB
|
||||||
|
5CJzG09pmgbxizqN/yxdjWdfW6Av79dh6K4uQT++Vtyp5DuAkmfn0ehayrUbDLkH
|
||||||
|
9jQFF128U5pnOPfKWf22acXqQBapesUSV/HZUZ3PXoWeHWXcMdz0azxOEunS4+px
|
||||||
|
fs5UzInRAmEcYwJHqJT3irFz+J2RsZ0WnJHrTGqFoXniQQH8QbCHehDTGN7/v/v1
|
||||||
|
LQBr5PQBnSEWhmrQ9uFrwPyMMg3yd+L75TaHLZ0MTSVezAG52oM9jBiU5tYXkSio
|
||||||
|
EfPdIsGlG74BybULGSG2OlTINlblj/lj7pL67V+gY9EGN1zzNKL5sW4YXlXewa6K
|
||||||
|
dTpLmmzWzI8Cm+tOuuJDSHSwMjn525O+Z/oyKLjdQdyfg1KnZYwNZFpMmCwfP5nd
|
||||||
|
cm4F7Anzb9HX9ciluAxc6as9TsNoDDTSAGPuUr0QvXqXd9ZCgXdNzdFeiaYknLP5
|
||||||
|
hT4f5CoO2M8qcG+CH7HnkaOHrSuK</ds:X509Certificate>
|
||||||
|
</ds:X509Data>
|
||||||
|
<ds:KeyValue>
|
||||||
|
<ds:RSAKeyValue>
|
||||||
|
<ds:Modulus>5J1O+4ZedrSBUsb+9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5
|
||||||
|
/wra04OU57cS1/+/yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/Pbs
|
||||||
|
wnrKukFU2acxISwTLu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SI
|
||||||
|
iqqPwHKh+6EDIooujo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891
|
||||||
|
KBA9Yebdw7m/+ufu+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWns
|
||||||
|
pvDK97D8YG0MeifPYveIPw==</ds:Modulus>
|
||||||
|
<ds:Exponent>AQAB</ds:Exponent>
|
||||||
|
</ds:RSAKeyValue>
|
||||||
|
</ds:KeyValue>
|
||||||
|
</ds:KeyInfo>
|
||||||
|
<ds:Object><xades:QualifyingProperties Target="#xmlsig-2e62ccd5-82d2-4922-90a0-31af30fc44c0" Id="XadesObjects"><xades:SignedProperties Id="xmldsig-2e62ccd5-82d2-4922-90a0-31af30fc44c0-signedprops"><xades:SignedSignatureProperties><xades:SigningTime>2025-03-16T16:49:57.777363</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>YcIPspAVFcNg+B/galYrdCLYvLIEwFI4KWdSzcuupPY=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>C=CO, L=Bogota D.C., O=Andes SCD, OU=Division de certificacion entidad final, CN=CA ANDES SCD S.A. Clase II v3, OID.1.2.840.113549.1.9.1=info@andesscd.com.co</ds:X509IssuerName><ds:X509SerialNumber>4834208642831502931</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate><xades:SignaturePolicyIdentifier><xades:SignaturePolicyId><xades:SigPolicyId><xades:Identifier>https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf</xades:Identifier><xades:Description>Política de firma para facturas electrónicas de la República de Colombia.</xades:Description></xades:SigPolicyId><xades:SigPolicyHash><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>dMoMvtcG5aIzgYo0tIsSQeVJBDnUnfSOfBpxXrmor0Y=</ds:DigestValue></xades:SigPolicyHash></xades:SignaturePolicyId></xades:SignaturePolicyIdentifier><xades:SignerRole><xades:ClaimedRoles><xades:ClaimedRole>supplier</xades:ClaimedRole></xades:ClaimedRoles></xades:SignerRole></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object></ds:Signature></ext:ExtensionContent></ext:UBLExtension></ext:UBLExtensions><Novedad CUNENov="false">false</Novedad><Periodo FechaIngreso="2022-01-05" FechaLiquidacionInicio="2024-04-01" FechaLiquidacionFin="2024-04-30" TiempoLaborado="1" FechaGen="2024-04-30"/><NumeroSecuenciaXML Prefijo="N" Consecutivo="000001" Numero="N000001"/><LugarGeneracionXML Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Idioma="es"/><ProveedorXML NIT="901575528" DV="2" SoftwareID="100b0d10-0ca0-4ad4-a894-b704a568cbf3" RazonSocial="BICI PIZZA S.A.S" SoftwareSC="277c710304542320e15609646371219dc9ac3edd9c73adc0a278a355fbef97609bb7e451b92900b517044443f6ae1838"/><CodigoQR>https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey=f498037db4d2f7c42224fbdc958d031927f17f0ad4e4c1f4a3e85d6363d68f3f951860873e6899937c080f03b0bd0ceb</CodigoQR><InformacionGeneral Version="V1.0: Documento Soporte de Pago de Nómina Electrónica" Ambiente="2" TipoXML="102" EncripCUNE="CUNE-SHA384" FechaGen="2024-04-30" HoraGen="08:01:00-05:00" PeriodoNomina="1" TipoMoneda="COP" TRM="0" CUNE="f498037db4d2f7c42224fbdc958d031927f17f0ad4e4c1f4a3e85d6363d68f3f951860873e6899937c080f03b0bd0ceb"/><Empleador NIT="901575528" DV="2" Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Direccion="calle etrivial" RazonSocial="BICI PIZZA S.A.S"/><Trabajador TipoTrabajador="01" SubTipoTrabajador="00" AltoRiesgoPension="false" TipoDocumento="11" NumeroDocumento="901575528" PrimerApellido="GONZALEZ" SegundoApellido="" PrimerNombre="JUAN" LugarTrabajoPais="CO" LugarTrabajoDepartamentoEstado="05" LugarTrabajoMunicipioCiudad="05001" LugarTrabajoDireccion="CL 35C 102-17 BL 7 AP 101" SalarioIntegral="false" TipoContrato="1" Sueldo="2400000.0"/><Pago Forma="1" Metodo="10"/><FechasPagos><FechaPago>2024-04-30</FechaPago></FechasPagos><Devengados><Basico DiasTrabajados="30" SueldoTrabajado="2400000.00"/></Devengados><Deducciones><Salud Porcentaje="4.00" Deduccion="96000.0"/><FondoPension Porcentaje="4.00" Deduccion="96000.0"/></Deducciones><Redondeo>0</Redondeo><DevengadosTotal>2400000.00</DevengadosTotal><DeduccionesTotal>192000.00</DeduccionesTotal><ComprobanteTotal>2208000.00</ComprobanteTotal></NominaIndividual>
|
||||||
BIN
examples/habilitacion/N000001.zip
Normal file
BIN
examples/habilitacion/N000001.zip
Normal file
Binary file not shown.
123
examples/habilitacion/N000002.py
Normal file
123
examples/habilitacion/N000002.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
from facho import fe
|
||||||
|
|
||||||
|
SOFTWARE_PIN='20234'
|
||||||
|
SOFTWARE_ID='100b0d10-0ca0-4ad4-a894-b704a568cbf3'
|
||||||
|
NIT='901575528'
|
||||||
|
DV='2'
|
||||||
|
|
||||||
|
def extensions(nomina):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def nomina():
|
||||||
|
nomina = fe.nomina.DIANNominaIndividual()
|
||||||
|
|
||||||
|
nomina.asignar_fecha_pago('2024-04-30')
|
||||||
|
|
||||||
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
|
novedad=fe.nomina.Novedad(value='false'),
|
||||||
|
secuencia=fe.nomina.NumeroSecuencia(
|
||||||
|
prefijo='N',
|
||||||
|
consecutivo='000002'
|
||||||
|
),
|
||||||
|
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(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit=NIT,
|
||||||
|
dv=DV,
|
||||||
|
software_id=SOFTWARE_ID,
|
||||||
|
software_pin=SOFTWARE_PIN
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_periodo(fe.nomina.Periodo(
|
||||||
|
fecha_ingreso= '2022-09-05',
|
||||||
|
fecha_liquidacion_inicio='2024-04-01',
|
||||||
|
fecha_liquidacion_fin='2024-04-30',
|
||||||
|
fecha_generacion='2024-04-30'
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
|
fecha_generacion = '2024-04-30',
|
||||||
|
hora_generacion = '08:01:00-05:00',
|
||||||
|
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
||||||
|
software_pin = SOFTWARE_PIN,
|
||||||
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_pago(fe.nomina.Pago(
|
||||||
|
forma=fe.nomina.FormaPago(
|
||||||
|
code='1',
|
||||||
|
),
|
||||||
|
metodo=fe.nomina.MetodoPago(
|
||||||
|
code='10'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit = NIT,
|
||||||
|
dv = DV,
|
||||||
|
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 = 'GIRALDO',
|
||||||
|
segundo_apellido = '',
|
||||||
|
primer_nombre = 'VIVIANA',
|
||||||
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
|
direccion = 'CL 35C 102-17 BL 7 AP 101'
|
||||||
|
),
|
||||||
|
numero_documento = NIT,
|
||||||
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
|
code = '01'
|
||||||
|
),
|
||||||
|
salario_integral = False,
|
||||||
|
sueldo = fe.nomina.Amount(1160000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
|
dias_trabajados = 30,
|
||||||
|
sueldo_trabajado = fe.nomina.Amount(1160000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
|
porcentaje = fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(46400)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||||
|
porcentaje=fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(46400)
|
||||||
|
))
|
||||||
|
return nomina
|
||||||
|
|
||||||
89
examples/habilitacion/N000002.xml
Normal file
89
examples/habilitacion/N000002.xml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<NominaIndividual xmlns:atd="urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2" xmlns="dian:gov:co:facturaelectronica:NominaIndividual" xmlns:fe="http://www.dian.gov.co/contratos/facturaelectronica/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cdt="urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1" xmlns:clm54217="urn:un:unece:uncefact:codelist:specification:54217:2001" xmlns:clmIANAMIMEMediaType="urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2" xmlns:sts="dian:gov:co:facturaelectronica:Structures-2-1" xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:sig="http://www.w3.org/2000/09/xmldsig#" SchemaLocation="" xsi:schemaLocation="dian:gov:co:facturaelectronica:NominaIndividual NominaIndividualElectronicaXSD.xsd"><ext:UBLExtensions><ext:UBLExtension><ext:ExtensionContent><ds:Signature Id="xmlsig-bd7246f2-0f63-4a0a-822b-f59be349b7df">
|
||||||
|
<ds:SignedInfo>
|
||||||
|
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||||
|
<ds:Reference Id="xmldsig-bd7246f2-0f63-4a0a-822b-f59be349b7df-ref0" URI="">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>OZ66ZARE1QPKfYYk+BdiEnO0675e7p00fGwhb/Iyd5s=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference Id="xmldsig-bd7246f2-0f63-4a0a-822b-f59be349b7df-ref1" URI="#xmldsig-bd7246f2-0f63-4a0a-822b-f59be349b7df-KeyInfo">
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>jZRqaYdQrLDYoqJmrKrLoO2ZHlGX1Xo5IpGFAznaQnI=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference URI="#xmldsig-bd7246f2-0f63-4a0a-822b-f59be349b7df-signedprops" Type="http://uri.etsi.org/01903#SignedProperties">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>XNMT1fgTLgeuUDfYH//8aY/TqzhsRcScSySL/6nKwxE=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
</ds:SignedInfo>
|
||||||
|
<ds:SignatureValue>fHBH/GVqHYi8iFbtTUwLUaVerZjfoj64Toq5jE+qi/HLmwhtDCAK2V/ISn0VDxpJ
|
||||||
|
3QrAqWw/VjTFEqWmRV7mCxybM98A/+5yeWbvDkG2eY5fUOUHin9+oomysY8cwLjA
|
||||||
|
joXsvjEJlM1YIndzWG/Dryr14Hcax6ItVSaopA+1BpUoFn/5jWwZXsbmq0jHDjsI
|
||||||
|
Vyk1WpZzYwmM/aGZg7gj/pR7kZZOnv4d3L/MnFP6vJRdRNtRwO73wBd5lYGU1KaB
|
||||||
|
iTimrV2gBwg0+o5bqloSaQEtqV87adJG0h3eosSiIhrG9rc9rOpvqqq7tG2nAxRx
|
||||||
|
NyPM8gwuKoaoU9ogvRsqHQ==</ds:SignatureValue>
|
||||||
|
<ds:KeyInfo Id="xmldsig-bd7246f2-0f63-4a0a-822b-f59be349b7df-KeyInfo">
|
||||||
|
<ds:X509Data>
|
||||||
|
<ds:X509Certificate>MIIH8TCCBdmgAwIBAgIIQxaPJd4YTlMwDQYJKoZIhvcNAQELBQAwgbYxIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMSYwJAYDVQQDEx1DQSBBTkRF
|
||||||
|
UyBTQ0QgUy5BLiBDbGFzZSBJSSB2MzEwMC4GA1UECxMnRGl2aXNpb24gZGUgY2Vy
|
||||||
|
dGlmaWNhY2lvbiBlbnRpZGFkIGZpbmFsMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDAS
|
||||||
|
BgNVBAcTC0JvZ290YSBELkMuMQswCQYDVQQGEwJDTzAeFw0yNDA1MTYwNTAwMDBa
|
||||||
|
Fw0yNTA1MTYwNDU5MDBaMIIBQDEtMCsGA1UECRMkVFYgNDYgQyA0MiBFU1RFIDc4
|
||||||
|
OSBDT1JSIFNBTlRBIEVMRU5BMSIwIAYJKoZIhvcNAQkBFhNiaWNpcGl6emFAZ21h
|
||||||
|
aWwuY29tMRowGAYDVQQDExFCSUNJIFBJWlpBIFMuQS5TLjETMBEGA1UEBRMKOTAx
|
||||||
|
NTc1NTI4MjE2MDQGA1UEDBMtRW1pc29yIEZhY3R1cmEgRWxlY3Ryb25pY2EgLSBQ
|
||||||
|
ZXJzb25hIEp1cmlkaWNhMTswOQYDVQQLEzJFbWl0aWRvIHBvciBBbmRlcyBTQ0Qg
|
||||||
|
QWMgMjYgNjkgQyAwMyBUb3JyZSBCIE9mIDcwMTEQMA4GA1UEChMHR0VSRU5URTES
|
||||||
|
MBAGA1UEBwwJTUVERUxMw41OMRIwEAYDVQQIEwlBTlRJT1FVSUExCzAJBgNVBAYT
|
||||||
|
AkNPMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5J1O+4ZedrSBUsb+
|
||||||
|
9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5/wra04OU57cS1/+/
|
||||||
|
yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/PbswnrKukFU2acxISwT
|
||||||
|
Lu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SIiqqPwHKh+6EDIoou
|
||||||
|
jo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891KBA9Yebdw7m/+ufu
|
||||||
|
+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWnspvDK97D8YG0MeifP
|
||||||
|
YveIPwIDAQABo4ICdDCCAnAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRA/iZp
|
||||||
|
RzInMtGsIcgu7M+N1TVo6DBvBggrBgEFBQcBAQRjMGEwNgYIKwYBBQUHMAKGKmh0
|
||||||
|
dHA6Ly9jZXJ0cy5hbmRlc3NjZC5jb20uY28vQ2xhc2VJSXYzLmNydDAnBggrBgEF
|
||||||
|
BQcwAYYbaHR0cDovL29jc3AuYW5kZXNzY2QuY29tLmNvMB4GA1UdEQQXMBWBE2Jp
|
||||||
|
Y2lwaXp6YUBnbWFpbC5jb20wggEjBgNVHSAEggEaMIIBFjCBwQYNKwYBBAGB9EgB
|
||||||
|
AgYIADCBrzCBrAYIKwYBBQUHAgIwgZ8MgZxMYSB1dGlsaXphY2nDs24gZGUgZXN0
|
||||||
|
ZSBjZXJ0aWZpY2FkbyBlc3TDoSBzdWpldGEgYSBsYSBQQyBkZSBGYWN0dXJhY2nD
|
||||||
|
s24gRWxlY3Ryw7NuaWNhIHkgRFBDIGVzdGFibGVjaWRhcyBwb3IgQW5kZXMgU0NE
|
||||||
|
LiBDw7NkaWdvIGRlIEFjcmVkaXRhY2nDs246IDE2LUVDRC0wMDQwUAYNKwYBBAGB
|
||||||
|
9EgBAQEKADA/MD0GCCsGAQUFBwIBFjFodHRwczovL3d3dy5hbmRlc3NjZC5jb20u
|
||||||
|
Y28vZG9jcy9EUENfQW5kZXNTQ0QucGRmMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
|
||||||
|
BgEFBQcDBDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLmFuZGVzc2NkLmNv
|
||||||
|
bS5jby9DbGFzZUlJdjMuY3JsMB0GA1UdDgQWBBRKPoh3BJM7SxEL0UXkSne2MyFO
|
||||||
|
jjAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQELBQADggIBAA6Zzor3kpJ6vNKv
|
||||||
|
TAeHaMfmJ/PaghQ1+Lab7Pwk+lsPsMETFu/IpEK5qij2bV54UNnqyLYOZtIbnWTG
|
||||||
|
qgT7QxQvy+/of/I3zzF+kH4/Lp2TSlHaDEb/airCZ3I2G23M9iaZzSwYuOsOaGwp
|
||||||
|
4ovkXlYwQ7FVNfIIoAq95m9cBAigb06bRIlVBVTQq44hQFQQG6aSIT7SSPtCwPhB
|
||||||
|
5CJzG09pmgbxizqN/yxdjWdfW6Av79dh6K4uQT++Vtyp5DuAkmfn0ehayrUbDLkH
|
||||||
|
9jQFF128U5pnOPfKWf22acXqQBapesUSV/HZUZ3PXoWeHWXcMdz0azxOEunS4+px
|
||||||
|
fs5UzInRAmEcYwJHqJT3irFz+J2RsZ0WnJHrTGqFoXniQQH8QbCHehDTGN7/v/v1
|
||||||
|
LQBr5PQBnSEWhmrQ9uFrwPyMMg3yd+L75TaHLZ0MTSVezAG52oM9jBiU5tYXkSio
|
||||||
|
EfPdIsGlG74BybULGSG2OlTINlblj/lj7pL67V+gY9EGN1zzNKL5sW4YXlXewa6K
|
||||||
|
dTpLmmzWzI8Cm+tOuuJDSHSwMjn525O+Z/oyKLjdQdyfg1KnZYwNZFpMmCwfP5nd
|
||||||
|
cm4F7Anzb9HX9ciluAxc6as9TsNoDDTSAGPuUr0QvXqXd9ZCgXdNzdFeiaYknLP5
|
||||||
|
hT4f5CoO2M8qcG+CH7HnkaOHrSuK</ds:X509Certificate>
|
||||||
|
</ds:X509Data>
|
||||||
|
<ds:KeyValue>
|
||||||
|
<ds:RSAKeyValue>
|
||||||
|
<ds:Modulus>5J1O+4ZedrSBUsb+9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5
|
||||||
|
/wra04OU57cS1/+/yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/Pbs
|
||||||
|
wnrKukFU2acxISwTLu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SI
|
||||||
|
iqqPwHKh+6EDIooujo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891
|
||||||
|
KBA9Yebdw7m/+ufu+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWns
|
||||||
|
pvDK97D8YG0MeifPYveIPw==</ds:Modulus>
|
||||||
|
<ds:Exponent>AQAB</ds:Exponent>
|
||||||
|
</ds:RSAKeyValue>
|
||||||
|
</ds:KeyValue>
|
||||||
|
</ds:KeyInfo>
|
||||||
|
<ds:Object><xades:QualifyingProperties Target="#xmlsig-bd7246f2-0f63-4a0a-822b-f59be349b7df" Id="XadesObjects"><xades:SignedProperties Id="xmldsig-bd7246f2-0f63-4a0a-822b-f59be349b7df-signedprops"><xades:SignedSignatureProperties><xades:SigningTime>2025-03-16T16:50:01.250573</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>YcIPspAVFcNg+B/galYrdCLYvLIEwFI4KWdSzcuupPY=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>C=CO, L=Bogota D.C., O=Andes SCD, OU=Division de certificacion entidad final, CN=CA ANDES SCD S.A. Clase II v3, OID.1.2.840.113549.1.9.1=info@andesscd.com.co</ds:X509IssuerName><ds:X509SerialNumber>4834208642831502931</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate><xades:SignaturePolicyIdentifier><xades:SignaturePolicyId><xades:SigPolicyId><xades:Identifier>https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf</xades:Identifier><xades:Description>Política de firma para facturas electrónicas de la República de Colombia.</xades:Description></xades:SigPolicyId><xades:SigPolicyHash><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>dMoMvtcG5aIzgYo0tIsSQeVJBDnUnfSOfBpxXrmor0Y=</ds:DigestValue></xades:SigPolicyHash></xades:SignaturePolicyId></xades:SignaturePolicyIdentifier><xades:SignerRole><xades:ClaimedRoles><xades:ClaimedRole>supplier</xades:ClaimedRole></xades:ClaimedRoles></xades:SignerRole></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object></ds:Signature></ext:ExtensionContent></ext:UBLExtension></ext:UBLExtensions><Novedad CUNENov="false">false</Novedad><Periodo FechaIngreso="2022-09-05" FechaLiquidacionInicio="2024-04-01" FechaLiquidacionFin="2024-04-30" TiempoLaborado="1" FechaGen="2024-04-30"/><NumeroSecuenciaXML Prefijo="N" Consecutivo="000002" Numero="N000002"/><LugarGeneracionXML Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Idioma="es"/><ProveedorXML NIT="901575528" DV="2" SoftwareID="100b0d10-0ca0-4ad4-a894-b704a568cbf3" RazonSocial="BICI PIZZA S.A.S" SoftwareSC="067c1069842576f1f954d3540d9f75a214e2a63219f36f4f25465e26958c10d2c9e222076635379bd7f61ca0459c87e9"/><CodigoQR>https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey=cb2e6968a811c661ebdc8b8cd19a323ca05471c2fe3c3b1cfb5275379d7df94d6c22f9405d732295e805095e366a99fa</CodigoQR><InformacionGeneral Version="V1.0: Documento Soporte de Pago de Nómina Electrónica" Ambiente="2" TipoXML="102" EncripCUNE="CUNE-SHA384" FechaGen="2024-04-30" HoraGen="08:01:00-05:00" PeriodoNomina="1" TipoMoneda="COP" TRM="0" CUNE="cb2e6968a811c661ebdc8b8cd19a323ca05471c2fe3c3b1cfb5275379d7df94d6c22f9405d732295e805095e366a99fa"/><Empleador NIT="901575528" DV="2" Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Direccion="calle etrivial" RazonSocial="BICI PIZZA S.A.S"/><Trabajador TipoTrabajador="01" SubTipoTrabajador="00" AltoRiesgoPension="false" TipoDocumento="11" NumeroDocumento="901575528" PrimerApellido="GIRALDO" SegundoApellido="" PrimerNombre="VIVIANA" LugarTrabajoPais="CO" LugarTrabajoDepartamentoEstado="05" LugarTrabajoMunicipioCiudad="05001" LugarTrabajoDireccion="CL 35C 102-17 BL 7 AP 101" SalarioIntegral="false" TipoContrato="1" Sueldo="1160000.0"/><Pago Forma="1" Metodo="10"/><FechasPagos><FechaPago>2024-04-30</FechaPago></FechasPagos><Devengados><Basico DiasTrabajados="30" SueldoTrabajado="1160000.00"/></Devengados><Deducciones><Salud Porcentaje="4.00" Deduccion="46400.0"/><FondoPension Porcentaje="4.00" Deduccion="46400.0"/></Deducciones><Redondeo>0</Redondeo><DevengadosTotal>1160000.00</DevengadosTotal><DeduccionesTotal>92800.00</DeduccionesTotal><ComprobanteTotal>1067200.00</ComprobanteTotal></NominaIndividual>
|
||||||
BIN
examples/habilitacion/N000002.zip
Normal file
BIN
examples/habilitacion/N000002.zip
Normal file
Binary file not shown.
123
examples/habilitacion/N000003.py
Normal file
123
examples/habilitacion/N000003.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
from facho import fe
|
||||||
|
|
||||||
|
SOFTWARE_PIN='20234'
|
||||||
|
SOFTWARE_ID='100b0d10-0ca0-4ad4-a894-b704a568cbf3'
|
||||||
|
NIT='901575528'
|
||||||
|
DV='2'
|
||||||
|
|
||||||
|
def extensions(nomina):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def nomina():
|
||||||
|
nomina = fe.nomina.DIANNominaIndividual()
|
||||||
|
|
||||||
|
nomina.asignar_fecha_pago('2024-04-30')
|
||||||
|
|
||||||
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
|
novedad=fe.nomina.Novedad(value='false'),
|
||||||
|
secuencia=fe.nomina.NumeroSecuencia(
|
||||||
|
prefijo='N',
|
||||||
|
consecutivo='000003'
|
||||||
|
),
|
||||||
|
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(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit=NIT,
|
||||||
|
dv=DV,
|
||||||
|
software_id=SOFTWARE_ID,
|
||||||
|
software_pin=SOFTWARE_PIN
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_periodo(fe.nomina.Periodo(
|
||||||
|
fecha_ingreso= '2022-01-05',
|
||||||
|
fecha_liquidacion_inicio='2024-04-01',
|
||||||
|
fecha_liquidacion_fin='2024-04-30',
|
||||||
|
fecha_generacion='2024-04-30'
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
|
fecha_generacion = '2024-04-30',
|
||||||
|
hora_generacion = '08:01:00-05:00',
|
||||||
|
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
||||||
|
software_pin = SOFTWARE_PIN,
|
||||||
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_pago(fe.nomina.Pago(
|
||||||
|
forma=fe.nomina.FormaPago(
|
||||||
|
code='1',
|
||||||
|
),
|
||||||
|
metodo=fe.nomina.MetodoPago(
|
||||||
|
code='10'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit = NIT,
|
||||||
|
dv = DV,
|
||||||
|
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 = 'GONZALEZ',
|
||||||
|
segundo_apellido = '',
|
||||||
|
primer_nombre = 'JUAN',
|
||||||
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
|
direccion = 'CL 35C 102-17 BL 7 AP 101'
|
||||||
|
),
|
||||||
|
numero_documento = NIT,
|
||||||
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
|
code = '01'
|
||||||
|
),
|
||||||
|
salario_integral = False,
|
||||||
|
sueldo = fe.nomina.Amount(2400000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
|
dias_trabajados = 30,
|
||||||
|
sueldo_trabajado = fe.nomina.Amount(2400000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
|
porcentaje = fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(96000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||||
|
porcentaje=fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(96000)
|
||||||
|
))
|
||||||
|
return nomina
|
||||||
|
|
||||||
89
examples/habilitacion/N000003.xml
Normal file
89
examples/habilitacion/N000003.xml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<NominaIndividual xmlns:atd="urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2" xmlns="dian:gov:co:facturaelectronica:NominaIndividual" xmlns:fe="http://www.dian.gov.co/contratos/facturaelectronica/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cdt="urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1" xmlns:clm54217="urn:un:unece:uncefact:codelist:specification:54217:2001" xmlns:clmIANAMIMEMediaType="urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2" xmlns:sts="dian:gov:co:facturaelectronica:Structures-2-1" xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:sig="http://www.w3.org/2000/09/xmldsig#" SchemaLocation="" xsi:schemaLocation="dian:gov:co:facturaelectronica:NominaIndividual NominaIndividualElectronicaXSD.xsd"><ext:UBLExtensions><ext:UBLExtension><ext:ExtensionContent><ds:Signature Id="xmlsig-135b3cc1-1d1c-4ddd-a4c0-704a880a352b">
|
||||||
|
<ds:SignedInfo>
|
||||||
|
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||||
|
<ds:Reference Id="xmldsig-135b3cc1-1d1c-4ddd-a4c0-704a880a352b-ref0" URI="">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>mf3prH7SIB1Df0Z/nOPdRGG0DKXP8oCra41918zaCyg=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference Id="xmldsig-135b3cc1-1d1c-4ddd-a4c0-704a880a352b-ref1" URI="#xmldsig-135b3cc1-1d1c-4ddd-a4c0-704a880a352b-KeyInfo">
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>H3dF/siCNdG6iSy15jUQct1k4qswXBZToWJH6tsptpk=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference URI="#xmldsig-135b3cc1-1d1c-4ddd-a4c0-704a880a352b-signedprops" Type="http://uri.etsi.org/01903#SignedProperties">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>IqiqJKHTI0OAWva1xZ+ZOk9ooGkzEa4hReQCr4/W778=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
</ds:SignedInfo>
|
||||||
|
<ds:SignatureValue>Nv0nFvZ4Y3KIaPODEiOFgThDYb+DNKlJrRUAOrIxcNvtotpK7Y91JnYbUgFvl28b
|
||||||
|
Z5V/catUMyOclGDjPzslTBcHXExleb5eIgUB8URdNvdrB78iXFUOfPc+ESFomru8
|
||||||
|
jyPX9cZw24ZYBmQqqusvqIkf/tIARFGZ+7AzXkp28dBRFyWtgjESn60DIrFjm9x5
|
||||||
|
Pthv1K95gytjrrpwvdk77KN4uumlCbGoc2Pizbj+ufijbnxEPDS7fS7RR0Qv9uz/
|
||||||
|
2X7znR10TK8+gwMz7AVRYQi90ZbhOadxf3j+HVAlHtw+JHbrPSC+7xBOiPPStY6o
|
||||||
|
6TkQU+ZMpz2IUovjqREXow==</ds:SignatureValue>
|
||||||
|
<ds:KeyInfo Id="xmldsig-135b3cc1-1d1c-4ddd-a4c0-704a880a352b-KeyInfo">
|
||||||
|
<ds:X509Data>
|
||||||
|
<ds:X509Certificate>MIIH8TCCBdmgAwIBAgIIQxaPJd4YTlMwDQYJKoZIhvcNAQELBQAwgbYxIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMSYwJAYDVQQDEx1DQSBBTkRF
|
||||||
|
UyBTQ0QgUy5BLiBDbGFzZSBJSSB2MzEwMC4GA1UECxMnRGl2aXNpb24gZGUgY2Vy
|
||||||
|
dGlmaWNhY2lvbiBlbnRpZGFkIGZpbmFsMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDAS
|
||||||
|
BgNVBAcTC0JvZ290YSBELkMuMQswCQYDVQQGEwJDTzAeFw0yNDA1MTYwNTAwMDBa
|
||||||
|
Fw0yNTA1MTYwNDU5MDBaMIIBQDEtMCsGA1UECRMkVFYgNDYgQyA0MiBFU1RFIDc4
|
||||||
|
OSBDT1JSIFNBTlRBIEVMRU5BMSIwIAYJKoZIhvcNAQkBFhNiaWNpcGl6emFAZ21h
|
||||||
|
aWwuY29tMRowGAYDVQQDExFCSUNJIFBJWlpBIFMuQS5TLjETMBEGA1UEBRMKOTAx
|
||||||
|
NTc1NTI4MjE2MDQGA1UEDBMtRW1pc29yIEZhY3R1cmEgRWxlY3Ryb25pY2EgLSBQ
|
||||||
|
ZXJzb25hIEp1cmlkaWNhMTswOQYDVQQLEzJFbWl0aWRvIHBvciBBbmRlcyBTQ0Qg
|
||||||
|
QWMgMjYgNjkgQyAwMyBUb3JyZSBCIE9mIDcwMTEQMA4GA1UEChMHR0VSRU5URTES
|
||||||
|
MBAGA1UEBwwJTUVERUxMw41OMRIwEAYDVQQIEwlBTlRJT1FVSUExCzAJBgNVBAYT
|
||||||
|
AkNPMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5J1O+4ZedrSBUsb+
|
||||||
|
9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5/wra04OU57cS1/+/
|
||||||
|
yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/PbswnrKukFU2acxISwT
|
||||||
|
Lu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SIiqqPwHKh+6EDIoou
|
||||||
|
jo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891KBA9Yebdw7m/+ufu
|
||||||
|
+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWnspvDK97D8YG0MeifP
|
||||||
|
YveIPwIDAQABo4ICdDCCAnAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRA/iZp
|
||||||
|
RzInMtGsIcgu7M+N1TVo6DBvBggrBgEFBQcBAQRjMGEwNgYIKwYBBQUHMAKGKmh0
|
||||||
|
dHA6Ly9jZXJ0cy5hbmRlc3NjZC5jb20uY28vQ2xhc2VJSXYzLmNydDAnBggrBgEF
|
||||||
|
BQcwAYYbaHR0cDovL29jc3AuYW5kZXNzY2QuY29tLmNvMB4GA1UdEQQXMBWBE2Jp
|
||||||
|
Y2lwaXp6YUBnbWFpbC5jb20wggEjBgNVHSAEggEaMIIBFjCBwQYNKwYBBAGB9EgB
|
||||||
|
AgYIADCBrzCBrAYIKwYBBQUHAgIwgZ8MgZxMYSB1dGlsaXphY2nDs24gZGUgZXN0
|
||||||
|
ZSBjZXJ0aWZpY2FkbyBlc3TDoSBzdWpldGEgYSBsYSBQQyBkZSBGYWN0dXJhY2nD
|
||||||
|
s24gRWxlY3Ryw7NuaWNhIHkgRFBDIGVzdGFibGVjaWRhcyBwb3IgQW5kZXMgU0NE
|
||||||
|
LiBDw7NkaWdvIGRlIEFjcmVkaXRhY2nDs246IDE2LUVDRC0wMDQwUAYNKwYBBAGB
|
||||||
|
9EgBAQEKADA/MD0GCCsGAQUFBwIBFjFodHRwczovL3d3dy5hbmRlc3NjZC5jb20u
|
||||||
|
Y28vZG9jcy9EUENfQW5kZXNTQ0QucGRmMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
|
||||||
|
BgEFBQcDBDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLmFuZGVzc2NkLmNv
|
||||||
|
bS5jby9DbGFzZUlJdjMuY3JsMB0GA1UdDgQWBBRKPoh3BJM7SxEL0UXkSne2MyFO
|
||||||
|
jjAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQELBQADggIBAA6Zzor3kpJ6vNKv
|
||||||
|
TAeHaMfmJ/PaghQ1+Lab7Pwk+lsPsMETFu/IpEK5qij2bV54UNnqyLYOZtIbnWTG
|
||||||
|
qgT7QxQvy+/of/I3zzF+kH4/Lp2TSlHaDEb/airCZ3I2G23M9iaZzSwYuOsOaGwp
|
||||||
|
4ovkXlYwQ7FVNfIIoAq95m9cBAigb06bRIlVBVTQq44hQFQQG6aSIT7SSPtCwPhB
|
||||||
|
5CJzG09pmgbxizqN/yxdjWdfW6Av79dh6K4uQT++Vtyp5DuAkmfn0ehayrUbDLkH
|
||||||
|
9jQFF128U5pnOPfKWf22acXqQBapesUSV/HZUZ3PXoWeHWXcMdz0azxOEunS4+px
|
||||||
|
fs5UzInRAmEcYwJHqJT3irFz+J2RsZ0WnJHrTGqFoXniQQH8QbCHehDTGN7/v/v1
|
||||||
|
LQBr5PQBnSEWhmrQ9uFrwPyMMg3yd+L75TaHLZ0MTSVezAG52oM9jBiU5tYXkSio
|
||||||
|
EfPdIsGlG74BybULGSG2OlTINlblj/lj7pL67V+gY9EGN1zzNKL5sW4YXlXewa6K
|
||||||
|
dTpLmmzWzI8Cm+tOuuJDSHSwMjn525O+Z/oyKLjdQdyfg1KnZYwNZFpMmCwfP5nd
|
||||||
|
cm4F7Anzb9HX9ciluAxc6as9TsNoDDTSAGPuUr0QvXqXd9ZCgXdNzdFeiaYknLP5
|
||||||
|
hT4f5CoO2M8qcG+CH7HnkaOHrSuK</ds:X509Certificate>
|
||||||
|
</ds:X509Data>
|
||||||
|
<ds:KeyValue>
|
||||||
|
<ds:RSAKeyValue>
|
||||||
|
<ds:Modulus>5J1O+4ZedrSBUsb+9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5
|
||||||
|
/wra04OU57cS1/+/yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/Pbs
|
||||||
|
wnrKukFU2acxISwTLu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SI
|
||||||
|
iqqPwHKh+6EDIooujo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891
|
||||||
|
KBA9Yebdw7m/+ufu+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWns
|
||||||
|
pvDK97D8YG0MeifPYveIPw==</ds:Modulus>
|
||||||
|
<ds:Exponent>AQAB</ds:Exponent>
|
||||||
|
</ds:RSAKeyValue>
|
||||||
|
</ds:KeyValue>
|
||||||
|
</ds:KeyInfo>
|
||||||
|
<ds:Object><xades:QualifyingProperties Target="#xmlsig-135b3cc1-1d1c-4ddd-a4c0-704a880a352b" Id="XadesObjects"><xades:SignedProperties Id="xmldsig-135b3cc1-1d1c-4ddd-a4c0-704a880a352b-signedprops"><xades:SignedSignatureProperties><xades:SigningTime>2025-03-16T16:51:23.354553</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>YcIPspAVFcNg+B/galYrdCLYvLIEwFI4KWdSzcuupPY=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>C=CO, L=Bogota D.C., O=Andes SCD, OU=Division de certificacion entidad final, CN=CA ANDES SCD S.A. Clase II v3, OID.1.2.840.113549.1.9.1=info@andesscd.com.co</ds:X509IssuerName><ds:X509SerialNumber>4834208642831502931</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate><xades:SignaturePolicyIdentifier><xades:SignaturePolicyId><xades:SigPolicyId><xades:Identifier>https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf</xades:Identifier><xades:Description>Política de firma para facturas electrónicas de la República de Colombia.</xades:Description></xades:SigPolicyId><xades:SigPolicyHash><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>dMoMvtcG5aIzgYo0tIsSQeVJBDnUnfSOfBpxXrmor0Y=</ds:DigestValue></xades:SigPolicyHash></xades:SignaturePolicyId></xades:SignaturePolicyIdentifier><xades:SignerRole><xades:ClaimedRoles><xades:ClaimedRole>supplier</xades:ClaimedRole></xades:ClaimedRoles></xades:SignerRole></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object></ds:Signature></ext:ExtensionContent></ext:UBLExtension></ext:UBLExtensions><Novedad CUNENov="false">false</Novedad><Periodo FechaIngreso="2022-01-05" FechaLiquidacionInicio="2024-04-01" FechaLiquidacionFin="2024-04-30" TiempoLaborado="1" FechaGen="2024-04-30"/><NumeroSecuenciaXML Prefijo="N" Consecutivo="000003" Numero="N000003"/><LugarGeneracionXML Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Idioma="es"/><ProveedorXML NIT="901575528" DV="2" SoftwareID="100b0d10-0ca0-4ad4-a894-b704a568cbf3" RazonSocial="BICI PIZZA S.A.S" SoftwareSC="23bd3a3e925c4cdf6c4b99c1eda9e64846526241a263b86f3ffc9673d91020625812ef6abdcf93b4c326b7b65999d6c1"/><CodigoQR>https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey=beae68d136b80593b01b5cd7594bc86cc2f6ffd17d0238e5842e29ef6dfde62d26cb959764b6bf0943e73149596bfec0</CodigoQR><InformacionGeneral Version="V1.0: Documento Soporte de Pago de Nómina Electrónica" Ambiente="2" TipoXML="102" EncripCUNE="CUNE-SHA384" FechaGen="2024-04-30" HoraGen="08:01:00-05:00" PeriodoNomina="1" TipoMoneda="COP" TRM="0" CUNE="beae68d136b80593b01b5cd7594bc86cc2f6ffd17d0238e5842e29ef6dfde62d26cb959764b6bf0943e73149596bfec0"/><Empleador NIT="901575528" DV="2" Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Direccion="calle etrivial" RazonSocial="BICI PIZZA S.A.S"/><Trabajador TipoTrabajador="01" SubTipoTrabajador="00" AltoRiesgoPension="false" TipoDocumento="11" NumeroDocumento="901575528" PrimerApellido="GONZALEZ" SegundoApellido="" PrimerNombre="JUAN" LugarTrabajoPais="CO" LugarTrabajoDepartamentoEstado="05" LugarTrabajoMunicipioCiudad="05001" LugarTrabajoDireccion="CL 35C 102-17 BL 7 AP 101" SalarioIntegral="false" TipoContrato="1" Sueldo="2400000.0"/><Pago Forma="1" Metodo="10"/><FechasPagos><FechaPago>2024-04-30</FechaPago></FechasPagos><Devengados><Basico DiasTrabajados="30" SueldoTrabajado="2400000.00"/></Devengados><Deducciones><Salud Porcentaje="4.00" Deduccion="96000.0"/><FondoPension Porcentaje="4.00" Deduccion="96000.0"/></Deducciones><Redondeo>0</Redondeo><DevengadosTotal>2400000.00</DevengadosTotal><DeduccionesTotal>192000.00</DeduccionesTotal><ComprobanteTotal>2208000.00</ComprobanteTotal></NominaIndividual>
|
||||||
BIN
examples/habilitacion/N000003.zip
Normal file
BIN
examples/habilitacion/N000003.zip
Normal file
Binary file not shown.
123
examples/habilitacion/N000004.py
Normal file
123
examples/habilitacion/N000004.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
from facho import fe
|
||||||
|
|
||||||
|
SOFTWARE_PIN='20234'
|
||||||
|
SOFTWARE_ID='100b0d10-0ca0-4ad4-a894-b704a568cbf3'
|
||||||
|
NIT='901575528'
|
||||||
|
DV='2'
|
||||||
|
|
||||||
|
def extensions(nomina):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def nomina():
|
||||||
|
nomina = fe.nomina.DIANNominaIndividual()
|
||||||
|
|
||||||
|
nomina.asignar_fecha_pago('2024-04-30')
|
||||||
|
|
||||||
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
|
novedad=fe.nomina.Novedad(value='false'),
|
||||||
|
secuencia=fe.nomina.NumeroSecuencia(
|
||||||
|
prefijo='N',
|
||||||
|
consecutivo='000004'
|
||||||
|
),
|
||||||
|
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(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit=NIT,
|
||||||
|
dv=DV,
|
||||||
|
software_id=SOFTWARE_ID,
|
||||||
|
software_pin=SOFTWARE_PIN
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_periodo(fe.nomina.Periodo(
|
||||||
|
fecha_ingreso= '2022-09-05',
|
||||||
|
fecha_liquidacion_inicio='2024-04-01',
|
||||||
|
fecha_liquidacion_fin='2024-04-30',
|
||||||
|
fecha_generacion='2024-04-30'
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
|
fecha_generacion = '2024-04-30',
|
||||||
|
hora_generacion = '08:01:00-05:00',
|
||||||
|
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
||||||
|
software_pin = SOFTWARE_PIN,
|
||||||
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_pago(fe.nomina.Pago(
|
||||||
|
forma=fe.nomina.FormaPago(
|
||||||
|
code='1',
|
||||||
|
),
|
||||||
|
metodo=fe.nomina.MetodoPago(
|
||||||
|
code='10'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit = NIT,
|
||||||
|
dv = DV,
|
||||||
|
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 = 'GIRALDO',
|
||||||
|
segundo_apellido = '',
|
||||||
|
primer_nombre = 'VIVIANA',
|
||||||
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
|
direccion = 'CL 35C 102-17 BL 7 AP 101'
|
||||||
|
),
|
||||||
|
numero_documento = NIT,
|
||||||
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
|
code = '01'
|
||||||
|
),
|
||||||
|
salario_integral = False,
|
||||||
|
sueldo = fe.nomina.Amount(1160000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
|
dias_trabajados = 30,
|
||||||
|
sueldo_trabajado = fe.nomina.Amount(1160000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
|
porcentaje = fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(46400)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||||
|
porcentaje=fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(46400)
|
||||||
|
))
|
||||||
|
return nomina
|
||||||
|
|
||||||
89
examples/habilitacion/N000004.xml
Normal file
89
examples/habilitacion/N000004.xml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<NominaIndividual xmlns:atd="urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2" xmlns="dian:gov:co:facturaelectronica:NominaIndividual" xmlns:fe="http://www.dian.gov.co/contratos/facturaelectronica/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cdt="urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1" xmlns:clm54217="urn:un:unece:uncefact:codelist:specification:54217:2001" xmlns:clmIANAMIMEMediaType="urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2" xmlns:sts="dian:gov:co:facturaelectronica:Structures-2-1" xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:sig="http://www.w3.org/2000/09/xmldsig#" SchemaLocation="" xsi:schemaLocation="dian:gov:co:facturaelectronica:NominaIndividual NominaIndividualElectronicaXSD.xsd"><ext:UBLExtensions><ext:UBLExtension><ext:ExtensionContent><ds:Signature Id="xmlsig-bf43fedd-6780-438f-afe3-ac062d8b8072">
|
||||||
|
<ds:SignedInfo>
|
||||||
|
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||||
|
<ds:Reference Id="xmldsig-bf43fedd-6780-438f-afe3-ac062d8b8072-ref0" URI="">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>ZAE71pLQXXnN5+540pnkxH5ALNBQcecMdLWFKTKby0g=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference Id="xmldsig-bf43fedd-6780-438f-afe3-ac062d8b8072-ref1" URI="#xmldsig-bf43fedd-6780-438f-afe3-ac062d8b8072-KeyInfo">
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>kNyh65TH4KfF6wqRoy1duEawgkvOlr2rYLCNfdTfK1c=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference URI="#xmldsig-bf43fedd-6780-438f-afe3-ac062d8b8072-signedprops" Type="http://uri.etsi.org/01903#SignedProperties">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>BoPBi5C0tXfV04cf74M4jktBxf9eVsXk5IWqGdeOSHw=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
</ds:SignedInfo>
|
||||||
|
<ds:SignatureValue>pw5WDlbd4GhnSAJKlTEDjsb1+VAVtyyXWA/isvGz4LHY5n1Fm4hiN7fD3JIrfOBj
|
||||||
|
z/tUfROLzbbywUnVklfaDri6txZlFFwa9SY8MO38bgE0HUxGq5khb/4uzktGRInp
|
||||||
|
H3i0TG5i42YB83PQItSLiEgPWqGVolj5sWfUqD81Ck4CvgtKuZgnn9JPLgP0sjjT
|
||||||
|
BUjKcMt4K+ZLvXumehKKCzEbtoaa5DHKUrpuCU2giGMMPElwaTulFA5kNLBnAk2n
|
||||||
|
HBCiIq+YZ2C3BqE+WQptcQDIObmEnRURvvUTB64gCh4Tigmq6vnv/dMPWmQvohmp
|
||||||
|
ETIZDwU0/xdGcUK7Ujyl4g==</ds:SignatureValue>
|
||||||
|
<ds:KeyInfo Id="xmldsig-bf43fedd-6780-438f-afe3-ac062d8b8072-KeyInfo">
|
||||||
|
<ds:X509Data>
|
||||||
|
<ds:X509Certificate>MIIH8TCCBdmgAwIBAgIIQxaPJd4YTlMwDQYJKoZIhvcNAQELBQAwgbYxIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMSYwJAYDVQQDEx1DQSBBTkRF
|
||||||
|
UyBTQ0QgUy5BLiBDbGFzZSBJSSB2MzEwMC4GA1UECxMnRGl2aXNpb24gZGUgY2Vy
|
||||||
|
dGlmaWNhY2lvbiBlbnRpZGFkIGZpbmFsMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDAS
|
||||||
|
BgNVBAcTC0JvZ290YSBELkMuMQswCQYDVQQGEwJDTzAeFw0yNDA1MTYwNTAwMDBa
|
||||||
|
Fw0yNTA1MTYwNDU5MDBaMIIBQDEtMCsGA1UECRMkVFYgNDYgQyA0MiBFU1RFIDc4
|
||||||
|
OSBDT1JSIFNBTlRBIEVMRU5BMSIwIAYJKoZIhvcNAQkBFhNiaWNpcGl6emFAZ21h
|
||||||
|
aWwuY29tMRowGAYDVQQDExFCSUNJIFBJWlpBIFMuQS5TLjETMBEGA1UEBRMKOTAx
|
||||||
|
NTc1NTI4MjE2MDQGA1UEDBMtRW1pc29yIEZhY3R1cmEgRWxlY3Ryb25pY2EgLSBQ
|
||||||
|
ZXJzb25hIEp1cmlkaWNhMTswOQYDVQQLEzJFbWl0aWRvIHBvciBBbmRlcyBTQ0Qg
|
||||||
|
QWMgMjYgNjkgQyAwMyBUb3JyZSBCIE9mIDcwMTEQMA4GA1UEChMHR0VSRU5URTES
|
||||||
|
MBAGA1UEBwwJTUVERUxMw41OMRIwEAYDVQQIEwlBTlRJT1FVSUExCzAJBgNVBAYT
|
||||||
|
AkNPMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5J1O+4ZedrSBUsb+
|
||||||
|
9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5/wra04OU57cS1/+/
|
||||||
|
yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/PbswnrKukFU2acxISwT
|
||||||
|
Lu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SIiqqPwHKh+6EDIoou
|
||||||
|
jo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891KBA9Yebdw7m/+ufu
|
||||||
|
+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWnspvDK97D8YG0MeifP
|
||||||
|
YveIPwIDAQABo4ICdDCCAnAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRA/iZp
|
||||||
|
RzInMtGsIcgu7M+N1TVo6DBvBggrBgEFBQcBAQRjMGEwNgYIKwYBBQUHMAKGKmh0
|
||||||
|
dHA6Ly9jZXJ0cy5hbmRlc3NjZC5jb20uY28vQ2xhc2VJSXYzLmNydDAnBggrBgEF
|
||||||
|
BQcwAYYbaHR0cDovL29jc3AuYW5kZXNzY2QuY29tLmNvMB4GA1UdEQQXMBWBE2Jp
|
||||||
|
Y2lwaXp6YUBnbWFpbC5jb20wggEjBgNVHSAEggEaMIIBFjCBwQYNKwYBBAGB9EgB
|
||||||
|
AgYIADCBrzCBrAYIKwYBBQUHAgIwgZ8MgZxMYSB1dGlsaXphY2nDs24gZGUgZXN0
|
||||||
|
ZSBjZXJ0aWZpY2FkbyBlc3TDoSBzdWpldGEgYSBsYSBQQyBkZSBGYWN0dXJhY2nD
|
||||||
|
s24gRWxlY3Ryw7NuaWNhIHkgRFBDIGVzdGFibGVjaWRhcyBwb3IgQW5kZXMgU0NE
|
||||||
|
LiBDw7NkaWdvIGRlIEFjcmVkaXRhY2nDs246IDE2LUVDRC0wMDQwUAYNKwYBBAGB
|
||||||
|
9EgBAQEKADA/MD0GCCsGAQUFBwIBFjFodHRwczovL3d3dy5hbmRlc3NjZC5jb20u
|
||||||
|
Y28vZG9jcy9EUENfQW5kZXNTQ0QucGRmMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
|
||||||
|
BgEFBQcDBDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLmFuZGVzc2NkLmNv
|
||||||
|
bS5jby9DbGFzZUlJdjMuY3JsMB0GA1UdDgQWBBRKPoh3BJM7SxEL0UXkSne2MyFO
|
||||||
|
jjAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQELBQADggIBAA6Zzor3kpJ6vNKv
|
||||||
|
TAeHaMfmJ/PaghQ1+Lab7Pwk+lsPsMETFu/IpEK5qij2bV54UNnqyLYOZtIbnWTG
|
||||||
|
qgT7QxQvy+/of/I3zzF+kH4/Lp2TSlHaDEb/airCZ3I2G23M9iaZzSwYuOsOaGwp
|
||||||
|
4ovkXlYwQ7FVNfIIoAq95m9cBAigb06bRIlVBVTQq44hQFQQG6aSIT7SSPtCwPhB
|
||||||
|
5CJzG09pmgbxizqN/yxdjWdfW6Av79dh6K4uQT++Vtyp5DuAkmfn0ehayrUbDLkH
|
||||||
|
9jQFF128U5pnOPfKWf22acXqQBapesUSV/HZUZ3PXoWeHWXcMdz0azxOEunS4+px
|
||||||
|
fs5UzInRAmEcYwJHqJT3irFz+J2RsZ0WnJHrTGqFoXniQQH8QbCHehDTGN7/v/v1
|
||||||
|
LQBr5PQBnSEWhmrQ9uFrwPyMMg3yd+L75TaHLZ0MTSVezAG52oM9jBiU5tYXkSio
|
||||||
|
EfPdIsGlG74BybULGSG2OlTINlblj/lj7pL67V+gY9EGN1zzNKL5sW4YXlXewa6K
|
||||||
|
dTpLmmzWzI8Cm+tOuuJDSHSwMjn525O+Z/oyKLjdQdyfg1KnZYwNZFpMmCwfP5nd
|
||||||
|
cm4F7Anzb9HX9ciluAxc6as9TsNoDDTSAGPuUr0QvXqXd9ZCgXdNzdFeiaYknLP5
|
||||||
|
hT4f5CoO2M8qcG+CH7HnkaOHrSuK</ds:X509Certificate>
|
||||||
|
</ds:X509Data>
|
||||||
|
<ds:KeyValue>
|
||||||
|
<ds:RSAKeyValue>
|
||||||
|
<ds:Modulus>5J1O+4ZedrSBUsb+9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5
|
||||||
|
/wra04OU57cS1/+/yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/Pbs
|
||||||
|
wnrKukFU2acxISwTLu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SI
|
||||||
|
iqqPwHKh+6EDIooujo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891
|
||||||
|
KBA9Yebdw7m/+ufu+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWns
|
||||||
|
pvDK97D8YG0MeifPYveIPw==</ds:Modulus>
|
||||||
|
<ds:Exponent>AQAB</ds:Exponent>
|
||||||
|
</ds:RSAKeyValue>
|
||||||
|
</ds:KeyValue>
|
||||||
|
</ds:KeyInfo>
|
||||||
|
<ds:Object><xades:QualifyingProperties Target="#xmlsig-bf43fedd-6780-438f-afe3-ac062d8b8072" Id="XadesObjects"><xades:SignedProperties Id="xmldsig-bf43fedd-6780-438f-afe3-ac062d8b8072-signedprops"><xades:SignedSignatureProperties><xades:SigningTime>2025-03-16T16:51:26.699846</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>YcIPspAVFcNg+B/galYrdCLYvLIEwFI4KWdSzcuupPY=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>C=CO, L=Bogota D.C., O=Andes SCD, OU=Division de certificacion entidad final, CN=CA ANDES SCD S.A. Clase II v3, OID.1.2.840.113549.1.9.1=info@andesscd.com.co</ds:X509IssuerName><ds:X509SerialNumber>4834208642831502931</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate><xades:SignaturePolicyIdentifier><xades:SignaturePolicyId><xades:SigPolicyId><xades:Identifier>https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf</xades:Identifier><xades:Description>Política de firma para facturas electrónicas de la República de Colombia.</xades:Description></xades:SigPolicyId><xades:SigPolicyHash><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>dMoMvtcG5aIzgYo0tIsSQeVJBDnUnfSOfBpxXrmor0Y=</ds:DigestValue></xades:SigPolicyHash></xades:SignaturePolicyId></xades:SignaturePolicyIdentifier><xades:SignerRole><xades:ClaimedRoles><xades:ClaimedRole>supplier</xades:ClaimedRole></xades:ClaimedRoles></xades:SignerRole></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object></ds:Signature></ext:ExtensionContent></ext:UBLExtension></ext:UBLExtensions><Novedad CUNENov="false">false</Novedad><Periodo FechaIngreso="2022-09-05" FechaLiquidacionInicio="2024-04-01" FechaLiquidacionFin="2024-04-30" TiempoLaborado="1" FechaGen="2024-04-30"/><NumeroSecuenciaXML Prefijo="N" Consecutivo="000004" Numero="N000004"/><LugarGeneracionXML Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Idioma="es"/><ProveedorXML NIT="901575528" DV="2" SoftwareID="100b0d10-0ca0-4ad4-a894-b704a568cbf3" RazonSocial="BICI PIZZA S.A.S" SoftwareSC="61d2d18fc61f70cff4f5c5c2a5e17e5c904bf42179a8118242e994b40c22ef203741568ee51d94b81a7fbde4ea6a79aa"/><CodigoQR>https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey=40d20d7af2d7ee471909e62fcb4beef7de82494e6c8df4e8349ca33a1246dea601b4cc9035e18972e853ecd435799eaa</CodigoQR><InformacionGeneral Version="V1.0: Documento Soporte de Pago de Nómina Electrónica" Ambiente="2" TipoXML="102" EncripCUNE="CUNE-SHA384" FechaGen="2024-04-30" HoraGen="08:01:00-05:00" PeriodoNomina="1" TipoMoneda="COP" TRM="0" CUNE="40d20d7af2d7ee471909e62fcb4beef7de82494e6c8df4e8349ca33a1246dea601b4cc9035e18972e853ecd435799eaa"/><Empleador NIT="901575528" DV="2" Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Direccion="calle etrivial" RazonSocial="BICI PIZZA S.A.S"/><Trabajador TipoTrabajador="01" SubTipoTrabajador="00" AltoRiesgoPension="false" TipoDocumento="11" NumeroDocumento="901575528" PrimerApellido="GIRALDO" SegundoApellido="" PrimerNombre="VIVIANA" LugarTrabajoPais="CO" LugarTrabajoDepartamentoEstado="05" LugarTrabajoMunicipioCiudad="05001" LugarTrabajoDireccion="CL 35C 102-17 BL 7 AP 101" SalarioIntegral="false" TipoContrato="1" Sueldo="1160000.0"/><Pago Forma="1" Metodo="10"/><FechasPagos><FechaPago>2024-04-30</FechaPago></FechasPagos><Devengados><Basico DiasTrabajados="30" SueldoTrabajado="1160000.00"/></Devengados><Deducciones><Salud Porcentaje="4.00" Deduccion="46400.0"/><FondoPension Porcentaje="4.00" Deduccion="46400.0"/></Deducciones><Redondeo>0</Redondeo><DevengadosTotal>1160000.00</DevengadosTotal><DeduccionesTotal>92800.00</DeduccionesTotal><ComprobanteTotal>1067200.00</ComprobanteTotal></NominaIndividual>
|
||||||
BIN
examples/habilitacion/N000004.zip
Normal file
BIN
examples/habilitacion/N000004.zip
Normal file
Binary file not shown.
@@ -1,127 +1,109 @@
|
|||||||
# importar libreria de modelos
|
# importar libreria de modelos
|
||||||
from facho import fe, form_xml
|
|
||||||
import facho.fe.form as form
|
import facho.fe.form as form
|
||||||
import datetime
|
import facho.fe.form_xml
|
||||||
|
|
||||||
PRIVATE_KEY_PATH = 'ruta a mi llave privada'
|
|
||||||
PRIVATE_PASSPHRASE = 'clave de la llave privada'
|
|
||||||
|
|
||||||
|
PRIVATE_KEY_PATH='ruta a mi llave privada'
|
||||||
|
PRIVATE_PASSPHRASE='clave de la llave privada'
|
||||||
|
|
||||||
# consultar las extensiones necesarias
|
# consultar las extensiones necesarias
|
||||||
def extensions(inv):
|
def extensions(inv):
|
||||||
security_code = fe.DianXMLExtensionSoftwareSecurityCode(
|
security_code = fe.DianXMLExtensionSoftwareSecurityCode('id software', 'pin', inv.invoice_ident)
|
||||||
'id software', 'pin', inv.invoice_ident)
|
|
||||||
authorization_provider = fe.DianXMLExtensionAuthorizationProvider()
|
authorization_provider = fe.DianXMLExtensionAuthorizationProvider()
|
||||||
cufe = fe.DianXMLExtensionCUFE(
|
cufe = fe.DianXMLExtensionCUFE(inv, fe.DianXMLExtensionCUFE.AMBIENTE_PRUEBAS,
|
||||||
inv, fe.DianXMLExtensionCUFE.AMBIENTE_PRUEBAS,
|
'clave tecnica')
|
||||||
'clave tecnica')
|
|
||||||
nit = form.PartyIdentification('nit', '5', '31')
|
nit = form.PartyIdentification('nit', '5', '31')
|
||||||
software_provider = fe.DianXMLExtensionSoftwareProvider(
|
software_provider = fe.DianXMLExtensionSoftwareProvider(nit, nit.dv, 'id software')
|
||||||
nit, nit.dv, 'id software')
|
inv_authorization = fe.DianXMLExtensionInvoiceAuthorization('invoice autorization',
|
||||||
inv_authorization = fe.DianXMLExtensionInvoiceAuthorization(
|
datetime(2019, 1, 19),
|
||||||
'invoice autorization',
|
datetime(2030, 1, 19),
|
||||||
datetime(2019, 1, 19),
|
'SETP', 990000001, 995000000)
|
||||||
datetime(2030, 1, 19),
|
return [security_code, authorization_provider, cufe, software_provider, inv_authorization]
|
||||||
'SETP', 990000001, 995000000)
|
|
||||||
return [
|
|
||||||
security_code,
|
|
||||||
authorization_provider,
|
|
||||||
cufe, software_provider,
|
|
||||||
inv_authorization
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# generar documento desde modelo a ruta indicada
|
# generar documento desde modelo a ruta indicada
|
||||||
def generate_document(invoice, filepath):
|
def generate_document(invoice, filepath):
|
||||||
xml = form_xml.DIANInvoiceXML(invoice)
|
xml = form_xml.DIANInvoiceXML(invoice)
|
||||||
for extension in extensions(invoice):
|
for extension in extensions(invoice):
|
||||||
xml.add_extension(extension)
|
xml.add_extension(extension)
|
||||||
form_xml.utils.DIANWriteSigned(
|
form_xml.utils.DIANWriteSigned(xml, filepath, PRIVATE_KEY_PATH, PRIVATE_PASSPHRASE, True)
|
||||||
xml, filepath, PRIVATE_KEY_PATH, PRIVATE_PASSPHRASE, True)
|
|
||||||
|
|
||||||
|
|
||||||
# Modelars las facturas
|
# Modelars las facturas
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
# factura de venta nacional
|
# factura de venta nacional
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
|
|
||||||
# asignar periodo de facturacion
|
# asignar periodo de facturacion
|
||||||
inv.set_period(datetime.now(), datetime.now())
|
inv.set_period(datetime.now(), datetime.now())
|
||||||
|
|
||||||
# asignar fecha de emision de la factura
|
# asignar fecha de emision de la factura
|
||||||
|
|
||||||
inv.set_issue(datetime.now())
|
inv.set_issue(datetime.now())
|
||||||
# asignar prefijo y numero del documento
|
# asignar prefijo y numero del documento
|
||||||
|
|
||||||
inv.set_ident('SETP990003033')
|
inv.set_ident('SETP990003033')
|
||||||
# asignar tipo de operacion ver DIAN:6.1.5
|
# asignar tipo de operacion ver DIAN:6.1.5
|
||||||
inv.set_operation_type('10')
|
inv.set_operation_type('10')
|
||||||
|
|
||||||
# asignar proveedor
|
# asignar proveedor
|
||||||
inv.set_supplier(form.Party(
|
inv.set_supplier(form.Party(
|
||||||
legal_name='FACHOSOS',
|
legal_name = 'FACHO SOS',
|
||||||
name='FACHOSOS',
|
name = 'FACHO SOS',
|
||||||
ident=form.PartyIdentification('900579212', '5', '31'),
|
ident = form.PartyIdentification('900579212', '5', '31'),
|
||||||
# obligaciones del contribuyente ver DIAN:FAK26
|
# obligaciones del contribuyente ver DIAN:FAK26
|
||||||
responsability_code=form.Responsability(['ZZ', 'O-09', 'O-14', 'O-48']),
|
responsability_code = form.Responsability(['O-07', 'O-09', 'O-14', 'O-48']),
|
||||||
# ver DIAN:FAJ28
|
# ver DIAN:FAJ28
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
# tipo de organizacion juridica ver DIAN:6.2.3
|
# tipo de organizacion juridica ver DIAN:6.2.3
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
email="sdds@sd.com",
|
email = "sdds@sd.com",
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
name='',
|
name = '',
|
||||||
street='',
|
street = '',
|
||||||
city=form.City('05001', 'Medellín'),
|
city = form.City('05001', 'Medellín'),
|
||||||
country=form.Country('CO', 'Colombia'),
|
country = form.Country('CO', 'Colombia'),
|
||||||
countrysubentity=form.CountrySubentity('05', 'Antioquia'))
|
countrysubentity = form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
|
|
||||||
inv.set_customer(form.Party(
|
inv.set_customer(form.Party(
|
||||||
legal_name='facho-customer',
|
legal_name = 'facho-customer',
|
||||||
name='facho-customer',
|
name = 'facho-customer',
|
||||||
ident=form.PartyIdentification('999999999', '', '13'),
|
ident = form.PartyIdentification('999999999', '', '13'),
|
||||||
responsability_code=form.Responsability(['R-99-PN']),
|
responsability_code = form.Responsability(['R-99-PN']),
|
||||||
responsability_regime_code='49',
|
responsability_regime_code = '49',
|
||||||
organization_code='2',
|
organization_code = '2',
|
||||||
email="sdds@sd.com",
|
email = "sdds@sd.com",
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
name='',
|
name = '',
|
||||||
street='',
|
street = '',
|
||||||
city=form.City('05001', 'Medellín'),
|
city = form.City('05001', 'Medellín'),
|
||||||
country=form.Country('CO', 'Colombia'),
|
country = form.Country('CO', 'Colombia'),
|
||||||
countrysubentity=form.CountrySubentity('05', 'Antioquia'))
|
countrysubentity = form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
# asignar metodo de pago
|
# asignar metodo de pago
|
||||||
inv.set_payment_mean(form.PaymentMean(
|
inv.set_payment_mean(form.PaymentMean(
|
||||||
# metodo de pago ver DIAN:3.4.1
|
# metodo de pago ver DIAN:3.4.1
|
||||||
id='1',
|
id = '1',
|
||||||
# codigo correspondiente al medio de pago ver DIAN:3.4.2
|
# codigo correspondiente al medio de pago ver DIAN:3.4.2
|
||||||
code='10',
|
code = '10',
|
||||||
# fecha de vencimiento de la factura
|
# fecha de vencimiento de la factura
|
||||||
due_at=datetime.now(),
|
due_at = datetime.now(),
|
||||||
|
|
||||||
# identificador numerico
|
# identificador numerico
|
||||||
payment_id='1'
|
payment_id = '1'
|
||||||
))
|
))
|
||||||
# adicionar una linea al documento
|
# adicionar una linea al documento
|
||||||
inv.add_invoice_line(form.InvoiceLine(
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
description='producto facho',
|
description = 'producto facho',
|
||||||
# item general de codigo 999
|
# item general de codigo 999
|
||||||
item=form.StandardItem('test', 9999),
|
item = form.StandardItem('test', 9999),
|
||||||
price=form.Price(
|
price = form.Price(
|
||||||
# precio base del tiem
|
# precio base del tiem
|
||||||
amount=form.Amount(100.00),
|
amount = form.Amount(100.00),
|
||||||
# ver DIAN:6.3.5.1
|
# ver DIAN:6.3.5.1
|
||||||
type_code='01',
|
type_code = '01',
|
||||||
type='x'
|
type = 'x'
|
||||||
),
|
),
|
||||||
tax=form.TaxTotal(
|
tax = form.TaxTotal(
|
||||||
subtotals=[
|
subtotals = [
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
percent=19.00,
|
percent = 19.00,
|
||||||
)]
|
)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
<cac:PartyTaxScheme>
|
<cac:PartyTaxScheme>
|
||||||
<cbc:RegistrationName>NEUROTEC TECNOLOGIA S.A.S</cbc:RegistrationName>
|
<cbc:RegistrationName>NEUROTEC TECNOLOGIA S.A.S</cbc:RegistrationName>
|
||||||
<cbc:CompanyID schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195" schemeID="5" schemeName="31">900579212</cbc:CompanyID>
|
<cbc:CompanyID schemeAgencyName="CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)" schemeAgencyID="195" schemeID="5" schemeName="31">900579212</cbc:CompanyID>
|
||||||
<cbc:TaxLevelCode listName="48">ZZ;O-09;O-14;O-48</cbc:TaxLevelCode>
|
<cbc:TaxLevelCode listName="48">O-07;O-09;O-14;O-48</cbc:TaxLevelCode>
|
||||||
<cac:TaxScheme/>
|
<cac:TaxScheme/>
|
||||||
</cac:PartyTaxScheme>
|
</cac:PartyTaxScheme>
|
||||||
<cac:Contact>
|
<cac:Contact>
|
||||||
|
|||||||
446
facho/cli.py
446
facho/cli.py
@@ -1,37 +1,39 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import sys
|
||||||
|
import base64
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
import logging.config
|
import logging.config
|
||||||
|
|
||||||
logging.config.dictConfig(
|
logging.config.dictConfig({
|
||||||
{
|
'version': 1,
|
||||||
"version": 1,
|
'formatters': {
|
||||||
"formatters": {"verbose": {"format": "%(name)s: %(message)s"}},
|
'verbose': {
|
||||||
"handlers": {
|
'format': '%(name)s: %(message)s'
|
||||||
"console": {
|
}
|
||||||
"level": "DEBUG",
|
},
|
||||||
"class": "logging.StreamHandler",
|
'handlers': {
|
||||||
"formatter": "verbose",
|
'console': {
|
||||||
},
|
'level': 'DEBUG',
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
'formatter': 'verbose',
|
||||||
},
|
},
|
||||||
"loggers": {
|
},
|
||||||
"zeep.transports": {
|
'loggers': {
|
||||||
"level": "DEBUG",
|
'zeep.transports': {
|
||||||
"propagate": True,
|
'level': 'DEBUG',
|
||||||
"handlers": ["console"],
|
'propagate': True,
|
||||||
},
|
'handlers': ['console'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
|
|
||||||
def disable_ssl():
|
def disable_ssl():
|
||||||
# MACHETE
|
# MACHETE
|
||||||
import ssl
|
import ssl
|
||||||
|
if getattr(ssl, '_create_unverified_context', None):
|
||||||
if getattr(ssl, "_create_unverified_context", None):
|
|
||||||
ssl._create_default_https_context = ssl._create_unverified_context
|
ssl._create_default_https_context = ssl._create_unverified_context
|
||||||
warnings.warn("be sure!! ssl disable")
|
warnings.warn("be sure!! ssl disable")
|
||||||
else:
|
else:
|
||||||
@@ -39,122 +41,99 @@ def disable_ssl():
|
|||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--nit", required=True)
|
@click.option('--nit', required=True)
|
||||||
@click.option("--nit-proveedor", required=True)
|
@click.option('--nit-proveedor', required=True)
|
||||||
@click.option("--id-software", required=True)
|
@click.option('--id-software', required=True)
|
||||||
@click.option("--username", required=True)
|
@click.option('--username', required=True)
|
||||||
@click.option("--password", required=True)
|
@click.option('--password', required=True)
|
||||||
def consultaResolucionesFacturacion(
|
def consultaResolucionesFacturacion(nit, nit_proveedor, id_software, username, password):
|
||||||
nit, nit_proveedor, id_software, username, password
|
|
||||||
):
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
client_dian = dian.DianClient(username,
|
||||||
client_dian = dian.DianClient(username, password)
|
password)
|
||||||
resp = client_dian.request(
|
resp = client_dian.request(dian.ConsultaResolucionesFacturacionPeticion(
|
||||||
dian.ConsultaResolucionesFacturacionPeticion(
|
nit, nit_proveedor, id_software
|
||||||
nit, nit_proveedor, id_software
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
print(str(resp))
|
print(str(resp))
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", required=True)
|
@click.option('--private-key', required=True)
|
||||||
@click.option("--public-key", required=True)
|
@click.option('--public-key', required=True)
|
||||||
@click.option("--habilitacion/--produccion", default=False)
|
@click.option('--habilitacion/--produccion', default=False)
|
||||||
@click.option("--password")
|
@click.option('--password')
|
||||||
@click.option("--test-setid", required=True)
|
@click.option('--test-setid', required=True)
|
||||||
@click.argument("filename", required=True)
|
@click.argument('filename', required=True)
|
||||||
@click.argument("zipfile", type=click.Path(exists=True))
|
@click.argument('zipfile', type=click.Path(exists=True))
|
||||||
def soap_send_test_set_async(
|
def soap_send_test_set_async(private_key, public_key, habilitacion, password, test_setid, filename, zipfile):
|
||||||
private_key,
|
|
||||||
public_key,
|
|
||||||
habilitacion,
|
|
||||||
password,
|
|
||||||
test_setid,
|
|
||||||
filename,
|
|
||||||
zipfile,
|
|
||||||
):
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(
|
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
||||||
private_key, public_key, password=password
|
|
||||||
)
|
|
||||||
req = dian.SendTestSetAsync
|
req = dian.SendTestSetAsync
|
||||||
if habilitacion:
|
if habilitacion:
|
||||||
req = dian.Habilitacion.SendTestSetAsync
|
req = dian.Habilitacion.SendTestSetAsync
|
||||||
resp = client.request(
|
resp = client.request(req(
|
||||||
req(
|
filename,
|
||||||
filename,
|
open(zipfile, 'rb').read(),
|
||||||
open(zipfile, "rb").read(),
|
test_setid,
|
||||||
test_setid,
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
print(resp)
|
print(resp)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", required=True)
|
@click.option('--private-key', required=True)
|
||||||
@click.option("--public-key", required=True)
|
@click.option('--public-key', required=True)
|
||||||
@click.option("--habilitacion/--produccion", default=False)
|
@click.option('--habilitacion/--produccion', default=False)
|
||||||
@click.option("--password")
|
@click.option('--password')
|
||||||
@click.argument("filename", required=True)
|
@click.argument('filename', required=True)
|
||||||
@click.argument("zipfile", type=click.Path(exists=True))
|
@click.argument('zipfile', type=click.Path(exists=True))
|
||||||
def soap_send_bill_async(
|
def soap_send_bill_async(private_key, public_key, habilitacion, password, filename, zipfile):
|
||||||
private_key, public_key, habilitacion, password, filename, zipfile
|
|
||||||
):
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(
|
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
||||||
private_key, public_key, password=password
|
|
||||||
)
|
|
||||||
req = dian.SendBillAsync
|
req = dian.SendBillAsync
|
||||||
if habilitacion:
|
if habilitacion:
|
||||||
req = dian.Habilitacion.SendBillAsync
|
req = dian.Habilitacion.SendBillAsync
|
||||||
resp = client.request(req(filename, open(zipfile, "rb").read()))
|
resp = client.request(req(
|
||||||
|
filename,
|
||||||
|
open(zipfile, 'rb').read()
|
||||||
|
))
|
||||||
print(resp)
|
print(resp)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", required=True)
|
@click.option('--private-key', required=True)
|
||||||
@click.option("--public-key", required=True)
|
@click.option('--public-key', required=True)
|
||||||
@click.option("--habilitacion/--produccion", default=False)
|
@click.option('--habilitacion/--produccion', default=False)
|
||||||
@click.option("--password")
|
@click.option('--password')
|
||||||
@click.argument("filename", required=True)
|
@click.argument('filename', required=True)
|
||||||
@click.argument("zipfile", type=click.Path(exists=True))
|
@click.argument('zipfile', type=click.Path(exists=True))
|
||||||
def soap_send_bill_sync(
|
def soap_send_bill_sync(private_key, public_key, habilitacion, password, filename, zipfile):
|
||||||
private_key, public_key, habilitacion, password, filename, zipfile
|
|
||||||
):
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(
|
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
||||||
private_key, public_key, password=password
|
|
||||||
)
|
|
||||||
req = dian.SendBillSync
|
req = dian.SendBillSync
|
||||||
if habilitacion:
|
if habilitacion:
|
||||||
req = dian.Habilitacion.SendBillSync
|
req = dian.Habilitacion.SendBillSync
|
||||||
resp = client.request(req(filename, open(zipfile, "rb").read()))
|
resp = client.request(req(
|
||||||
|
filename,
|
||||||
|
open(zipfile, 'rb').read()
|
||||||
|
))
|
||||||
print(resp)
|
print(resp)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", required=True)
|
@click.option('--private-key', required=True)
|
||||||
@click.option("--public-key", required=True)
|
@click.option('--public-key', required=True)
|
||||||
@click.option("--habilitacion/--produccion", default=False)
|
@click.option('--habilitacion/--produccion', default=False)
|
||||||
@click.option("--password")
|
@click.option('--password')
|
||||||
@click.option("--track-id", required=True)
|
@click.option('--track-id', required=True)
|
||||||
def soap_get_status_zip(
|
def soap_get_status_zip(private_key, public_key, habilitacion, password, track_id):
|
||||||
private_key, public_key, habilitacion, password, track_id
|
|
||||||
):
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(
|
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
||||||
private_key, public_key, password=password
|
|
||||||
)
|
|
||||||
req = dian.GetStatusZip
|
req = dian.GetStatusZip
|
||||||
if habilitacion:
|
if habilitacion:
|
||||||
req = dian.Habilitacion.GetStatusZip
|
req = dian.Habilitacion.GetStatusZip
|
||||||
resp = client.request(req(trackId=track_id))
|
resp = client.request(req(
|
||||||
|
trackId = track_id
|
||||||
|
))
|
||||||
|
|
||||||
print("StatusCode:", resp.StatusCode)
|
print("StatusCode:", resp.StatusCode)
|
||||||
print("StatusDescription:", resp.StatusDescription)
|
print("StatusDescription:", resp.StatusDescription)
|
||||||
@@ -164,78 +143,68 @@ def soap_get_status_zip(
|
|||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", required=True)
|
@click.option('--private-key', required=True)
|
||||||
@click.option("--public-key", required=True)
|
@click.option('--public-key', required=True)
|
||||||
@click.option("--habilitacion/--produccion", default=False)
|
@click.option('--habilitacion/--produccion', default=False)
|
||||||
@click.option("--password")
|
@click.option('--password')
|
||||||
@click.option("--track-id", required=True)
|
@click.option('--track-id', required=True)
|
||||||
def soap_get_status(
|
def soap_get_status(private_key, public_key, habilitacion, password, track_id):
|
||||||
private_key, public_key, habilitacion, password, track_id
|
|
||||||
):
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(
|
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
||||||
private_key, public_key, password=password
|
|
||||||
)
|
|
||||||
req = dian.GetStatus
|
req = dian.GetStatus
|
||||||
if habilitacion:
|
if habilitacion:
|
||||||
req = dian.Habilitacion.GetStatus
|
req = dian.Habilitacion.GetStatus
|
||||||
resp = client.request(req(trackId=track_id))
|
resp = client.request(req(
|
||||||
|
trackId = track_id
|
||||||
|
))
|
||||||
print(resp)
|
print(resp)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", required=True)
|
@click.option('--private-key', required=True)
|
||||||
@click.option("--public-key", required=True)
|
@click.option('--public-key', required=True)
|
||||||
@click.option("--habilitacion/--produccion", default=False)
|
@click.option('--habilitacion/--produccion', default=False)
|
||||||
@click.option("--password")
|
@click.option('--password')
|
||||||
@click.option("--nit", required=True)
|
@click.option('--nit', required=True)
|
||||||
@click.option("--nit-proveedor", required=True)
|
@click.option('--nit-proveedor', required=True)
|
||||||
@click.option("--id-software", required=True)
|
@click.option('--id-software', required=True)
|
||||||
def soap_get_numbering_range(
|
def soap_get_numbering_range(private_key,
|
||||||
private_key,
|
public_key,
|
||||||
public_key,
|
habilitacion,
|
||||||
habilitacion,
|
password,
|
||||||
password,
|
nit, nit_proveedor, id_software):
|
||||||
nit,
|
|
||||||
nit_proveedor,
|
|
||||||
id_software,
|
|
||||||
):
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(
|
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
||||||
private_key, public_key, password=password
|
|
||||||
)
|
|
||||||
req = dian.GetNumberingRange
|
req = dian.GetNumberingRange
|
||||||
if habilitacion:
|
if habilitacion:
|
||||||
req = dian.Habilitacion.GetNumberingRange
|
req = dian.Habilitacion.GetNumberingRange
|
||||||
resp = client.request(req(nit, nit_proveedor, id_software))
|
resp = client.request(req(
|
||||||
|
nit, nit_proveedor, id_software
|
||||||
|
))
|
||||||
print(resp)
|
print(resp)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.argument("invoice_path")
|
@click.argument('invoice_path')
|
||||||
def validate_invoice(invoice_path):
|
def validate_invoice(invoice_path):
|
||||||
warnings.warn("!! NO APROBADO FUNCIONAMIENTO")
|
warnings.warn("!! NO APROBADO FUNCIONAMIENTO")
|
||||||
|
|
||||||
from facho.fe.data.dian import XSD
|
from facho.fe.data.dian import XSD
|
||||||
|
content = open(invoice_path, 'r').read()
|
||||||
content = open(invoice_path, "r").read()
|
|
||||||
# TODO donde ubicar esta responsabilidad?
|
# TODO donde ubicar esta responsabilidad?
|
||||||
# esto es requerido por el XSD de la DIAN
|
# esto es requerido por el XSD de la DIAN
|
||||||
content = content.replace(
|
content = content.replace(
|
||||||
'xmlns:fe="http://www.dian.gov.co/contratos/facturaelectronica/v1"',
|
'xmlns:fe="http://www.dian.gov.co/contratos/facturaelectronica/v1"',
|
||||||
'xmlns:fe="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"',
|
'xmlns:fe="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"'
|
||||||
)
|
)
|
||||||
XSD.validate(content, XSD.UBLInvoice)
|
XSD.validate(content, XSD.UBLInvoice)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.argument("nomina_path")
|
@click.argument('nomina_path')
|
||||||
def validate_nominaindividual(nomina_path):
|
def validate_nominaindividual(nomina_path):
|
||||||
from facho.fe.data.dian import XSD
|
from facho.fe.data.dian import XSD
|
||||||
|
content = open(nomina_path, 'r').read()
|
||||||
content = open(nomina_path, "r").read()
|
|
||||||
content = content.replace(
|
content = content.replace(
|
||||||
'xmlns="http://www.dian.gov.co/contratos/facturaelectronica/v1"',
|
'xmlns="http://www.dian.gov.co/contratos/facturaelectronica/v1"',
|
||||||
'xmlns="dian:gov:co:facturaelectronica:NominaIndividual"',
|
'xmlns="dian:gov:co:facturaelectronica:NominaIndividual"',
|
||||||
@@ -244,55 +213,35 @@ def validate_nominaindividual(nomina_path):
|
|||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", type=click.Path(exists=True))
|
@click.option('--private-key', type=click.Path(exists=True))
|
||||||
@click.option("--passphrase")
|
@click.option('--passphrase')
|
||||||
@click.option("--ssl/--no-ssl", default=False)
|
@click.option('--ssl/--no-ssl', default=False)
|
||||||
@click.option("--use-cache-policy/--no-use-cache-policy", default=False)
|
@click.option('--use-cache-policy/--no-use-cache-policy', default=False)
|
||||||
@click.argument("xmlfile", type=click.Path(exists=True), required=True)
|
@click.argument('xmlfile', type=click.Path(exists=True), required=True)
|
||||||
@click.argument("output", required=True)
|
@click.argument('output', required=True)
|
||||||
def sign_xml(
|
def sign_xml(private_key, passphrase, xmlfile, ssl=True, use_cache_policy=False, output=None):
|
||||||
private_key,
|
|
||||||
passphrase,
|
|
||||||
xmlfile,
|
|
||||||
ssl=True,
|
|
||||||
use_cache_policy=False,
|
|
||||||
output=None,
|
|
||||||
):
|
|
||||||
if not ssl:
|
if not ssl:
|
||||||
disable_ssl()
|
disable_ssl()
|
||||||
|
|
||||||
from facho import fe
|
from facho import fe
|
||||||
|
|
||||||
if use_cache_policy:
|
if use_cache_policy:
|
||||||
warnings.warn("xades using cache policy")
|
warnings.warn("xades using cache policy")
|
||||||
|
|
||||||
signer = fe.DianXMLExtensionSigner(
|
signer = fe.DianXMLExtensionSigner(private_key, passphrase=passphrase, localpolicy=use_cache_policy)
|
||||||
private_key, passphrase=passphrase, localpolicy=use_cache_policy
|
document = open(xmlfile, 'r').read().encode('utf-8')
|
||||||
)
|
with open(output, 'w') as f:
|
||||||
document = open(xmlfile, "r").read().encode("utf-8")
|
|
||||||
with open(output, "w") as f:
|
|
||||||
f.write(signer.sign_xml_string(document))
|
f.write(signer.sign_xml_string(document))
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", type=click.Path(exists=True))
|
@click.option('--private-key', type=click.Path(exists=True))
|
||||||
@click.option("--generate/--validate", default=False)
|
@click.option('--generate/--validate', default=False)
|
||||||
@click.option("--passphrase")
|
@click.option('--passphrase')
|
||||||
@click.option("--ssl/--no-ssl", default=False)
|
@click.option('--ssl/--no-ssl', default=False)
|
||||||
@click.option("--sign/--no-sign", default=False)
|
@click.option('--sign/--no-sign', default=False)
|
||||||
@click.option("--use-cache-policy/--no-use-cache-policy", default=False)
|
@click.option('--use-cache-policy/--no-use-cache-policy', default=False)
|
||||||
@click.argument("scriptname", type=click.Path(exists=True), required=True)
|
@click.argument('scriptname', type=click.Path(exists=True), required=True)
|
||||||
@click.argument("output", required=True)
|
@click.argument('output', required=True)
|
||||||
def generate_invoice(
|
def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=True, sign=False, use_cache_policy=False, output=None):
|
||||||
private_key,
|
|
||||||
passphrase,
|
|
||||||
scriptname,
|
|
||||||
generate=False,
|
|
||||||
ssl=True,
|
|
||||||
sign=False,
|
|
||||||
use_cache_policy=False,
|
|
||||||
output=None,
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
imprime xml en pantalla.
|
imprime xml en pantalla.
|
||||||
SCRIPTNAME espera
|
SCRIPTNAME espera
|
||||||
@@ -305,21 +254,19 @@ def generate_invoice(
|
|||||||
|
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
|
||||||
spec = importlib.util.spec_from_file_location("invoice", scriptname)
|
spec = importlib.util.spec_from_file_location('invoice', scriptname)
|
||||||
module = importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
|
|
||||||
from facho.fe.form_xml import (
|
import facho.fe.form as form
|
||||||
DIANWriteSigned,
|
from facho.fe.form_xml import DIANInvoiceXML, DIANWriteSigned,DIANWrite
|
||||||
DIANWrite,
|
from facho import fe
|
||||||
DIANSupportDocumentXML,
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
invoice_xml = module.document_xml()
|
invoice_xml = module.document_xml()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# invoice_xml = DIANInvoiceXML
|
invoice_xml = DIANInvoiceXML
|
||||||
invoice_xml = DIANSupportDocumentXML
|
|
||||||
print("Using document xml:", invoice_xml)
|
print("Using document xml:", invoice_xml)
|
||||||
invoice = module.invoice()
|
invoice = module.invoice()
|
||||||
invoice.calculate()
|
invoice.calculate()
|
||||||
@@ -332,39 +279,24 @@ def generate_invoice(
|
|||||||
xml.add_extension(extension)
|
xml.add_extension(extension)
|
||||||
|
|
||||||
if sign:
|
if sign:
|
||||||
DIANWriteSigned(
|
DIANWriteSigned(xml, output, private_key, passphrase, use_cache_policy)
|
||||||
xml, output, private_key, passphrase, use_cache_policy
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
DIANWrite(xml, output)
|
DIANWrite(xml, output)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", type=click.Path(exists=True))
|
@click.option('--private-key', type=click.Path(exists=True))
|
||||||
@click.option("--passphrase")
|
@click.option('--passphrase')
|
||||||
@click.option("--ssl/--no-ssl", default=False)
|
@click.option('--ssl/--no-ssl', default=False)
|
||||||
@click.option("--sign/--no-sign", default=False)
|
@click.option('--sign/--no-sign', default=False)
|
||||||
@click.option("--use-cache-policy/--no-use-cache-policy", default=False)
|
@click.option('--use-cache-policy/--no-use-cache-policy', default=False)
|
||||||
@click.argument("scriptname", type=click.Path(exists=True), required=True)
|
@click.argument('scriptname', type=click.Path(exists=True), required=True)
|
||||||
@click.argument("output", required=True)
|
@click.argument('output', required=True)
|
||||||
def generate_nomina(
|
def generate_nomina(private_key, passphrase, scriptname, ssl=True, sign=False, use_cache_policy=False, output=None):
|
||||||
private_key,
|
|
||||||
passphrase,
|
|
||||||
scriptname,
|
|
||||||
ssl=True,
|
|
||||||
sign=False,
|
|
||||||
use_cache_policy=False,
|
|
||||||
output=None,
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
imprime xml en pantalla.
|
imprime xml en pantalla.
|
||||||
SCRIPTNAME espera
|
SCRIPTNAME espera
|
||||||
def nomina() -> (
|
def nomina() -> fe.nomina.NominaIndividual
|
||||||
fe.nomina.NominaIndividual
|
def extensions(fe.nomina.NominaIndividual): -> List[facho.FachoXMLExtension]
|
||||||
)
|
|
||||||
def extensions(
|
|
||||||
fe.nomina.NominaIndividual
|
|
||||||
): -> List[facho.FachoXMLExtension]
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not ssl:
|
if not ssl:
|
||||||
@@ -372,7 +304,7 @@ def generate_nomina(
|
|||||||
|
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
|
||||||
spec = importlib.util.spec_from_file_location("nomina", scriptname)
|
spec = importlib.util.spec_from_file_location('nomina', scriptname)
|
||||||
module = importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
|
|
||||||
@@ -388,83 +320,59 @@ def generate_nomina(
|
|||||||
xml.add_extension(extension)
|
xml.add_extension(extension)
|
||||||
|
|
||||||
if sign:
|
if sign:
|
||||||
DIANWriteSigned(
|
DIANWriteSigned(xml, output, private_key, passphrase, use_cache_policy, dian_signer=facho.fe.nomina.DianXMLExtensionSigner)
|
||||||
xml,
|
|
||||||
output,
|
|
||||||
private_key,
|
|
||||||
passphrase,
|
|
||||||
use_cache_policy,
|
|
||||||
dian_signer=facho.fe.nomina.DianXMLExtensionSigner,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
DIANWrite(xml, output)
|
DIANWrite(xml, output)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", required=True)
|
@click.option('--private-key', required=True)
|
||||||
@click.option("--public-key", required=True)
|
@click.option('--public-key', required=True)
|
||||||
@click.option("--habilitacion/--produccion", default=False)
|
@click.option('--habilitacion/--produccion', default=False)
|
||||||
@click.option("--password")
|
@click.option('--password')
|
||||||
@click.argument("filename", required=True)
|
@click.argument('filename', required=True)
|
||||||
@click.argument("zipfile", type=click.Path(exists=True))
|
@click.argument('zipfile', type=click.Path(exists=True))
|
||||||
def soap_send_nomina_sync(
|
def soap_send_nomina_sync(private_key, public_key, habilitacion, password, filename, zipfile):
|
||||||
private_key, public_key, habilitacion, password, filename, zipfile
|
|
||||||
):
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(
|
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
||||||
private_key, public_key, password=password
|
|
||||||
)
|
|
||||||
req = dian.SendNominaSync
|
req = dian.SendNominaSync
|
||||||
if habilitacion:
|
if habilitacion:
|
||||||
req = dian.Habilitacion.SendNominaSync
|
req = dian.Habilitacion.SendNominaSync
|
||||||
resp = client.request(req(open(zipfile, "rb").read()))
|
resp = client.request(req(
|
||||||
|
open(zipfile, 'rb').read()
|
||||||
|
))
|
||||||
print(resp)
|
print(resp)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--private-key", type=click.Path(exists=True))
|
@click.option('--private-key', type=click.Path(exists=True))
|
||||||
@click.option("--passphrase")
|
@click.option('--passphrase')
|
||||||
@click.option("--ssl/--no-ssl", default=False)
|
@click.option('--ssl/--no-ssl', default=False)
|
||||||
@click.option("--use-cache-policy/--no-use-cache-policy", default=False)
|
@click.option('--use-cache-policy/--no-use-cache-policy', default=False)
|
||||||
@click.argument("xmlfile", type=click.Path(exists=True), required=True)
|
@click.argument('xmlfile', type=click.Path(exists=True), required=True)
|
||||||
def sign_verify_xml(
|
def sign_verify_xml(private_key, passphrase, xmlfile, ssl=True, use_cache_policy=False, output=None):
|
||||||
private_key,
|
|
||||||
passphrase,
|
|
||||||
xmlfile,
|
|
||||||
ssl=True,
|
|
||||||
use_cache_policy=False,
|
|
||||||
output=None,
|
|
||||||
):
|
|
||||||
if not ssl:
|
if not ssl:
|
||||||
disable_ssl()
|
disable_ssl()
|
||||||
|
|
||||||
from facho.fe import fe
|
from facho.fe import fe
|
||||||
|
|
||||||
if use_cache_policy:
|
if use_cache_policy:
|
||||||
warnings.warn("xades using cache policy")
|
warnings.warn("xades using cache policy")
|
||||||
|
|
||||||
print("THIS ONLY WORKS FOR DOCUMENTS GENERATE WITH FACHO")
|
print("THIS ONLY WORKS FOR DOCUMENTS GENERATE WITH FACHO")
|
||||||
signer = fe.DianXMLExtensionSignerVerifier(
|
signer = fe.DianXMLExtensionSignerVerifier(private_key, passphrase=passphrase, localpolicy=use_cache_policy)
|
||||||
private_key, passphrase=passphrase, localpolicy=use_cache_policy
|
document = open(xmlfile, 'r').read().encode('utf-8')
|
||||||
)
|
|
||||||
document = open(xmlfile, "r").read().encode("utf-8")
|
|
||||||
|
|
||||||
if signer.verify_string(document):
|
if signer.verify_string(document):
|
||||||
print("+OK")
|
print("+OK")
|
||||||
else:
|
else:
|
||||||
print("-INVALID")
|
print("-INVALID")
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option("--software-id")
|
@click.option('--software-id')
|
||||||
@click.option("--software-pin")
|
@click.option('--software-pin')
|
||||||
@click.option("--nit")
|
@click.option('--nit')
|
||||||
@click.option("--dv")
|
@click.option('--dv')
|
||||||
@click.option("--output-zippath")
|
@click.option('--output-zippath')
|
||||||
def generate_nomina_habilitacion(
|
def generate_nomina_habilitacion(software_id, software_pin, nit, dv, output_zippath):
|
||||||
software_id, software_pin, nit, dv, output_zippath
|
|
||||||
):
|
|
||||||
from facho import fe
|
from facho import fe
|
||||||
|
|
||||||
generador = fe.nomina.habilitacion.Habilitacion(
|
generador = fe.nomina.habilitacion.Habilitacion(
|
||||||
@@ -472,17 +380,15 @@ def generate_nomina_habilitacion(
|
|||||||
software_id=software_id,
|
software_id=software_id,
|
||||||
software_pin=software_pin,
|
software_pin=software_pin,
|
||||||
nit=nit,
|
nit=nit,
|
||||||
dv=dv,
|
dv=dv
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
generador.generar(output_zippath)
|
generador.generar(output_zippath)
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
def main():
|
def main():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
main.add_command(consultaResolucionesFacturacion)
|
main.add_command(consultaResolucionesFacturacion)
|
||||||
main.add_command(soap_send_test_set_async)
|
main.add_command(soap_send_test_set_async)
|
||||||
main.add_command(soap_send_bill_async)
|
main.add_command(soap_send_bill_async)
|
||||||
|
|||||||
101
facho/facho.py
101
facho/facho.py
@@ -1,11 +1,12 @@
|
|||||||
# This file is part of facho. The COPYRIGHT file at the top level of
|
# This file is part of facho. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from lxml.etree import Element, tostring
|
from lxml.etree import Element, SubElement, tostring
|
||||||
import re
|
import re
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
class FachoValueInvalid(Exception):
|
class FachoValueInvalid(Exception):
|
||||||
def __init__(self, xpath):
|
def __init__(self, xpath):
|
||||||
@@ -31,10 +32,7 @@ class LXMLBuilder:
|
|||||||
|
|
||||||
def __init__(self, nsmap):
|
def __init__(self, nsmap):
|
||||||
self.nsmap = nsmap
|
self.nsmap = nsmap
|
||||||
self._re_node_expr = \
|
self._re_node_expr = re.compile(r'^(?P<path>((?P<ns>\w+):)?(?P<tag>[a-zA-Z0-9_-]+))(?P<attrs>\[.+\])?')
|
||||||
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+)\"?')
|
self._re_attrs = re.compile(r'(\w+)\s*=\s*\"?(\w+)\"?')
|
||||||
|
|
||||||
def match_expression(self, node_expr):
|
def match_expression(self, node_expr):
|
||||||
@@ -119,11 +117,11 @@ class LXMLBuilder:
|
|||||||
def is_attribute(self, elem, key, value):
|
def is_attribute(self, elem, key, value):
|
||||||
return elem.get(key, False) == value
|
return elem.get(key, False) == value
|
||||||
|
|
||||||
def set_attribute(self, elem, key, value):
|
def set_attribute(self, elem, key, value):
|
||||||
elem.attrib[key] = value
|
elem.attrib[key] = value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def remove_attributes(cls, elem, keys, exclude=[]):
|
def remove_attributes(cls, elem, keys, exclude = []):
|
||||||
for key in keys:
|
for key in keys:
|
||||||
if key in exclude:
|
if key in exclude:
|
||||||
continue
|
continue
|
||||||
@@ -140,13 +138,12 @@ class LXMLBuilder:
|
|||||||
attrs['pretty_print'] = attrs.pop('pretty_print', False)
|
attrs['pretty_print'] = attrs.pop('pretty_print', False)
|
||||||
attrs['encoding'] = attrs.pop('encoding', 'UTF-8')
|
attrs['encoding'] = attrs.pop('encoding', 'UTF-8')
|
||||||
|
|
||||||
for el in elem.iter():
|
for el in elem.getiterator():
|
||||||
keys = filter(lambda key: key.startswith('facho_'), el.keys())
|
keys = filter(lambda key: key.startswith('facho_'), el.keys())
|
||||||
self.remove_attributes(el, keys, exclude=['facho_optional'])
|
self.remove_attributes(el, keys, exclude=['facho_optional'])
|
||||||
|
|
||||||
is_optional = el.get('facho_optional', 'False') == 'True'
|
is_optional = el.get('facho_optional', 'False') == 'True'
|
||||||
if is_optional and list(el) == [] and el.keys() == [
|
if is_optional and el.getchildren() == [] and el.keys() == ['facho_optional']:
|
||||||
'facho_optional']:
|
|
||||||
el.getparent().remove(el)
|
el.getparent().remove(el)
|
||||||
|
|
||||||
return tostring(elem, **attrs).decode('utf-8')
|
return tostring(elem, **attrs).decode('utf-8')
|
||||||
@@ -156,16 +153,14 @@ class FachoXML:
|
|||||||
"""
|
"""
|
||||||
Decora XML con funciones de consulta XPATH de un solo elemento
|
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:
|
if builder is None:
|
||||||
self.builder = LXMLBuilder(nsmap)
|
self.builder = LXMLBuilder(nsmap)
|
||||||
else:
|
else:
|
||||||
self.builder = builder
|
self.builder = builder
|
||||||
|
|
||||||
self.nsmap = nsmap
|
self.nsmap = nsmap
|
||||||
|
|
||||||
if isinstance(root, str):
|
if isinstance(root, str):
|
||||||
self.root = self.builder.build_element_from_string(root, nsmap)
|
self.root = self.builder.build_element_from_string(root, nsmap)
|
||||||
else:
|
else:
|
||||||
@@ -182,22 +177,16 @@ class FachoXML:
|
|||||||
xml = LXMLBuilder.from_string(document)
|
xml = LXMLBuilder.from_string(document)
|
||||||
return FachoXML(xml, nsmap=namespaces)
|
return FachoXML(xml, nsmap=namespaces)
|
||||||
|
|
||||||
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):
|
def append_element(self, elem, new_elem):
|
||||||
# elem = self.find_or_create_element(xpath, append=append)
|
#elem = self.find_or_create_element(xpath, append=append)
|
||||||
# self.builder.append(elem, new_elem)
|
#self.builder.append(elem, new_elem)
|
||||||
self.builder.append(elem, new_elem)
|
self.builder.append(elem, new_elem)
|
||||||
|
|
||||||
def add_extension(self, extension):
|
def add_extension(self, extension):
|
||||||
extension.build(self)
|
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 = xpath.split('/')
|
||||||
nodes.pop()
|
nodes.pop()
|
||||||
root_prefix = '/'.join(nodes)
|
root_prefix = '/'.join(nodes)
|
||||||
@@ -207,9 +196,7 @@ class FachoXML:
|
|||||||
|
|
||||||
if parent is None:
|
if parent is None:
|
||||||
parent = self.find_or_create_element(xpath, append=append)
|
parent = self.find_or_create_element(xpath, append=append)
|
||||||
return FachoXML(
|
return FachoXML(parent, nsmap=self.nsmap, fragment_prefix=root_prefix, fragment_root_element=self.root)
|
||||||
parent, nsmap=self.nsmap, fragment_prefix=root_prefix,
|
|
||||||
fragment_root_element=self.root)
|
|
||||||
|
|
||||||
def register_alias_xpath(self, alias, xpath):
|
def register_alias_xpath(self, alias, xpath):
|
||||||
self.xpath_for[alias] = xpath
|
self.xpath_for[alias] = xpath
|
||||||
@@ -245,8 +232,7 @@ class FachoXML:
|
|||||||
"""
|
"""
|
||||||
xpath = self._path_xpath_for(xpath)
|
xpath = self._path_xpath_for(xpath)
|
||||||
node_paths = xpath.split('/')
|
node_paths = xpath.split('/')
|
||||||
# remove empty /
|
node_paths.pop(0) #remove empty /
|
||||||
node_paths.pop(0)
|
|
||||||
root_tag = node_paths.pop(0)
|
root_tag = node_paths.pop(0)
|
||||||
|
|
||||||
root_node = self.builder.build_from_expression(root_tag)
|
root_node = self.builder.build_from_expression(root_tag)
|
||||||
@@ -254,10 +240,10 @@ class FachoXML:
|
|||||||
# restaurar ya que no es la raiz y asignar actual como raiz
|
# restaurar ya que no es la raiz y asignar actual como raiz
|
||||||
node_paths.insert(0, root_tag)
|
node_paths.insert(0, root_tag)
|
||||||
root_node = self.root
|
root_node = self.root
|
||||||
|
|
||||||
if not self.builder.same_tag(root_node.tag, self.root.tag):
|
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
|
# crea jerarquia segun xpath indicado
|
||||||
parent = None
|
parent = None
|
||||||
@@ -267,8 +253,8 @@ class FachoXML:
|
|||||||
for node_path in node_paths:
|
for node_path in node_paths:
|
||||||
node_expr = self.builder.match_expression(node_path)
|
node_expr = self.builder.match_expression(node_path)
|
||||||
node = self.builder.build_from_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
|
parent = current_elem
|
||||||
if child is not None:
|
if child is not None:
|
||||||
@@ -279,12 +265,11 @@ class FachoXML:
|
|||||||
|
|
||||||
node_expr = self.builder.match_expression(node_tag)
|
node_expr = self.builder.match_expression(node_tag)
|
||||||
node = self.builder.build_from_expression(node_tag)
|
node = self.builder.build_from_expression(node_tag)
|
||||||
child = self.builder.find_relative(
|
child = self.builder.find_relative(current_elem, node_expr['path'], self.nsmap)
|
||||||
current_elem, node_expr['path'], self.nsmap)
|
|
||||||
parent = current_elem
|
parent = current_elem
|
||||||
if child is not None:
|
if child is not None:
|
||||||
current_elem = child
|
current_elem = child
|
||||||
|
|
||||||
if parent == current_elem:
|
if parent == current_elem:
|
||||||
self.builder.append(parent, node)
|
self.builder.append(parent, node)
|
||||||
return node
|
return node
|
||||||
@@ -292,7 +277,7 @@ class FachoXML:
|
|||||||
# se fuerza la adicion como un nuevo elemento
|
# se fuerza la adicion como un nuevo elemento
|
||||||
if append:
|
if append:
|
||||||
last_slibing = None
|
last_slibing = None
|
||||||
for child in list(parent):
|
for child in parent.getchildren():
|
||||||
if child.tag == node_tag:
|
if child.tag == node_tag:
|
||||||
last_slibing = child
|
last_slibing = child
|
||||||
|
|
||||||
@@ -301,10 +286,9 @@ class FachoXML:
|
|||||||
self.builder.append(parent, node)
|
self.builder.append(parent, node)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
if self.builder.is_attribute(
|
if self.builder.is_attribute(last_slibing, 'facho_placeholder', 'True'):
|
||||||
last_slibing, 'facho_placeholder', 'True'):
|
|
||||||
self._remove_facho_attributes(last_slibing)
|
self._remove_facho_attributes(last_slibing)
|
||||||
return last_slibing
|
return last_slibing
|
||||||
self.builder.append_next(last_slibing, node)
|
self.builder.append_next(last_slibing, node)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
@@ -315,8 +299,7 @@ class FachoXML:
|
|||||||
self._remove_facho_attributes(current_elem)
|
self._remove_facho_attributes(current_elem)
|
||||||
return current_elem
|
return current_elem
|
||||||
|
|
||||||
def set_element_validator(
|
def set_element_validator(self, xpath, validator = False):
|
||||||
self, xpath, validator=False):
|
|
||||||
"""
|
"""
|
||||||
validador al asignar contenido a xpath indicado
|
validador al asignar contenido a xpath indicado
|
||||||
|
|
||||||
@@ -329,9 +312,8 @@ class FachoXML:
|
|||||||
self._validators[key] = lambda v, attrs: True
|
self._validators[key] = lambda v, attrs: True
|
||||||
else:
|
else:
|
||||||
self._validators[key] = validator
|
self._validators[key] = validator
|
||||||
|
|
||||||
def set_element(
|
def set_element(self, xpath, content, **attrs):
|
||||||
self, xpath, content, **attrs):
|
|
||||||
"""
|
"""
|
||||||
asigna contenido ubicado por ruta tipo XPATH.
|
asigna contenido ubicado por ruta tipo XPATH.
|
||||||
@param xpath ruta tipo XPATH
|
@param xpath ruta tipo XPATH
|
||||||
@@ -373,8 +355,7 @@ class FachoXML:
|
|||||||
self.builder.set_attribute(elem, k, str(v))
|
self.builder.set_attribute(elem, k, str(v))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_element_attribute(
|
def get_element_attribute(self, xpath, attribute, multiple=False):
|
||||||
self, xpath, attribute, multiple=False):
|
|
||||||
elem = self.get_element(xpath, multiple=multiple)
|
elem = self.get_element(xpath, multiple=multiple)
|
||||||
|
|
||||||
if elem is None:
|
if elem is None:
|
||||||
@@ -411,16 +392,14 @@ class FachoXML:
|
|||||||
return None
|
return None
|
||||||
return format_(text)
|
return format_(text)
|
||||||
|
|
||||||
def get_element_text_or_attribute(
|
def get_element_text_or_attribute(self, xpath, default=None, multiple=False, raise_on_fail=False):
|
||||||
self, xpath, default=None, multiple=False, raise_on_fail=False):
|
|
||||||
parts = xpath.split('/')
|
parts = xpath.split('/')
|
||||||
is_attribute = parts[-1].startswith('@')
|
is_attribute = parts[-1].startswith('@')
|
||||||
if is_attribute:
|
if is_attribute:
|
||||||
attribute_name = parts.pop(-1).lstrip('@')
|
attribute_name = parts.pop(-1).lstrip('@')
|
||||||
element_path = "/".join(parts)
|
element_path = "/".join(parts)
|
||||||
try:
|
try:
|
||||||
val = self.get_element_attribute(
|
val = self.get_element_attribute(element_path, attribute_name, multiple=multiple)
|
||||||
element_path, attribute_name, multiple=multiple)
|
|
||||||
if val is None:
|
if val is None:
|
||||||
return default
|
return default
|
||||||
return val
|
return val
|
||||||
@@ -453,8 +432,7 @@ class FachoXML:
|
|||||||
if isinstance(xpath, tuple):
|
if isinstance(xpath, tuple):
|
||||||
val = xpath[0]
|
val = xpath[0]
|
||||||
else:
|
else:
|
||||||
val = self.get_element_text_or_attribute(
|
val = self.get_element_text_or_attribute(xpath, raise_on_fail=raise_on_fail)
|
||||||
xpath, raise_on_fail=raise_on_fail)
|
|
||||||
vals.append(val)
|
vals.append(val)
|
||||||
return vals
|
return vals
|
||||||
|
|
||||||
@@ -476,8 +454,7 @@ class FachoXML:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def _remove_facho_attributes(self, elem):
|
def _remove_facho_attributes(self, elem):
|
||||||
self.builder.remove_attributes(
|
self.builder.remove_attributes(elem, ['facho_optional', 'facho_placeholder'])
|
||||||
elem, ['facho_optional', 'facho_placeholder'])
|
|
||||||
|
|
||||||
def tostring(self, **kw):
|
def tostring(self, **kw):
|
||||||
return self.builder.tostring(self.root, **kw)
|
return self.builder.tostring(self.root, **kw)
|
||||||
@@ -489,17 +466,15 @@ class FachoXML:
|
|||||||
root = self.root
|
root = self.root
|
||||||
if self.fragment_root_element is not None:
|
if self.fragment_root_element is not None:
|
||||||
root = self.fragment_root_element
|
root = self.fragment_root_element
|
||||||
|
|
||||||
if isinstance(self.nsmap, dict):
|
if isinstance(self.nsmap, dict):
|
||||||
nsmap = dict(map(reversed, self.nsmap.items()))
|
nsmap = dict(map(reversed, self.nsmap.items()))
|
||||||
ns = nsmap[etree.QName(root).namespace] + ':'
|
ns = nsmap[etree.QName(root).namespace] + ':'
|
||||||
|
|
||||||
if self.fragment_root_element is not None:
|
if self.fragment_root_element is not None:
|
||||||
new_xpath = '/' + ns + etree.QName(root).localname + '/' + \
|
new_xpath = '/' + ns + etree.QName(root).localname + '/' + etree.QName(self.root).localname + '/' + xpath.lstrip('/')
|
||||||
etree.QName(self.root).localname + '/' + xpath.lstrip('/')
|
|
||||||
else:
|
else:
|
||||||
new_xpath = '/' + ns + etree.QName(root).localname + '/' + \
|
new_xpath = '/' + ns + etree.QName(root).localname + '/' + xpath.lstrip('/')
|
||||||
xpath.lstrip('/')
|
|
||||||
return new_xpath
|
return new_xpath
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from .fe import DianXMLExtensionSigner
|
|||||||
from .fe import DianXMLExtensionSoftwareSecurityCode
|
from .fe import DianXMLExtensionSoftwareSecurityCode
|
||||||
from .fe import DianXMLExtensionCUFE
|
from .fe import DianXMLExtensionCUFE
|
||||||
from .fe import DianXMLExtensionCUDE
|
from .fe import DianXMLExtensionCUDE
|
||||||
from .fe import DianXMLExtensionCUDS
|
|
||||||
from .fe import DianXMLExtensionInvoiceAuthorization
|
from .fe import DianXMLExtensionInvoiceAuthorization
|
||||||
from .fe import DianXMLExtensionSoftwareProvider
|
from .fe import DianXMLExtensionSoftwareProvider
|
||||||
from .fe import DianXMLExtensionAuthorizationProvider
|
from .fe import DianXMLExtensionAuthorizationProvider
|
||||||
@@ -14,22 +13,3 @@ from .fe import AMBIENTE_PRUEBAS
|
|||||||
from .fe import AMBIENTE_PRODUCCION
|
from .fe import AMBIENTE_PRODUCCION
|
||||||
from . import form_xml
|
from . import form_xml
|
||||||
from . import nomina
|
from . import nomina
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'FeXML',
|
|
||||||
'fe_from_string',
|
|
||||||
'NAMESPACES',
|
|
||||||
'DianXMLExtensionSigner',
|
|
||||||
'DianXMLExtensionSoftwareSecurityCode',
|
|
||||||
'DianXMLExtensionCUFE',
|
|
||||||
'DianXMLExtensionCUDE',
|
|
||||||
'DianXMLExtensionCUDS',
|
|
||||||
'DianXMLExtensionInvoiceAuthorization',
|
|
||||||
'DianXMLExtensionSoftwareProvider',
|
|
||||||
'DianXMLExtensionAuthorizationProvider',
|
|
||||||
'DianZIP',
|
|
||||||
'AMBIENTE_PRUEBAS',
|
|
||||||
'AMBIENTE_PRODUCCION',
|
|
||||||
'form_xml',
|
|
||||||
'nomina',
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,13 +1,23 @@
|
|||||||
|
from facho import facho
|
||||||
|
|
||||||
import zeep
|
import zeep
|
||||||
from zeep.wsse.username import UsernameToken
|
from zeep.wsse.username import UsernameToken
|
||||||
from .wsse.signature import BinarySignature
|
from .wsse.signature import Signature, BinarySignature
|
||||||
|
from zeep.wsa import WsAddressingPlugin
|
||||||
import xmlsec
|
import xmlsec
|
||||||
from dataclasses import dataclass, asdict
|
import urllib.request
|
||||||
|
from datetime import datetime
|
||||||
|
from dataclasses import dataclass, asdict, field
|
||||||
|
from typing import List
|
||||||
|
import http.client
|
||||||
|
import hashlib
|
||||||
|
import secrets
|
||||||
|
import base64
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['DianClient']
|
__all__ = ['DianClient',
|
||||||
|
'ConsultaResolucionesFacturacionPeticion',
|
||||||
|
'ConsultaResolucionesFacturacionRespuesta']
|
||||||
|
|
||||||
class SOAPService:
|
class SOAPService:
|
||||||
|
|
||||||
@@ -23,7 +33,6 @@ class SOAPService:
|
|||||||
def todict(self):
|
def todict(self):
|
||||||
return asdict(self)
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GetNumberingRangeResponse:
|
class GetNumberingRangeResponse:
|
||||||
|
|
||||||
@@ -38,7 +47,8 @@ class GetNumberingRangeResponse:
|
|||||||
ValidateDateTo: str
|
ValidateDateTo: str
|
||||||
TechnicalKey: str
|
TechnicalKey: str
|
||||||
|
|
||||||
NumberRangeResponse: list[NumberRangeResponse]
|
NumberRangeResponse: List[NumberRangeResponse]
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fromdict(cls, data):
|
def fromdict(cls, data):
|
||||||
@@ -81,7 +91,7 @@ class SendBillAsync(SOAPService):
|
|||||||
@dataclass
|
@dataclass
|
||||||
class SendTestSetAsyncResponse:
|
class SendTestSetAsyncResponse:
|
||||||
ZipKey: str
|
ZipKey: str
|
||||||
ErrorMessageList: list[str]
|
ErrorMessageList: List[str]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fromdict(cls, data):
|
def fromdict(cls, data):
|
||||||
@@ -90,7 +100,6 @@ class SendTestSetAsyncResponse:
|
|||||||
data['ErrorMessageList'] or []
|
data['ErrorMessageList'] or []
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SendTestSetAsync(SOAPService):
|
class SendTestSetAsync(SOAPService):
|
||||||
fileName: str
|
fileName: str
|
||||||
@@ -106,7 +115,6 @@ class SendTestSetAsync(SOAPService):
|
|||||||
def build_response(self, as_dict):
|
def build_response(self, as_dict):
|
||||||
return SendTestSetAsyncResponse.fromdict(as_dict)
|
return SendTestSetAsyncResponse.fromdict(as_dict)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SendBillSync(SOAPService):
|
class SendBillSync(SOAPService):
|
||||||
fileName: str
|
fileName: str
|
||||||
@@ -121,13 +129,12 @@ class SendBillSync(SOAPService):
|
|||||||
def build_response(self, as_dict):
|
def build_response(self, as_dict):
|
||||||
return as_dict
|
return as_dict
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GetStatusResponse:
|
class GetStatusResponse:
|
||||||
IsValid: bool
|
IsValid: bool
|
||||||
StatusDescription: str
|
StatusDescription: str
|
||||||
StatusCode: int
|
StatusCode: int
|
||||||
ErrorMessage: list[str]
|
ErrorMessage: List[str]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fromdict(cls, data):
|
def fromdict(cls, data):
|
||||||
@@ -135,12 +142,12 @@ class GetStatusResponse:
|
|||||||
error_message = data['ErrorMessage']['string']
|
error_message = data['ErrorMessage']['string']
|
||||||
else:
|
else:
|
||||||
error_message = None
|
error_message = None
|
||||||
|
|
||||||
return cls(data['IsValid'],
|
return cls(data['IsValid'],
|
||||||
data['StatusDescription'],
|
data['StatusDescription'],
|
||||||
data['StatusCode'],
|
data['StatusCode'],
|
||||||
error_message)
|
error_message)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GetStatus(SOAPService):
|
class GetStatus(SOAPService):
|
||||||
@@ -155,7 +162,6 @@ class GetStatus(SOAPService):
|
|||||||
def build_response(self, as_dict):
|
def build_response(self, as_dict):
|
||||||
return GetStatusResponse.fromdict(as_dict)
|
return GetStatusResponse.fromdict(as_dict)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GetStatusZip(SOAPService):
|
class GetStatusZip(SOAPService):
|
||||||
trackId: bytes
|
trackId: bytes
|
||||||
@@ -169,7 +175,6 @@ class GetStatusZip(SOAPService):
|
|||||||
def build_response(self, as_dict):
|
def build_response(self, as_dict):
|
||||||
return GetStatusResponse.fromdict(as_dict[0])
|
return GetStatusResponse.fromdict(as_dict[0])
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SendNominaSync(SOAPService):
|
class SendNominaSync(SOAPService):
|
||||||
contentFile: bytes
|
contentFile: bytes
|
||||||
@@ -183,7 +188,7 @@ class SendNominaSync(SOAPService):
|
|||||||
def build_response(self, as_dict):
|
def build_response(self, as_dict):
|
||||||
return as_dict
|
return as_dict
|
||||||
|
|
||||||
|
|
||||||
class Habilitacion:
|
class Habilitacion:
|
||||||
WSDL = 'https://vpfe-hab.dian.gov.co/WcfDianCustomerServices.svc?wsdl'
|
WSDL = 'https://vpfe-hab.dian.gov.co/WcfDianCustomerServices.svc?wsdl'
|
||||||
|
|
||||||
@@ -215,7 +220,6 @@ class Habilitacion:
|
|||||||
def get_wsdl(self):
|
def get_wsdl(self):
|
||||||
return Habilitacion.WSDL
|
return Habilitacion.WSDL
|
||||||
|
|
||||||
|
|
||||||
class DianGateway:
|
class DianGateway:
|
||||||
|
|
||||||
def _open(self, service):
|
def _open(self, service):
|
||||||
@@ -246,11 +250,7 @@ class DianClient(DianGateway):
|
|||||||
self._password = password
|
self._password = password
|
||||||
|
|
||||||
def _open(self, service):
|
def _open(self, service):
|
||||||
return zeep.Client(
|
return zeep.Client(service.get_wsdl(), wsse=UsernameToken(self._username, self._password))
|
||||||
service.get_wsdl(),
|
|
||||||
wsse=UsernameToken(
|
|
||||||
self._username,
|
|
||||||
self._password))
|
|
||||||
|
|
||||||
|
|
||||||
class DianSignatureClient(DianGateway):
|
class DianSignatureClient(DianGateway):
|
||||||
@@ -262,10 +262,13 @@ class DianSignatureClient(DianGateway):
|
|||||||
|
|
||||||
def _open(self, service):
|
def _open(self, service):
|
||||||
# RESOLUCCION 0004: pagina 756
|
# RESOLUCCION 0004: pagina 756
|
||||||
|
from zeep.wsse import utils
|
||||||
|
|
||||||
client = zeep.Client(service.get_wsdl(), wsse=BinarySignature(
|
client = zeep.Client(service.get_wsdl(), wsse=
|
||||||
self.private_key_path, self.public_key_path, self.password,
|
BinarySignature(
|
||||||
signature_method=xmlsec.Transform.RSA_SHA256,
|
self.private_key_path, self.public_key_path, self.password,
|
||||||
digest_method=xmlsec.Transform.SHA256),
|
signature_method=xmlsec.Transform.RSA_SHA256,
|
||||||
|
digest_method=xmlsec.Transform.SHA256)
|
||||||
|
,
|
||||||
)
|
)
|
||||||
return client
|
return client
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import pytz
|
import pytz
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from lxml.etree import QName
|
from lxml.etree import QName
|
||||||
|
|
||||||
@@ -70,11 +70,8 @@ class MemorySignature(object):
|
|||||||
def apply(self, envelope, headers):
|
def apply(self, envelope, headers):
|
||||||
key = _make_sign_key(self.key_data, self.cert_data, self.password)
|
key = _make_sign_key(self.key_data, self.cert_data, self.password)
|
||||||
_sign_envelope_with_key(
|
_sign_envelope_with_key(
|
||||||
envelope,
|
envelope, key, self.signature_method, self.digest_method, expires_dt=self.expires_dt
|
||||||
key,
|
)
|
||||||
self.signature_method,
|
|
||||||
self.digest_method,
|
|
||||||
expires_dt=self.expires_dt)
|
|
||||||
return envelope, headers
|
return envelope, headers
|
||||||
|
|
||||||
def verify(self, envelope):
|
def verify(self, envelope):
|
||||||
@@ -84,7 +81,7 @@ class MemorySignature(object):
|
|||||||
|
|
||||||
|
|
||||||
class Signature(MemorySignature):
|
class Signature(MemorySignature):
|
||||||
"""Sign given SOAP envelope with WSSE sig using given key and cert file."""
|
"""Sign given SOAP envelope with WSSE sig using given key file and cert file."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -104,18 +101,15 @@ class Signature(MemorySignature):
|
|||||||
|
|
||||||
|
|
||||||
class BinarySignature(Signature):
|
class BinarySignature(Signature):
|
||||||
"""Sign given SOAP envelope with WSSE sig using given key and cert file.
|
"""Sign given SOAP envelope with WSSE sig using given key file and cert file.
|
||||||
|
|
||||||
Place the key information into BinarySecurityElement."""
|
Place the key information into BinarySecurityElement."""
|
||||||
|
|
||||||
def apply(self, envelope, headers):
|
def apply(self, envelope, headers):
|
||||||
key = _make_sign_key(self.key_data, self.cert_data, self.password)
|
key = _make_sign_key(self.key_data, self.cert_data, self.password)
|
||||||
_sign_envelope_with_key_binary(
|
_sign_envelope_with_key_binary(
|
||||||
envelope,
|
envelope, key, self.signature_method, self.digest_method, expires_dt = self.expires_dt
|
||||||
key,
|
)
|
||||||
self.signature_method,
|
|
||||||
self.digest_method,
|
|
||||||
expires_dt=self.expires_dt)
|
|
||||||
return envelope, headers
|
return envelope, headers
|
||||||
|
|
||||||
|
|
||||||
@@ -225,12 +219,10 @@ def sign_envelope(
|
|||||||
"""
|
"""
|
||||||
# Load the signing key and certificate.
|
# Load the signing key and certificate.
|
||||||
key = _make_sign_key(_read_file(keyfile), _read_file(certfile), password)
|
key = _make_sign_key(_read_file(keyfile), _read_file(certfile), password)
|
||||||
return _sign_envelope_with_key(
|
return _sign_envelope_with_key(envelope, key, signature_method, digest_method)
|
||||||
envelope, key, signature_method, digest_method)
|
|
||||||
|
|
||||||
|
def get_timestamp(timestamp = None, delta=None):
|
||||||
def get_timestamp(timestamp=None, delta=None):
|
timestamp = timestamp or datetime.utcnow()
|
||||||
timestamp = timestamp or datetime.now(timezone.utc)
|
|
||||||
if delta:
|
if delta:
|
||||||
timestamp += delta
|
timestamp += delta
|
||||||
|
|
||||||
@@ -238,33 +230,24 @@ def get_timestamp(timestamp=None, delta=None):
|
|||||||
timestamp = timestamp.replace(tzinfo=pytz.utc, microsecond=0)
|
timestamp = timestamp.replace(tzinfo=pytz.utc, microsecond=0)
|
||||||
return timestamp.strftime(format_)
|
return timestamp.strftime(format_)
|
||||||
|
|
||||||
|
|
||||||
def _append_timestamp(security, expires_dt=None):
|
def _append_timestamp(security, expires_dt=None):
|
||||||
if expires_dt is None:
|
if expires_dt is None:
|
||||||
expires_dt = timedelta(seconds=6000)
|
expires_dt = timedelta(seconds=6000)
|
||||||
|
|
||||||
etimestamp = utils.WSU.Timestamp({
|
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()})
|
||||||
'{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.Created(get_timestamp()))
|
||||||
etimestamp.append(utils.WSU.Expires(get_timestamp(delta=expires_dt)))
|
etimestamp.append(utils.WSU.Expires(get_timestamp(delta=expires_dt)))
|
||||||
security.insert(0, etimestamp)
|
security.insert(0, etimestamp)
|
||||||
if etree.LXML_VERSION[:2] >= (3, 5):
|
if etree.LXML_VERSION[:2] >= (3, 5):
|
||||||
etree.cleanup_namespaces(security,
|
etree.cleanup_namespaces(security,
|
||||||
keep_ns_prefixes=security.nsmap,
|
keep_ns_prefixes = security.nsmap,
|
||||||
top_nsmap=utils.NSMAP)
|
top_nsmap=utils.NSMAP)
|
||||||
else:
|
else:
|
||||||
etree.cleanup_namespaces(security)
|
etree.cleanup_namespaces(header)
|
||||||
|
|
||||||
|
def _signature_prepare(envelope, key, signature_method, digest_method, expires_dt=None):
|
||||||
def _signature_prepare(
|
|
||||||
envelope,
|
|
||||||
key,
|
|
||||||
signature_method,
|
|
||||||
digest_method,
|
|
||||||
expires_dt=None):
|
|
||||||
"""Prepare envelope and sign."""
|
"""Prepare envelope and sign."""
|
||||||
|
soap_env = detect_soap_env(envelope)
|
||||||
|
|
||||||
# Create the Signature node.
|
# Create the Signature node.
|
||||||
signature = xmlsec.template.create(
|
signature = xmlsec.template.create(
|
||||||
@@ -295,7 +278,7 @@ def _signature_prepare(
|
|||||||
_append_timestamp(security, expires_dt=expires_dt)
|
_append_timestamp(security, expires_dt=expires_dt)
|
||||||
|
|
||||||
timestamp = security.find(QName(ns.WSU, "Timestamp"))
|
timestamp = security.find(QName(ns.WSU, "Timestamp"))
|
||||||
if timestamp is not None:
|
if timestamp != None:
|
||||||
_sign_node(ctx, signature, timestamp, digest_method)
|
_sign_node(ctx, signature, timestamp, digest_method)
|
||||||
ctx.sign(signature)
|
ctx.sign(signature)
|
||||||
|
|
||||||
@@ -303,30 +286,18 @@ def _signature_prepare(
|
|||||||
# KeyInfo. The recipient expects this structure, but we can't rearrange
|
# KeyInfo. The recipient expects this structure, but we can't rearrange
|
||||||
# like this until after signing, because otherwise xmlsec won't populate
|
# like this until after signing, because otherwise xmlsec won't populate
|
||||||
# the X509 data (because it doesn't understand WSSE).
|
# the X509 data (because it doesn't understand WSSE).
|
||||||
sec_token_ref = etree.SubElement(
|
sec_token_ref = etree.SubElement(key_info, QName(ns.WSSE, "SecurityTokenReference"))
|
||||||
key_info, QName(
|
|
||||||
ns.WSSE, "SecurityTokenReference"))
|
|
||||||
return security, sec_token_ref, x509_data
|
return security, sec_token_ref, x509_data
|
||||||
|
|
||||||
|
|
||||||
def _sign_envelope_with_key(
|
def _sign_envelope_with_key(envelope, key, signature_method, digest_method, expires_dt=None):
|
||||||
envelope,
|
|
||||||
key,
|
|
||||||
signature_method,
|
|
||||||
digest_method,
|
|
||||||
expires_dt=None):
|
|
||||||
_, sec_token_ref, x509_data = _signature_prepare(
|
_, sec_token_ref, x509_data = _signature_prepare(
|
||||||
envelope, key, signature_method, digest_method, expires_dt=expires_dt
|
envelope, key, signature_method, digest_method, expires_dt=expires_dt
|
||||||
)
|
)
|
||||||
sec_token_ref.append(x509_data)
|
sec_token_ref.append(x509_data)
|
||||||
|
|
||||||
|
|
||||||
def _sign_envelope_with_key_binary(
|
def _sign_envelope_with_key_binary(envelope, key, signature_method, digest_method, expires_dt=None):
|
||||||
envelope,
|
|
||||||
key,
|
|
||||||
signature_method,
|
|
||||||
digest_method,
|
|
||||||
expires_dt=None):
|
|
||||||
security, sec_token_ref, x509_data = _signature_prepare(
|
security, sec_token_ref, x509_data = _signature_prepare(
|
||||||
envelope, key, signature_method, digest_method, expires_dt=expires_dt
|
envelope, key, signature_method, digest_method, expires_dt=expires_dt
|
||||||
)
|
)
|
||||||
@@ -382,10 +353,7 @@ def _verify_envelope_with_key(envelope, key):
|
|||||||
ctx = xmlsec.SignatureContext()
|
ctx = xmlsec.SignatureContext()
|
||||||
|
|
||||||
# Find each signed element and register its ID with the signing context.
|
# Find each signed element and register its ID with the signing context.
|
||||||
refs = signature.xpath(
|
refs = signature.xpath("ds:SignedInfo/ds:Reference", namespaces={"ds": ns.DS})
|
||||||
"ds:SignedInfo/ds:Reference",
|
|
||||||
namespaces={
|
|
||||||
"ds": ns.DS})
|
|
||||||
for ref in refs:
|
for ref in refs:
|
||||||
# Get the reference URI and cut off the initial '#'
|
# Get the reference URI and cut off the initial '#'
|
||||||
referenced_id = ref.get("URI")[1:]
|
referenced_id = ref.get("URI")[1:]
|
||||||
|
|||||||
@@ -7,17 +7,10 @@ def path_for_xsd(dirname, xsdname):
|
|||||||
data_dir = os.path.dirname(os.path.abspath(__file__))
|
data_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
return os.path.join(data_dir, dirname, xsdname)
|
return os.path.join(data_dir, dirname, xsdname)
|
||||||
|
|
||||||
|
UBLInvoice= xmlschema.XMLSchema(path_for_xsd('maindoc', 'UBL-Invoice-2.1.xsd'))
|
||||||
|
|
||||||
UBLInvoice = xmlschema.XMLSchema(
|
NominaIndividual = xmlschema.XMLSchema(path_for_xsd('nomina', 'NominaIndividualElectronicaXSDV1.0.6.xsd'))
|
||||||
path_for_xsd(
|
NominaIndividualDeAjuste = xmlschema.XMLSchema(path_for_xsd('nomina', 'NominaIndividualDeAjusteElectronicaXSDV1.0.6.xsd'))
|
||||||
'maindoc',
|
|
||||||
'UBL-Invoice-2.1.xsd'))
|
|
||||||
|
|
||||||
NominaIndividual = xmlschema.XMLSchema(path_for_xsd(
|
|
||||||
'nomina', 'NominaIndividualElectronicaXSDV1.0.6.xsd'))
|
|
||||||
NominaIndividualDeAjuste = xmlschema.XMLSchema(path_for_xsd(
|
|
||||||
'nomina', 'NominaIndividualDeAjusteElectronicaXSDV1.0.6.xsd'))
|
|
||||||
|
|
||||||
|
|
||||||
def validate(xml, schema):
|
def validate(xml, schema):
|
||||||
schema.validate(xml)
|
schema.validate(xml)
|
||||||
|
|||||||
@@ -1,61 +1,50 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- DIAN Genericode listas de validacion :: Ultima modificación 18-02-2019 - evb-->
|
<!-- 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/">
|
<gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/">
|
||||||
<Identification>
|
<Identification>
|
||||||
<ShortName>TarifaImpuestos</ShortName>
|
<ShortName>TarifaImpuestos</ShortName>
|
||||||
<LongName xml:lang="es">Tarifas por Impuesto</LongName>
|
<LongName xml:lang="es">Tarifas por Impuesto</LongName>
|
||||||
<Version>1</Version>
|
<Version>1</Version>
|
||||||
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TarifaImpuestos</CanonicalUri>
|
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TarifaImpuestos</CanonicalUri>
|
||||||
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TarifaImpuestos-2.1</CanonicalVersionUri>
|
<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>
|
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TarifaImpuestos-2.1.gc</LocationUri>
|
||||||
<Agency>
|
<Agency>
|
||||||
<LongName xml:lang="es">DIAN (Dirección de Impuestos y Aduanas Nacionales)</LongName>
|
<LongName xml:lang="es">DIAN (Dirección de Impuestos y Aduanas Nacionales)</LongName>
|
||||||
<Identifier>195</Identifier>
|
<Identifier>195</Identifier>
|
||||||
</Agency>
|
</Agency>
|
||||||
</Identification>
|
</Identification>
|
||||||
<ColumnSet>
|
<ColumnSet>
|
||||||
<Column Id="code" Use="required">
|
<Column Id="code" Use="required">
|
||||||
<ShortName>Code</ShortName>
|
<ShortName>Code</ShortName>
|
||||||
<LongName xml:lang="es">Codigo Comun</LongName>
|
<LongName xml:lang="es">Codigo Comun</LongName>
|
||||||
<Data Type="normalizedString"/>
|
<Data Type="normalizedString"/>
|
||||||
</Column>
|
</Column>
|
||||||
<Column Id="name" Use="required">
|
<Column Id="name" Use="required">
|
||||||
<ShortName>Name</ShortName>
|
<ShortName>Name</ShortName>
|
||||||
<LongName xml:lang="es">Nombre</LongName>
|
<LongName xml:lang="es">Nombre</LongName>
|
||||||
<Data Type="string"/>
|
<Data Type="string"/>
|
||||||
</Column>
|
</Column>
|
||||||
<Column Id="description" Use="required">
|
<Column Id="description" Use="required">
|
||||||
<ShortName>Description</ShortName>
|
<ShortName>Description</ShortName>
|
||||||
<LongName xml:lang="es">Descripcion</LongName>
|
<LongName xml:lang="es">Descripcion</LongName>
|
||||||
<Data Type="string"/>
|
<Data Type="string"/>
|
||||||
</Column>
|
</Column>
|
||||||
<Key Id="codeKey">
|
<Key Id="codeKey">
|
||||||
<ShortName>CodeKey</ShortName>
|
<ShortName>CodeKey</ShortName>
|
||||||
<ColumnRef Ref="code"/>
|
<ColumnRef Ref="code"/>
|
||||||
</Key>
|
</Key>
|
||||||
</ColumnSet>
|
</ColumnSet>
|
||||||
<SimpleCodeList>
|
<SimpleCodeList>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>15.00</SimpleValue>
|
<SimpleValue>15.00</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>ReteIVA</SimpleValue>
|
<SimpleValue>ReteIVA</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="description">
|
<Value ColumnRef="description">
|
||||||
<SimpleValue>ReteIVA</SimpleValue>
|
<SimpleValue>ReteIVA</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
</SimpleCodeList>
|
||||||
<Value ColumnRef="code">
|
</gc:CodeList>
|
||||||
<SimpleValue>100.00</SimpleValue>
|
|
||||||
</Value>
|
|
||||||
<Value ColumnRef="name">
|
|
||||||
<SimpleValue>ReteIVA</SimpleValue>
|
|
||||||
</Value>
|
|
||||||
<Value ColumnRef="description">
|
|
||||||
<SimpleValue>ReteIVA</SimpleValue>
|
|
||||||
</Value>
|
|
||||||
</Row>
|
|
||||||
</SimpleCodeList>
|
|
||||||
</gc:CodeList>
|
|
||||||
|
|||||||
@@ -1,100 +1,74 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- DIAN Genericode listas de valores: Ultima modificación 03-04-2022 - wcbr-->
|
<!-- 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/">
|
<gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/">
|
||||||
<Identification>
|
<Identification>
|
||||||
<ShortName>TipoDocumento</ShortName>
|
<ShortName>TipoDocumento</ShortName>
|
||||||
<LongName xml:lang="es">Tipo de Documento</LongName>
|
<LongName xml:lang="es">Tipo de Documento</LongName>
|
||||||
<Version>1</Version>
|
<Version>1</Version>
|
||||||
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoDocumento</CanonicalUri>
|
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoDocumento</CanonicalUri>
|
||||||
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoDocumento-2.1</CanonicalVersionUri>
|
<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>
|
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TipoDocumento-2.1.gc</LocationUri>
|
||||||
<Agency>
|
<Agency>
|
||||||
<LongName xml:lang="es">DIAN (Dirección de Impuestos y Aduanas Nacionales)</LongName>
|
<LongName xml:lang="es">DIAN (Dirección de Impuestos y Aduanas Nacionales)</LongName>
|
||||||
<Identifier>195</Identifier>
|
<Identifier>195</Identifier>
|
||||||
</Agency>
|
</Agency>
|
||||||
</Identification>
|
</Identification>
|
||||||
<ColumnSet>
|
<ColumnSet>
|
||||||
<Column Id="code" Use="required">
|
<Column Id="code" Use="required">
|
||||||
<ShortName>Code</ShortName>
|
<ShortName>Code</ShortName>
|
||||||
<LongName xml:lang="es">Codigo Comun</LongName>
|
<LongName xml:lang="es">Codigo Comun</LongName>
|
||||||
<Data Type="normalizedString"/>
|
<Data Type="normalizedString"/>
|
||||||
</Column>
|
</Column>
|
||||||
<Column Id="name" Use="required">
|
<Column Id="name" Use="required">
|
||||||
<ShortName>Name</ShortName>
|
<ShortName>Name</ShortName>
|
||||||
<LongName xml:lang="es">Nombre</LongName>
|
<LongName xml:lang="es">Nombre</LongName>
|
||||||
<Data Type="string"/>
|
<Data Type="string"/>
|
||||||
</Column>
|
</Column>
|
||||||
<Key Id="codeKey">
|
<Key Id="codeKey">
|
||||||
<ShortName>CodeKey</ShortName>
|
<ShortName>CodeKey</ShortName>
|
||||||
<ColumnRef Ref="code"/>
|
<ColumnRef Ref="code"/>
|
||||||
</Key>
|
</Key>
|
||||||
</ColumnSet>
|
</ColumnSet>
|
||||||
<SimpleCodeList>
|
<SimpleCodeList>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>01</SimpleValue>
|
<SimpleValue>01</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>Factura electrónica de Venta</SimpleValue>
|
<SimpleValue>Factura de Venta Nacional</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="description">
|
</Row>
|
||||||
<SimpleValue>Tipos de factura</SimpleValue>
|
<Row>
|
||||||
</Value>
|
<Value ColumnRef="code">
|
||||||
</Row>
|
<SimpleValue>02</SimpleValue>
|
||||||
<Row>
|
</Value>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>02</SimpleValue>
|
<SimpleValue>Factura de Exportación </SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
</Row>
|
||||||
<SimpleValue>Factura electrónica de venta con propósito de exportación</SimpleValue>
|
<Row>
|
||||||
</Value>
|
<Value ColumnRef="code">
|
||||||
<Value ColumnRef="description">
|
<SimpleValue>03</SimpleValue>
|
||||||
<SimpleValue>Tipos de factura</SimpleValue>
|
</Value>
|
||||||
</Value>
|
<Value ColumnRef="name">
|
||||||
</Row>
|
<SimpleValue>Factura de Contingencia</SimpleValue>
|
||||||
<Row>
|
</Value>
|
||||||
<Value ColumnRef="code">
|
</Row>
|
||||||
<SimpleValue>03</SimpleValue>
|
<Row>
|
||||||
</Value>
|
<Value ColumnRef="code">
|
||||||
<Value ColumnRef="name">
|
<SimpleValue>91</SimpleValue>
|
||||||
<SimpleValue>Factura de talonario o papel con numeración de contingencia.</SimpleValue>
|
</Value>
|
||||||
</Value>
|
<Value ColumnRef="name">
|
||||||
<Value ColumnRef="description">
|
<SimpleValue>Nota Crédito</SimpleValue>
|
||||||
<SimpleValue>Tipos de factura</SimpleValue>
|
</Value>
|
||||||
</Value>
|
</Row>
|
||||||
</Row>
|
<Row>
|
||||||
<Row>
|
<Value ColumnRef="code">
|
||||||
<Value ColumnRef="code">
|
<SimpleValue>92</SimpleValue>
|
||||||
<SimpleValue>04</SimpleValue>
|
</Value>
|
||||||
</Value>
|
<Value ColumnRef="name">
|
||||||
<Value ColumnRef="name">
|
<SimpleValue>Nota Débito</SimpleValue>
|
||||||
<SimpleValue>Factura electrónica de Venta por Contingencia DIAN</SimpleValue>
|
</Value>
|
||||||
</Value>
|
</Row>
|
||||||
<Value ColumnRef="description">
|
</SimpleCodeList>
|
||||||
<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>
|
|
||||||
</SimpleCodeList>
|
|
||||||
</gc:CodeList>
|
</gc:CodeList>
|
||||||
|
|||||||
@@ -1,171 +1,162 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- DIAN Genericode listas de valores:: Ultima modificación 18-02-2019 - evb-->
|
<!-- 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/">
|
<gc:CodeList xmlns:gc="http://docs.oasis-open.org/codelist/ns/genericode/1.0/">
|
||||||
<Identification>
|
<Identification>
|
||||||
<ShortName>TipoImpuesto</ShortName>
|
<ShortName>TipoImpuesto</ShortName>
|
||||||
<LongName xml:lang="es">Tipo de Tributos</LongName>
|
<LongName xml:lang="es">Tipo de Tributos</LongName>
|
||||||
<Version>1</Version>
|
<Version>1</Version>
|
||||||
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoImpuesto</CanonicalUri>
|
<CanonicalUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoImpuesto</CanonicalUri>
|
||||||
<CanonicalVersionUri>urn:dian:names:especificacion:ubl:listacodigos:gc:TipoImpuesto-2.1</CanonicalVersionUri>
|
<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>
|
<LocationUri>http://dian.gov.co/ubl/os-ubl-2.0/cl/gc/default/TipoImpuesto-2.1.gc</LocationUri>
|
||||||
<Agency>
|
<Agency>
|
||||||
<LongName xml:lang="es">DIAN (Dirección de Impuestos y Aduanas Nacionales)</LongName>
|
<LongName xml:lang="es">DIAN (Dirección de Impuestos y Aduanas Nacionales)</LongName>
|
||||||
<Identifier>195</Identifier>
|
<Identifier>195</Identifier>
|
||||||
</Agency>
|
</Agency>
|
||||||
</Identification>
|
</Identification>
|
||||||
<ColumnSet>
|
<ColumnSet>
|
||||||
<Column Id="code" Use="required">
|
<Column Id="code" Use="required">
|
||||||
<ShortName>Code</ShortName>
|
<ShortName>Code</ShortName>
|
||||||
<LongName xml:lang="es">Codigo Comun</LongName>
|
<LongName xml:lang="es">Codigo Comun</LongName>
|
||||||
<Data Type="normalizedString"/>
|
<Data Type="normalizedString"/>
|
||||||
</Column>
|
</Column>
|
||||||
<Column Id="name" Use="required">
|
<Column Id="name" Use="required">
|
||||||
<ShortName>Name</ShortName>
|
<ShortName>Name</ShortName>
|
||||||
<LongName xml:lang="es">Nombre</LongName>
|
<LongName xml:lang="es">Nombre</LongName>
|
||||||
<Data Type="string"/>
|
<Data Type="string"/>
|
||||||
</Column>
|
</Column>
|
||||||
<Key Id="codeKey">
|
<Key Id="codeKey">
|
||||||
<ShortName>CodeKey</ShortName>
|
<ShortName>CodeKey</ShortName>
|
||||||
<ColumnRef Ref="code"/>
|
<ColumnRef Ref="code"/>
|
||||||
</Key>
|
</Key>
|
||||||
</ColumnSet>
|
</ColumnSet>
|
||||||
<SimpleCodeList>
|
<SimpleCodeList>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>01</SimpleValue>
|
<SimpleValue>01</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>IVA</SimpleValue>
|
<SimpleValue>IVA</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>02</SimpleValue>
|
<SimpleValue>02</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>IC</SimpleValue>
|
<SimpleValue>IC</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>03</SimpleValue>
|
<SimpleValue>03</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>ICA</SimpleValue>
|
<SimpleValue>ICA</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>04</SimpleValue>
|
<SimpleValue>04</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>INC</SimpleValue>
|
<SimpleValue>INC</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>05</SimpleValue>
|
<SimpleValue>05</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>ReteIVA</SimpleValue>
|
<SimpleValue>ReteIVA</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>06</SimpleValue>
|
<SimpleValue>06</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>ReteRenta</SimpleValue>
|
<SimpleValue>ReteFuente</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>07</SimpleValue>
|
<SimpleValue>07</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>ReteICA</SimpleValue>
|
<SimpleValue>ReteICA</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>08</SimpleValue>
|
<SimpleValue>08</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>ReteCREE</SimpleValue>
|
<SimpleValue>ReteCREE</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>20</SimpleValue>
|
<SimpleValue>20</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>FtoHorticultura</SimpleValue>
|
<SimpleValue>FtoHorticultura</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>21</SimpleValue>
|
<SimpleValue>21</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>Timbre</SimpleValue>
|
<SimpleValue>Timbre</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>22</SimpleValue>
|
<SimpleValue>22</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>Bolsas</SimpleValue>
|
<SimpleValue>Bolsas</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>23</SimpleValue>
|
<SimpleValue>23</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>INCarbono</SimpleValue>
|
<SimpleValue>INCarbono</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>24</SimpleValue>
|
<SimpleValue>24</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>INCombustibles</SimpleValue>
|
<SimpleValue>INCombustibles</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>25</SimpleValue>
|
<SimpleValue>25</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>Sobretasa Combustibles</SimpleValue>
|
<SimpleValue>Sobretasa Combustibles</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>26</SimpleValue>
|
<SimpleValue>26</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>Sordicom</SimpleValue>
|
<SimpleValue>Sordicom</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>30</SimpleValue>
|
<SimpleValue>ZZ</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
<Value ColumnRef="name">
|
<Value ColumnRef="name">
|
||||||
<SimpleValue>Impuesto al Consumo de Datos</SimpleValue>
|
<SimpleValue>Nombre de la figura tributaria</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
|
</SimpleCodeList>
|
||||||
<Row>
|
|
||||||
<Value ColumnRef="code">
|
|
||||||
<SimpleValue>ZZ</SimpleValue>
|
|
||||||
</Value>
|
|
||||||
<Value ColumnRef="name">
|
|
||||||
<SimpleValue>Nombre de la figura tributaria</SimpleValue>
|
|
||||||
</Value>
|
|
||||||
</Row>
|
|
||||||
</SimpleCodeList>
|
|
||||||
</gc:CodeList>
|
</gc:CodeList>
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -30,6 +30,46 @@
|
|||||||
</Key>
|
</Key>
|
||||||
</ColumnSet>
|
</ColumnSet>
|
||||||
<SimpleCodeList>
|
<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>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>O-13</SimpleValue>
|
<SimpleValue>O-13</SimpleValue>
|
||||||
@@ -38,6 +78,14 @@
|
|||||||
<SimpleValue>Gran contribuyente</SimpleValue>
|
<SimpleValue>Gran contribuyente</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Value ColumnRef="code">
|
||||||
|
<SimpleValue>O-14</SimpleValue>
|
||||||
|
</Value>
|
||||||
|
<Value ColumnRef="name">
|
||||||
|
<SimpleValue>Informante de exógena</SimpleValue>
|
||||||
|
</Value>
|
||||||
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>O-15</SimpleValue>
|
<SimpleValue>O-15</SimpleValue>
|
||||||
@@ -46,6 +94,38 @@
|
|||||||
<SimpleValue>Autorretenedor</SimpleValue>
|
<SimpleValue>Autorretenedor</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</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>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>O-23</SimpleValue>
|
<SimpleValue>O-23</SimpleValue>
|
||||||
@@ -54,6 +134,62 @@
|
|||||||
<SimpleValue>Agente de retención en el impuesto sobre las ventas</SimpleValue>
|
<SimpleValue>Agente de retención en el impuesto sobre las ventas</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</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>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>O-47</SimpleValue>
|
<SimpleValue>O-47</SimpleValue>
|
||||||
@@ -78,6 +214,782 @@
|
|||||||
<SimpleValue>No responsable de IVA</SimpleValue>
|
<SimpleValue>No responsable de IVA</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</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>
|
<Row>
|
||||||
<Value ColumnRef="code">
|
<Value ColumnRef="code">
|
||||||
<SimpleValue>R-99-PN</SimpleValue>
|
<SimpleValue>R-99-PN</SimpleValue>
|
||||||
|
|||||||
@@ -62,13 +62,5 @@
|
|||||||
<SimpleValue>Régimen simple de tributación</SimpleValue>
|
<SimpleValue>Régimen simple de tributación</SimpleValue>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
|
||||||
<Value ColumnRef="code">
|
|
||||||
<SimpleValue>ZZ</SimpleValue>
|
|
||||||
</Value>
|
|
||||||
<Value ColumnRef="name">
|
|
||||||
<SimpleValue>No aplica</SimpleValue>
|
|
||||||
</Value>
|
|
||||||
</Row>
|
|
||||||
</SimpleCodeList>
|
</SimpleCodeList>
|
||||||
</gc:CodeList>
|
</gc:CodeList>
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ class CodeList:
|
|||||||
def _load(self, filename, primary_column):
|
def _load(self, filename, primary_column):
|
||||||
tree = etree.parse(filename)
|
tree = etree.parse(filename)
|
||||||
|
|
||||||
# obtener identificadores...
|
#obtener identificadores...
|
||||||
self.short_name = tree.find('./Identification/ShortName').text
|
self.short_name = tree.find('./Identification/ShortName').text
|
||||||
self.long_name = tree.find('./Identification/LongName').text
|
self.long_name = tree.find('./Identification/LongName').text
|
||||||
self.version = tree.find('./Identification/Version').text
|
self.version = tree.find('./Identification/Version').text
|
||||||
|
|
||||||
# obtener registros...
|
#obtener registros...
|
||||||
for row in tree.findall('./SimpleCodeList/Row'):
|
for row in tree.findall('./SimpleCodeList/Row'):
|
||||||
new_row = self.xmlrow_to_dict(row)
|
new_row = self.xmlrow_to_dict(row)
|
||||||
primary_key = new_row[primary_column]
|
primary_key = new_row[primary_column]
|
||||||
@@ -34,9 +34,9 @@ class CodeList:
|
|||||||
def xmlrow_to_dict(self, xmlrow):
|
def xmlrow_to_dict(self, xmlrow):
|
||||||
row = {}
|
row = {}
|
||||||
|
|
||||||
# construir registro...
|
#construir registro...
|
||||||
for value in list(xmlrow):
|
for value in xmlrow.getchildren():
|
||||||
row[value.attrib['ColumnRef']] = list(value)[0].text
|
row[value.attrib['ColumnRef']] = value.getchildren()[0].text
|
||||||
|
|
||||||
return row
|
return row
|
||||||
|
|
||||||
@@ -60,7 +60,6 @@ class CodeList:
|
|||||||
# nombres de variables igual a ./Identification/ShortName
|
# nombres de variables igual a ./Identification/ShortName
|
||||||
# TODO: garantizar unica carga en python
|
# TODO: garantizar unica carga en python
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['TipoOrganizacion',
|
__all__ = ['TipoOrganizacion',
|
||||||
'TipoResponsabilidad',
|
'TipoResponsabilidad',
|
||||||
'TipoAmbiente',
|
'TipoAmbiente',
|
||||||
@@ -73,88 +72,33 @@ __all__ = ['TipoOrganizacion',
|
|||||||
'Municipio',
|
'Municipio',
|
||||||
'Departamento']
|
'Departamento']
|
||||||
|
|
||||||
|
|
||||||
def path_for_codelist(name):
|
def path_for_codelist(name):
|
||||||
return os.path.join(DATA_DIR, name)
|
return os.path.join(DATA_DIR, name)
|
||||||
|
|
||||||
|
TipoOrganizacion = CodeList(path_for_codelist('TipoOrganizacion-2.1.gc'), 'code', 'name')
|
||||||
TipoOrganizacion = CodeList(path_for_codelist(
|
TipoResponsabilidad = CodeList(path_for_codelist('TipoResponsabilidad-2.1.gc'), 'code', 'name')\
|
||||||
'TipoOrganizacion-2.1.gc'), 'code', 'name')
|
.update(CodeList(path_for_codelist('TipoResponsabilidad-2.1.custom.gc'), 'code', 'name'))
|
||||||
TipoResponsabilidad = CodeList(
|
TipoAmbiente = CodeList(path_for_codelist('TipoAmbiente-2.1.gc'), 'code', 'name')
|
||||||
path_for_codelist('TipoResponsabilidad-2.1.gc'),
|
TipoDocumento = CodeList(path_for_codelist('TipoDocumento-2.1.gc'), 'code', 'name')
|
||||||
'code',
|
TipoImpuesto = CodeList(path_for_codelist('TipoImpuesto-2.1.gc'), 'code', 'name')\
|
||||||
'name') .update(
|
.update(CodeList(path_for_codelist('TipoImpuesto-2.1.custom.gc'), 'code', 'name'))
|
||||||
CodeList(
|
CodigoPrecioReferencia = CodeList(path_for_codelist('CodigoPrecioReferencia-2.1.gc'), 'code', 'name')
|
||||||
path_for_codelist('TipoResponsabilidad-2.1.custom.gc'),
|
|
||||||
'code',
|
|
||||||
'name'))
|
|
||||||
TipoAmbiente = CodeList(path_for_codelist(
|
|
||||||
'TipoAmbiente-2.1.gc'), 'code', 'name')
|
|
||||||
TipoDocumento = CodeList(path_for_codelist(
|
|
||||||
'TipoDocumento-2.1.gc'), 'code', 'name')
|
|
||||||
TipoImpuesto = CodeList(
|
|
||||||
path_for_codelist('TipoImpuesto-2.1.gc'),
|
|
||||||
'code',
|
|
||||||
'name') .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')
|
MediosPago = CodeList(path_for_codelist('MediosPago-2.1.gc'), 'code', 'name')
|
||||||
FormasPago = CodeList(path_for_codelist('FormasPago-2.1.gc'), 'code', 'name')
|
FormasPago = CodeList(path_for_codelist('FormasPago-2.1.gc'), 'code', 'name')
|
||||||
RegimenFiscal = CodeList(path_for_codelist(
|
RegimenFiscal = CodeList(path_for_codelist('RegimenFiscal-2.1.custom.gc'), 'code', 'name')
|
||||||
'RegimenFiscal-2.1.custom.gc'), 'code', 'name')
|
TipoOperacionNC = CodeList(path_for_codelist('TipoOperacionNC-2.1.gc'), 'code', 'name')
|
||||||
TipoOperacionNC = CodeList(path_for_codelist(
|
TipoOperacionND = CodeList(path_for_codelist('TipoOperacionND-2.1 - copia.gc'), 'code', 'name')
|
||||||
'TipoOperacionNC-2.1.gc'), 'code', 'name')
|
TipoOperacionF = CodeList(path_for_codelist('TipoOperacionF-2.1.gc'), 'code', 'name')\
|
||||||
TipoOperacionNCDS = CodeList(path_for_codelist(
|
.update(CodeList(path_for_codelist('TipoOperacionF-2.1.custom.gc'), 'code', 'name'))
|
||||||
'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'))
|
|
||||||
Municipio = CodeList(path_for_codelist('Municipio-2.1.gc'), 'code', 'name')
|
Municipio = CodeList(path_for_codelist('Municipio-2.1.gc'), 'code', 'name')
|
||||||
Departamento = CodeList(path_for_codelist(
|
Departamento = CodeList(path_for_codelist('Departamentos-2.1.gc'), 'code', 'name')
|
||||||
'Departamentos-2.1.gc'), 'code', 'name')
|
|
||||||
Paises = CodeList(path_for_codelist('Paises-2.1.gc'), 'code', 'name')
|
Paises = CodeList(path_for_codelist('Paises-2.1.gc'), 'code', 'name')
|
||||||
TipoIdFiscal = CodeList(path_for_codelist(
|
TipoIdFiscal = CodeList(path_for_codelist('TipoIdFiscal-2.1.gc'), 'code', 'name')
|
||||||
'TipoIdFiscal-2.1.gc'), 'code', 'name')
|
CodigoDescuento = CodeList(path_for_codelist('CodigoDescuento-2.1.gc'), 'code', 'name')
|
||||||
CodigoDescuento = CodeList(path_for_codelist(
|
UnidadesMedida = CodeList(path_for_codelist('UnidadesMedida-2.1.gc'), 'code', 'name')
|
||||||
'CodigoDescuento-2.1.gc'), 'code', 'name')
|
TipoTrabajador = CodeList(path_for_codelist('TipoTrabajador-2.1.gc'), 'code', 'name')
|
||||||
UnidadesMedida = CodeList(path_for_codelist(
|
SubTipoTrabajador = CodeList(path_for_codelist('SubTipoTrabajador-2.1.gc'), 'code', 'name')
|
||||||
'UnidadesMedida-2.1.gc'), 'code', 'name')
|
TipoContrato = CodeList(path_for_codelist('TipoContrato-2.1.gc'), 'code', 'name')
|
||||||
TipoTrabajador = CodeList(path_for_codelist(
|
PeriodoNomina = CodeList(path_for_codelist('PeriodoNomina-2.1.gc'), 'code', 'name')
|
||||||
'TipoTrabajador-2.1.gc'), 'code', 'name')
|
|
||||||
SubTipoTrabajador = CodeList(path_for_codelist(
|
|
||||||
'SubTipoTrabajador-2.1.gc'), 'code', 'name')
|
|
||||||
TipoContrato = CodeList(path_for_codelist(
|
|
||||||
'TipoContrato-2.1.gc'), 'code', 'name')
|
|
||||||
PeriodoNomina = CodeList(path_for_codelist(
|
|
||||||
'PeriodoNomina-2.1.gc'), 'code', 'name')
|
|
||||||
TipoMoneda = CodeList(path_for_codelist('TipoMoneda-2.1.gc'), 'code', 'name')
|
TipoMoneda = CodeList(path_for_codelist('TipoMoneda-2.1.gc'), 'code', 'name')
|
||||||
IdiomaISO6391 = CodeList(path_for_codelist(
|
IdiomaISO6391 = CodeList(path_for_codelist('Idioma-2.1.gc'), 'iso-639-1', 'name')
|
||||||
'Idioma-2.1.gc'), 'iso-639-1', 'name')
|
|
||||||
|
|||||||
480
facho/fe/fe.py
480
facho/fe/fe.py
@@ -1,115 +1,63 @@
|
|||||||
# This file is part of facho. The COPYRIGHT file at the top level of
|
# This file is part of facho. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
|
from lxml.builder import E
|
||||||
from ..facho import FachoXML, FachoXMLExtension, LXMLBuilder
|
from ..facho import FachoXML, FachoXMLExtension, LXMLBuilder
|
||||||
import uuid
|
import uuid
|
||||||
import xmlsig
|
import xmlsig
|
||||||
import xades
|
import xades
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import OpenSSL
|
||||||
import zipfile
|
import zipfile
|
||||||
# import warnings
|
import warnings
|
||||||
import hashlib
|
import hashlib
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from .data.dian import codelist
|
from .data.dian import codelist
|
||||||
from . import form
|
from . import form
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
# from pathlib import Path
|
from pathlib import Path
|
||||||
from dateutil import tz
|
|
||||||
|
|
||||||
from cryptography.hazmat.primitives.serialization import pkcs12
|
|
||||||
|
|
||||||
# Monkey-patch xades/xmlsig para compatibilidad con pyOpenSSL >= 24
|
|
||||||
# (PKCS12 fue eliminado de OpenSSL.crypto, pero ambas librerías lo referencian)
|
|
||||||
import OpenSSL
|
|
||||||
import xades.xades_context
|
|
||||||
|
|
||||||
if not hasattr(OpenSSL.crypto, 'PKCS12'):
|
|
||||||
def _patched_load_pkcs12(self, key):
|
|
||||||
if isinstance(key, tuple):
|
|
||||||
self.x509 = key[1]
|
|
||||||
self.public_key = key[1].public_key()
|
|
||||||
self.private_key = key[0]
|
|
||||||
else:
|
|
||||||
raise NotImplementedError("unsupported key type")
|
|
||||||
xades.xades_context.XAdESContext.load_pkcs12 = _patched_load_pkcs12
|
|
||||||
|
|
||||||
AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code']
|
AMBIENTE_PRUEBAS = codelist.TipoAmbiente.by_name('Pruebas')['code']
|
||||||
AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code']
|
AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code']
|
||||||
|
|
||||||
|
|
||||||
SCHEME_AGENCY_ATTRS = {
|
SCHEME_AGENCY_ATTRS = {
|
||||||
'schemeAgencyName': 'CO, DIAN (Dirección de Impuestos y Aduanas'
|
'schemeAgencyName': 'CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)',
|
||||||
' Nacionales)',
|
'schemeAgencyID': '195'
|
||||||
'schemeAgencyID': '195'}
|
}
|
||||||
|
|
||||||
|
|
||||||
# RESOLUCION 0001: pagina 516
|
# RESOLUCION 0001: pagina 516
|
||||||
POLICY_ID = (
|
POLICY_ID = 'https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf'
|
||||||
'https://facturaelectronica.dian.gov.co/politicadefirma/v2'
|
POLICY_NAME = u'Política de firma para facturas electrónicas de la República de Colombia.'
|
||||||
'/politicadefirmav2.pdf'
|
|
||||||
)
|
|
||||||
POLICY_NAME = (
|
|
||||||
u'Política de firma para facturas electrónicas de la República de '
|
|
||||||
u'Colombia.'
|
|
||||||
)
|
|
||||||
|
|
||||||
Bogota = tz.gettz('America/Bogota')
|
|
||||||
# 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 = {
|
NAMESPACES = {
|
||||||
'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
|
#'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2',
|
||||||
'cac': (
|
#'no': 'dian:gov:co:facturaelectronica:NominaIndividual',
|
||||||
'urn:oasis:names:specification:ubl:schema:xsd'
|
'noa': 'dian:gov:co:facturaelectronica:NominaIndividualDeAjuste',
|
||||||
':CommonAggregateComponents-2'),
|
# 'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
|
||||||
'cbc': 'urn:oasis:names:specification:ubl:schema:xsd'
|
'xs': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
':CommonBasicComponents-2',
|
# 'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
|
||||||
'ext': (
|
#'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
|
||||||
'urn:oasis:names:specification:ubl:schema:xsd'
|
# 'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1',
|
||||||
':CommonExtensionComponents-2'),
|
# 'clm54217': 'urn:un:unece:uncefact:codelist:specification:54217:2001',
|
||||||
'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2',
|
# 'clmIANAMIMEMediaType': 'urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003',``
|
||||||
'sts': 'dian:gov:co:facturaelectronica:Structures-2-1',
|
'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2',
|
||||||
'udt': (
|
# 'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2',
|
||||||
'urn:un:unece:uncefact:data:specification'
|
# 'sts': 'dian:gov:co:facturaelectronica:Structures-2-1',
|
||||||
':UnqualifiedDataTypesSchemaModule:2'),
|
# 'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2',
|
||||||
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
'ds': 'http://www.w3.org/2000/09/xmldsig#',
|
'xades': 'http://uri.etsi.org/01903/v1.3.2#',
|
||||||
'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#',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def fe_from_string(document: str) -> FachoXML:
|
def fe_from_string(document: str) -> FachoXML:
|
||||||
return FeXML.from_string(document)
|
return FeXML.from_string(document)
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
# from contextlib import contextmanager
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def mock_xades_policy():
|
def mock_xades_policy():
|
||||||
from mock import patch
|
from mock import patch
|
||||||
@@ -127,38 +75,28 @@ def mock_xades_policy():
|
|||||||
mock.return_value = UrllibPolicyMock()
|
mock.return_value = UrllibPolicyMock()
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
class FeXML(FachoXML):
|
class FeXML(FachoXML):
|
||||||
|
|
||||||
def __init__(self, root, namespace):
|
def __init__(self, root, namespace):
|
||||||
# raise Exception(namespace)
|
|
||||||
super().__init__("{%s}%s" % (namespace, root),
|
super().__init__("{%s}%s" % (namespace, root),
|
||||||
nsmap=NAMESPACES)
|
nsmap=NAMESPACES)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_string(cls, document: str) -> 'FeXML':
|
def from_string(cls, document: str) -> 'FeXML':
|
||||||
return super().from_string(document, namespaces=NAMESPACES)
|
return super().from_string(document, namespaces=NAMESPACES)
|
||||||
|
|
||||||
def tostring(self, **kw):
|
def tostring(self, **kw):
|
||||||
# MACHETE(bit4bit) la DIAN espera que la etiqueta raiz no este en un
|
# MACHETE(bit4bit) la DIAN espera que la etiqueta raiz no este en un namespace
|
||||||
# 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)\
|
return super().tostring(**kw)\
|
||||||
.replace(xmlns_name + ':', '')\
|
.replace("noa:", "")\
|
||||||
.replace('xmlns:' + xmlns_name, 'xmlns')\
|
.replace("xmlns:noa", "xmlns")\
|
||||||
.replace(root_namespace, urn_oasis)
|
.replace("change", "xsi:schemaLocation")
|
||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionCUDFE(FachoXMLExtension):
|
class DianXMLExtensionCUDFE(FachoXMLExtension):
|
||||||
def __init__(self, invoice, tipo_ambiente=AMBIENTE_PRUEBAS):
|
|
||||||
|
def __init__(self, invoice, tipo_ambiente = AMBIENTE_PRUEBAS):
|
||||||
self.tipo_ambiente = tipo_ambiente
|
self.tipo_ambiente = tipo_ambiente
|
||||||
self.invoice = invoice
|
self.invoice = invoice
|
||||||
|
|
||||||
@@ -173,12 +111,9 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
|
|
||||||
def _get_qrcode(self, cufe):
|
def _get_qrcode(self, cufe):
|
||||||
url_for = {
|
url_for = {
|
||||||
AMBIENTE_PRUEBAS: (
|
AMBIENTE_PRUEBAS: 'https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey=',
|
||||||
'https://catalogo-vpfe-hab.dian.gov.co/document/'
|
AMBIENTE_PRODUCCION: 'https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey='
|
||||||
'searchqr?documentkey='),
|
}
|
||||||
AMBIENTE_PRODUCCION: (
|
|
||||||
'https://catalogo-vpfe.dian.gov.co/document/'
|
|
||||||
'searchqr?documentkey=')}
|
|
||||||
return url_for[self.tipo_ambiente] + cufe
|
return url_for[self.tipo_ambiente] + cufe
|
||||||
|
|
||||||
def build(self, fachoxml):
|
def build(self, fachoxml):
|
||||||
@@ -186,33 +121,12 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
fachoxml.set_element('./cbc:UUID', cufe,
|
fachoxml.set_element('./cbc:UUID', cufe,
|
||||||
schemeID=self.tipo_ambiente,
|
schemeID=self.tipo_ambiente,
|
||||||
schemeName=self.schemeName())
|
schemeName=self.schemeName())
|
||||||
|
#DIAN 1.8.-2021: FAD03
|
||||||
if self.schemeName() == "CUDS-SHA384":
|
fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta')
|
||||||
if fachoxml.tag_document() == 'Invoice':
|
fachoxml.set_element('./cbc:ProfileExecutionID', self._tipo_ambiente_int())
|
||||||
fachoxml.set_element(
|
#DIAN 1.7.-2020: FAB36
|
||||||
'./cbc:ProfileID',
|
fachoxml.set_element('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode',
|
||||||
'DIAN 2.1: documento soporte en adquisiciones '
|
self._get_qrcode(cufe))
|
||||||
'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')
|
|
||||||
|
|
||||||
# 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',
|
|
||||||
self._get_qrcode(cufe))
|
|
||||||
|
|
||||||
def issue_time(self, datetime_):
|
def issue_time(self, datetime_):
|
||||||
return datetime_.strftime('%H:%M:%S-05:00')
|
return datetime_.strftime('%H:%M:%S-05:00')
|
||||||
@@ -227,10 +141,8 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
build_vars['FecFac'] = self.issue_date(invoice.invoice_issue)
|
build_vars['FecFac'] = self.issue_date(invoice.invoice_issue)
|
||||||
build_vars['HoraFac'] = self.issue_time(invoice.invoice_issue)
|
build_vars['HoraFac'] = self.issue_time(invoice.invoice_issue)
|
||||||
# PAG 601
|
# PAG 601
|
||||||
build_vars['ValorBruto'] = (
|
build_vars['ValorBruto'] = invoice.invoice_legal_monetary_total.line_extension_amount
|
||||||
invoice.invoice_legal_monetary_total.line_extension_amount)
|
build_vars['ValorTotalPagar'] = invoice.invoice_legal_monetary_total.payable_amount
|
||||||
build_vars['ValorTotalPagar'
|
|
||||||
] = invoice.invoice_legal_monetary_total.payable_amount
|
|
||||||
ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0))
|
ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0))
|
||||||
build_vars['CodImpuesto1'] = '01'
|
build_vars['CodImpuesto1'] = '01'
|
||||||
build_vars['CodImpuesto2'] = '04'
|
build_vars['CodImpuesto2'] = '04'
|
||||||
@@ -240,8 +152,7 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
if subtotal.scheme is not None:
|
if subtotal.scheme is not None:
|
||||||
# TODO cual es la naturaleza de tax_scheme_ident?
|
# TODO cual es la naturaleza de tax_scheme_ident?
|
||||||
codigo_impuesto = subtotal.scheme.code
|
codigo_impuesto = subtotal.scheme.code
|
||||||
ValorImpuestoPara.setdefault(
|
ValorImpuestoPara.setdefault(codigo_impuesto, form.Amount(0.0))
|
||||||
codigo_impuesto, form.Amount(0.0))
|
|
||||||
ValorImpuestoPara[codigo_impuesto] += subtotal.tax_amount
|
ValorImpuestoPara[codigo_impuesto] += subtotal.tax_amount
|
||||||
|
|
||||||
build_vars['ValorImpuestoPara'] = ValorImpuestoPara
|
build_vars['ValorImpuestoPara'] = ValorImpuestoPara
|
||||||
@@ -261,8 +172,7 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionCUFE(DianXMLExtensionCUDFE):
|
class DianXMLExtensionCUFE(DianXMLExtensionCUDFE):
|
||||||
def __init__(
|
def __init__(self, invoice, clave_tecnica = '', tipo_ambiente = AMBIENTE_PRUEBAS):
|
||||||
self, invoice, clave_tecnica='', tipo_ambiente=AMBIENTE_PRUEBAS):
|
|
||||||
self.tipo_ambiente = tipo_ambiente
|
self.tipo_ambiente = tipo_ambiente
|
||||||
self.clave_tecnica = clave_tecnica
|
self.clave_tecnica = clave_tecnica
|
||||||
self.invoice = invoice
|
self.invoice = invoice
|
||||||
@@ -281,40 +191,25 @@ class DianXMLExtensionCUFE(DianXMLExtensionCUDFE):
|
|||||||
CodImpuesto2 = build_vars['CodImpuesto2']
|
CodImpuesto2 = build_vars['CodImpuesto2']
|
||||||
CodImpuesto3 = build_vars['CodImpuesto3']
|
CodImpuesto3 = build_vars['CodImpuesto3']
|
||||||
return [
|
return [
|
||||||
'%s' %
|
'%s' % build_vars['NumFac'],
|
||||||
build_vars['NumFac'],
|
'%s' % build_vars['FecFac'],
|
||||||
'%s' %
|
'%s' % build_vars['HoraFac'],
|
||||||
build_vars['FecFac'],
|
form.Amount(build_vars['ValorBruto']).truncate_as_string(2),
|
||||||
'%s' %
|
|
||||||
build_vars['HoraFac'],
|
|
||||||
form.Amount(
|
|
||||||
build_vars['ValorBruto']).truncate_as_string(2),
|
|
||||||
CodImpuesto1,
|
CodImpuesto1,
|
||||||
build_vars['ValorImpuestoPara'].get(
|
build_vars['ValorImpuestoPara'].get(CodImpuesto1, form.Amount(0.0)).truncate_as_string(2),
|
||||||
CodImpuesto1,
|
|
||||||
form.Amount(0.0)).truncate_as_string(2),
|
|
||||||
CodImpuesto2,
|
CodImpuesto2,
|
||||||
build_vars['ValorImpuestoPara'].get(
|
build_vars['ValorImpuestoPara'].get(CodImpuesto2, form.Amount(0.0)).truncate_as_string(2),
|
||||||
CodImpuesto2,
|
|
||||||
form.Amount(0.0)).truncate_as_string(2),
|
|
||||||
CodImpuesto3,
|
CodImpuesto3,
|
||||||
build_vars['ValorImpuestoPara'].get(
|
build_vars['ValorImpuestoPara'].get(CodImpuesto3, form.Amount(0.0)).truncate_as_string(2),
|
||||||
CodImpuesto3,
|
|
||||||
form.Amount(0.0)).truncate_as_string(2),
|
|
||||||
build_vars['ValorTotalPagar'].truncate_as_string(2),
|
build_vars['ValorTotalPagar'].truncate_as_string(2),
|
||||||
'%s' %
|
'%s' % build_vars['NitOFE'],
|
||||||
build_vars['NitOFE'],
|
'%s' % build_vars['NumAdq'],
|
||||||
'%s' %
|
'%s' % build_vars['ClTec'],
|
||||||
build_vars['NumAdq'],
|
'%d' % build_vars['TipoAmb'],
|
||||||
'%s' %
|
|
||||||
build_vars['ClTec'],
|
|
||||||
'%d' %
|
|
||||||
build_vars['TipoAmb'],
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionCUDE(DianXMLExtensionCUDFE):
|
class DianXMLExtensionCUDE(DianXMLExtensionCUDFE):
|
||||||
def __init__(self, invoice, software_pin, tipo_ambiente=AMBIENTE_PRUEBAS):
|
def __init__(self, invoice, software_pin, tipo_ambiente = AMBIENTE_PRUEBAS):
|
||||||
self.tipo_ambiente = tipo_ambiente
|
self.tipo_ambiente = tipo_ambiente
|
||||||
self.software_pin = software_pin
|
self.software_pin = software_pin
|
||||||
self.invoice = invoice
|
self.invoice = invoice
|
||||||
@@ -333,86 +228,23 @@ class DianXMLExtensionCUDE(DianXMLExtensionCUDFE):
|
|||||||
CodImpuesto2 = build_vars['CodImpuesto2']
|
CodImpuesto2 = build_vars['CodImpuesto2']
|
||||||
CodImpuesto3 = build_vars['CodImpuesto3']
|
CodImpuesto3 = build_vars['CodImpuesto3']
|
||||||
return [
|
return [
|
||||||
'%s' %
|
'%s' % build_vars['NumFac'],
|
||||||
build_vars['NumFac'],
|
'%s' % build_vars['FecFac'],
|
||||||
'%s' %
|
'%s' % build_vars['HoraFac'],
|
||||||
build_vars['FecFac'],
|
form.Amount(build_vars['ValorBruto']).truncate_as_string(2),
|
||||||
'%s' %
|
|
||||||
build_vars['HoraFac'],
|
|
||||||
form.Amount(
|
|
||||||
build_vars['ValorBruto']).truncate_as_string(2),
|
|
||||||
CodImpuesto1,
|
CodImpuesto1,
|
||||||
form.Amount(
|
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0)).truncate_as_string(2),
|
||||||
build_vars['ValorImpuestoPara'].get(
|
|
||||||
CodImpuesto1,
|
|
||||||
0.0)).truncate_as_string(2),
|
|
||||||
CodImpuesto2,
|
CodImpuesto2,
|
||||||
form.Amount(
|
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto2, 0.0)).truncate_as_string(2),
|
||||||
build_vars['ValorImpuestoPara'].get(
|
|
||||||
CodImpuesto2,
|
|
||||||
0.0)).truncate_as_string(2),
|
|
||||||
CodImpuesto3,
|
CodImpuesto3,
|
||||||
form.Amount(
|
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto3, 0.0)).truncate_as_string(2),
|
||||||
build_vars['ValorImpuestoPara'].get(
|
form.Amount(build_vars['ValorTotalPagar']).truncate_as_string(2),
|
||||||
CodImpuesto3,
|
'%s' % build_vars['NitOFE'],
|
||||||
0.0)).truncate_as_string(2),
|
'%s' % build_vars['NumAdq'],
|
||||||
form.Amount(
|
'%s' % build_vars['Software-PIN'],
|
||||||
build_vars['ValorTotalPagar']).truncate_as_string(2),
|
'%d' % build_vars['TipoAmb'],
|
||||||
'%s' %
|
|
||||||
build_vars['NitOFE'],
|
|
||||||
'%s' %
|
|
||||||
build_vars['NumAdq'],
|
|
||||||
'%s' %
|
|
||||||
build_vars['Software-PIN'],
|
|
||||||
'%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']
|
|
||||||
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):
|
class DianXMLExtensionSoftwareProvider(FachoXMLExtension):
|
||||||
# RESOLUCION 0004: pagina 108
|
# RESOLUCION 0004: pagina 108
|
||||||
|
|
||||||
@@ -422,21 +254,15 @@ class DianXMLExtensionSoftwareProvider(FachoXMLExtension):
|
|||||||
self.id_software = id_software
|
self.id_software = id_software
|
||||||
|
|
||||||
def build(self, fexml):
|
def build(self, fexml):
|
||||||
software_provider = fexml.fragment(
|
software_provider = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider')
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
|
||||||
':DianExtensions/sts:SoftwareProvider')
|
|
||||||
provider_id_attrs = SCHEME_AGENCY_ATTRS.copy()
|
provider_id_attrs = SCHEME_AGENCY_ATTRS.copy()
|
||||||
provider_id_attrs.update({'schemeID': self.dv})
|
provider_id_attrs.update({'schemeID': self.dv})
|
||||||
# DIAN 1.7.-2020: FAB23
|
#DIAN 1.7.-2020: FAB23
|
||||||
provider_id_attrs.update({'schemeName': '31'})
|
provider_id_attrs.update({'schemeName': '31'})
|
||||||
software_provider.set_element(
|
software_provider.set_element('/sts:SoftwareProvider/sts:ProviderID', self.nit,
|
||||||
'/sts:SoftwareProvider/sts:ProviderID',
|
**provider_id_attrs)
|
||||||
self.nit,
|
software_provider.set_element('/sts:SoftwareProvider/sts:SoftwareID', self.id_software,
|
||||||
**provider_id_attrs)
|
**SCHEME_AGENCY_ATTRS)
|
||||||
software_provider.set_element(
|
|
||||||
'/sts:SoftwareProvider/sts:SoftwareID',
|
|
||||||
self.id_software,
|
|
||||||
**SCHEME_AGENCY_ATTRS)
|
|
||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionSoftwareSecurityCode(FachoXMLExtension):
|
class DianXMLExtensionSoftwareSecurityCode(FachoXMLExtension):
|
||||||
@@ -448,10 +274,7 @@ class DianXMLExtensionSoftwareSecurityCode(FachoXMLExtension):
|
|||||||
self.invoice_ident = invoice_ident
|
self.invoice_ident = invoice_ident
|
||||||
|
|
||||||
def build(self, fexml):
|
def build(self, fexml):
|
||||||
dian_path = (
|
dian_path = './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareSecurityCode'
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
|
||||||
':DianExtensions/sts:SoftwareSecurityCode'
|
|
||||||
)
|
|
||||||
code = str(self.id_software) + str(self.pin) + str(self.invoice_ident)
|
code = str(self.id_software) + str(self.pin) + str(self.invoice_ident)
|
||||||
m = hashlib.sha384()
|
m = hashlib.sha384()
|
||||||
m.update(code.encode('utf-8'))
|
m.update(code.encode('utf-8'))
|
||||||
@@ -461,6 +284,7 @@ class DianXMLExtensionSoftwareSecurityCode(FachoXMLExtension):
|
|||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionSigner:
|
class DianXMLExtensionSigner:
|
||||||
|
|
||||||
def __init__(self, pkcs12_path, passphrase=None, localpolicy=True):
|
def __init__(self, pkcs12_path, passphrase=None, localpolicy=True):
|
||||||
self._pkcs12_data = open(pkcs12_path, 'rb').read()
|
self._pkcs12_data = open(pkcs12_path, 'rb').read()
|
||||||
self._passphrase = None
|
self._passphrase = None
|
||||||
@@ -471,25 +295,24 @@ class DianXMLExtensionSigner:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_bytes(cls, data, passphrase=None, localpolicy=True):
|
def from_bytes(cls, data, passphrase=None, localpolicy=True):
|
||||||
self = cls.__new__(cls)
|
self = cls.__new__(cls)
|
||||||
|
|
||||||
self._pkcs12_data = data
|
self._pkcs12_data = data
|
||||||
self._passphrase = None
|
self._passphrase = None
|
||||||
self._localpolicy = localpolicy
|
self._localpolicy = localpolicy
|
||||||
if passphrase:
|
if passphrase:
|
||||||
self._passphrase = passphrase.encode('utf-8')
|
self._passphrase = passphrase.encode('utf-8')
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _element_extension_content(self, fachoxml):
|
def _element_extension_content(self, fachoxml):
|
||||||
return fachoxml.builder.xpath(
|
return fachoxml.builder.xpath(fachoxml.root, './ext:UBLExtensions/ext:UBLExtension[2]/ext:ExtensionContent')
|
||||||
fachoxml.root,
|
|
||||||
'./ext:UBLExtensions/ext:UBLExtension[2]/ext:ExtensionContent')
|
|
||||||
|
|
||||||
def sign_xml_string(self, document):
|
def sign_xml_string(self, document):
|
||||||
xml = LXMLBuilder.from_string(document)
|
xml = LXMLBuilder.from_string(document)
|
||||||
signature = self.sign_xml_element(xml)
|
signature = self.sign_xml_element(xml)
|
||||||
|
|
||||||
fachoxml = FachoXML(xml, nsmap=NAMESPACES)
|
fachoxml = FachoXML(xml,nsmap=NAMESPACES)
|
||||||
# DIAN 1.7.-2020: FAB01
|
#DIAN 1.7.-2020: FAB01
|
||||||
extcontent = self._element_extension_content(fachoxml)
|
extcontent = self._element_extension_content(fachoxml)
|
||||||
fachoxml.append_element(extcontent, signature)
|
fachoxml.append_element(extcontent, signature)
|
||||||
|
|
||||||
@@ -504,38 +327,33 @@ class DianXMLExtensionSigner:
|
|||||||
)
|
)
|
||||||
xml.append(signature)
|
xml.append(signature)
|
||||||
|
|
||||||
|
|
||||||
ref = xmlsig.template.add_reference(
|
ref = xmlsig.template.add_reference(
|
||||||
signature,
|
signature, xmlsig.constants.TransformSha256, uri="", name="xmldsig-%s-ref0" % (id_uuid)
|
||||||
xmlsig.constants.TransformSha256,
|
)
|
||||||
uri="",
|
|
||||||
name="xmldsig-%s-ref0" %
|
|
||||||
(id_uuid))
|
|
||||||
xmlsig.template.add_transform(ref, xmlsig.constants.TransformEnveloped)
|
xmlsig.template.add_transform(ref, xmlsig.constants.TransformEnveloped)
|
||||||
|
|
||||||
id_keyinfo = "xmldsig-%s-KeyInfo" % (id_uuid)
|
id_keyinfo = "xmldsig-%s-KeyInfo" % (id_uuid)
|
||||||
xmlsig.template.add_reference(
|
xmlsig.template.add_reference(
|
||||||
signature, xmlsig.constants.TransformSha256, uri="#%s" % (
|
signature, xmlsig.constants.TransformSha256, uri="#%s" % (id_keyinfo), name="xmldsig-%s-ref1" % (id_uuid),
|
||||||
id_keyinfo), name="xmldsig-%s-ref1" % (id_uuid),
|
|
||||||
)
|
)
|
||||||
ki = xmlsig.template.ensure_key_info(signature, name=id_keyinfo)
|
ki = xmlsig.template.ensure_key_info(signature, name=id_keyinfo)
|
||||||
data = xmlsig.template.add_x509_data(ki)
|
data = xmlsig.template.add_x509_data(ki)
|
||||||
xmlsig.template.x509_data_add_certificate(data)
|
xmlsig.template.x509_data_add_certificate(data)
|
||||||
xmlsig.template.add_key_value(ki)
|
xmlsig.template.add_key_value(ki)
|
||||||
|
|
||||||
qualifying = xades.template.create_qualifying_properties(
|
qualifying = xades.template.create_qualifying_properties(signature, 'XadesObjects', 'xades')
|
||||||
signature, 'XadesObjects', 'xades')
|
|
||||||
xades.utils.ensure_id(qualifying)
|
xades.utils.ensure_id(qualifying)
|
||||||
|
|
||||||
id_props = "xmldsig-%s-signedprops" % (id_uuid)
|
id_props = "xmldsig-%s-signedprops" % (id_uuid)
|
||||||
props_ref = xmlsig.template.add_reference(
|
props_ref = xmlsig.template.add_reference(
|
||||||
signature, xmlsig.constants.TransformSha256, uri="#%s" %
|
signature, xmlsig.constants.TransformSha256, uri="#%s" % (id_props),
|
||||||
(id_props), uri_type="http://uri.etsi.org/01903#SignedProperties")
|
uri_type="http://uri.etsi.org/01903#SignedProperties"
|
||||||
xmlsig.template.add_transform(
|
)
|
||||||
props_ref, xmlsig.constants.TransformInclC14N)
|
xmlsig.template.add_transform(props_ref, xmlsig.constants.TransformInclC14N)
|
||||||
|
|
||||||
# TODO assert with http://www.sic.gov.co/hora-legal-colombiana
|
# TODO assert with http://www.sic.gov.co/hora-legal-colombiana
|
||||||
props = xades.template.create_signed_properties(
|
props = xades.template.create_signed_properties(qualifying, name=id_props, datetime=datetime.now())
|
||||||
qualifying, name=id_props, datetime=datetime.now(tz=Bogota))
|
|
||||||
xades.template.add_claimed_role(props, "supplier")
|
xades.template.add_claimed_role(props, "supplier")
|
||||||
|
|
||||||
policy = xades.policy.GenericPolicyId(
|
policy = xades.policy.GenericPolicyId(
|
||||||
@@ -543,9 +361,8 @@ class DianXMLExtensionSigner:
|
|||||||
POLICY_NAME,
|
POLICY_NAME,
|
||||||
xmlsig.constants.TransformSha256)
|
xmlsig.constants.TransformSha256)
|
||||||
ctx = xades.XAdESContext(policy)
|
ctx = xades.XAdESContext(policy)
|
||||||
ctx.load_pkcs12(pkcs12.load_key_and_certificates(
|
ctx.load_pkcs12(OpenSSL.crypto.load_pkcs12(self._pkcs12_data,
|
||||||
self._pkcs12_data,
|
self._passphrase))
|
||||||
self._passphrase))
|
|
||||||
|
|
||||||
if self._localpolicy:
|
if self._localpolicy:
|
||||||
with mock_xades_policy():
|
with mock_xades_policy():
|
||||||
@@ -554,7 +371,7 @@ class DianXMLExtensionSigner:
|
|||||||
else:
|
else:
|
||||||
ctx.sign(signature)
|
ctx.sign(signature)
|
||||||
ctx.verify(signature)
|
ctx.verify(signature)
|
||||||
# xmlsig take parent root
|
#xmlsig take parent root
|
||||||
xml.remove(signature)
|
xml.remove(signature)
|
||||||
return signature
|
return signature
|
||||||
|
|
||||||
@@ -563,35 +380,29 @@ class DianXMLExtensionSigner:
|
|||||||
extcontent = self._element_extension_content(fachoxml)
|
extcontent = self._element_extension_content(fachoxml)
|
||||||
fachoxml.append_element(extcontent, signature)
|
fachoxml.append_element(extcontent, signature)
|
||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionAuthorizationProvider(FachoXMLExtension):
|
class DianXMLExtensionAuthorizationProvider(FachoXMLExtension):
|
||||||
# RESOLUCION 0004: pagina 176
|
# RESOLUCION 0004: pagina 176
|
||||||
|
|
||||||
def build(self, fexml):
|
def build(self, fexml):
|
||||||
attrs = {'schemeID': '4', 'schemeName': '31'}
|
attrs = {'schemeID': '4', 'schemeName': '31'}
|
||||||
attrs.update(SCHEME_AGENCY_ATTRS)
|
attrs.update(SCHEME_AGENCY_ATTRS)
|
||||||
authorization_provider = fexml.fragment(
|
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
authorization_provider = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider')
|
||||||
':DianExtensions/sts:AuthorizationProvider')
|
|
||||||
authorization_provider.set_element('./sts:AuthorizationProviderID',
|
authorization_provider.set_element('./sts:AuthorizationProviderID',
|
||||||
'800197268',
|
'800197268',
|
||||||
**attrs)
|
**attrs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionInvoiceSource(FachoXMLExtension):
|
class DianXMLExtensionInvoiceSource(FachoXMLExtension):
|
||||||
# CAB13
|
# CAB13
|
||||||
def build(self, fexml):
|
def build(self, fexml):
|
||||||
dian_path = (
|
dian_path = '/fe:CreditNote/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode'
|
||||||
'/fe:CreditNote/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionCo'
|
fexml.set_element(dian_path, 'CO',
|
||||||
'ntent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode'
|
listAgencyID="6",
|
||||||
)
|
listAgencyName="United Nations Economic Commission for Europe",
|
||||||
fexml.set_element(
|
listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1")
|
||||||
dian_path, 'CO',
|
|
||||||
listAgencyID="6",
|
|
||||||
listAgencyName="United Nations Economic Commission for Europe",
|
|
||||||
listSchemeURI=(
|
|
||||||
"urn:oasis:names:specification:ubl:codelist:gc:"
|
|
||||||
"CountryIdentificationCode-2.1"))
|
|
||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension):
|
class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension):
|
||||||
@@ -608,38 +419,29 @@ class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension):
|
|||||||
self.to = to
|
self.to = to
|
||||||
|
|
||||||
def build(self, fexml):
|
def build(self, fexml):
|
||||||
invoice_control = fexml.fragment(
|
invoice_control = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceControl')
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
invoice_control.set_element('/sts:InvoiceControl/sts:InvoiceAuthorization', self.authorization)
|
||||||
':DianExtensions/sts:InvoiceControl')
|
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizationPeriod/cbc:StartDate',
|
||||||
invoice_control.set_element(
|
self.period_startdate.strftime('%Y-%m-%d'))
|
||||||
'/sts:InvoiceControl/sts:InvoiceAuthorization',
|
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizationPeriod/cbc:EndDate',
|
||||||
self.authorization)
|
self.period_enddate.strftime('%Y-%m-%d'))
|
||||||
invoice_control.set_element(
|
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:Prefix',
|
||||||
'/sts:InvoiceControl/sts:AuthorizationPeriod/cbc:StartDate',
|
self.prefix)
|
||||||
self.period_startdate.strftime('%Y-%m-%d'))
|
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:From',
|
||||||
invoice_control.set_element(
|
self.from_)
|
||||||
'/sts:InvoiceControl/sts:AuthorizationPeriod/cbc:EndDate',
|
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:To',
|
||||||
self.period_enddate.strftime('%Y-%m-%d'))
|
self.to)
|
||||||
invoice_control.set_element(
|
|
||||||
'/sts:InvoiceControl/sts:AuthorizedInvoices/sts:Prefix',
|
fexml.set_element('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode',
|
||||||
self.prefix)
|
'CO',
|
||||||
invoice_control.set_element(
|
#DIAN 1.7.-2020: FAB15
|
||||||
'/sts:InvoiceControl/sts:AuthorizedInvoices/sts:From', self.from_)
|
listAgencyID="6",
|
||||||
invoice_control.set_element(
|
#DIAN 1.7.-2020: FAB16
|
||||||
'/sts:InvoiceControl/sts:AuthorizedInvoices/sts:To', self.to)
|
listAgencyName="United Nations Economic Commission for Europe",
|
||||||
|
#DIAN 1.7.-2020: FAB17
|
||||||
|
listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1"
|
||||||
|
)
|
||||||
|
|
||||||
fexml.set_element(
|
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
|
||||||
':DianExtensions/sts:InvoiceSource/cbc:IdentificationCode',
|
|
||||||
'CO',
|
|
||||||
# DIAN 1.7.-2020: FAB15
|
|
||||||
listAgencyID="6",
|
|
||||||
# DIAN 1.7.-2020: FAB16
|
|
||||||
listAgencyName="United Nations Economic Commission for Europe",
|
|
||||||
# DIAN 1.7.-2020: FAB17
|
|
||||||
listSchemeURI=(
|
|
||||||
"urn:oasis:names:specification:ubl:codelist:gc:"
|
|
||||||
"CountryIdentificationCode-2.1"))
|
|
||||||
|
|
||||||
|
|
||||||
class DianZIP:
|
class DianZIP:
|
||||||
@@ -648,8 +450,7 @@ class DianZIP:
|
|||||||
MAX_FILES = 50
|
MAX_FILES = 50
|
||||||
|
|
||||||
def __init__(self, file_like):
|
def __init__(self, file_like):
|
||||||
self.zipfile = zipfile.ZipFile(
|
self.zipfile = zipfile.ZipFile(file_like, mode='w', compression=zipfile.ZIP_DEFLATED)
|
||||||
file_like, mode='w', compression=zipfile.ZIP_DEFLATED)
|
|
||||||
self.num_files = 0
|
self.num_files = 0
|
||||||
|
|
||||||
def add_xml(self, name, xml_data):
|
def add_xml(self, name, xml_data):
|
||||||
@@ -670,6 +471,7 @@ class DianZIP:
|
|||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
"""
|
"""
|
||||||
Facilita el uso de esta manera:
|
Facilita el uso de esta manera:
|
||||||
|
|
||||||
f = open('xxx', 'rb')
|
f = open('xxx', 'rb')
|
||||||
with DianZIP(f) as zip:
|
with DianZIP(f) as zip:
|
||||||
zip.add_invoice_xml('name', 'data xml')
|
zip.add_invoice_xml('name', 'data xml')
|
||||||
@@ -682,11 +484,7 @@ class DianZIP:
|
|||||||
|
|
||||||
class DianXMLExtensionSignerVerifier:
|
class DianXMLExtensionSignerVerifier:
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, pkcs12_path_or_bytes, passphrase=None, localpolicy=True):
|
||||||
self,
|
|
||||||
pkcs12_path_or_bytes,
|
|
||||||
passphrase=None,
|
|
||||||
localpolicy=True):
|
|
||||||
self._pkcs12_path_or_bytes = pkcs12_path_or_bytes
|
self._pkcs12_path_or_bytes = pkcs12_path_or_bytes
|
||||||
self._passphrase = None
|
self._passphrase = None
|
||||||
self._localpolicy = localpolicy
|
self._localpolicy = localpolicy
|
||||||
@@ -696,7 +494,7 @@ class DianXMLExtensionSignerVerifier:
|
|||||||
def verify_string(self, document):
|
def verify_string(self, document):
|
||||||
# Obtener FachoXML
|
# Obtener FachoXML
|
||||||
xml = LXMLBuilder.from_string(document)
|
xml = LXMLBuilder.from_string(document)
|
||||||
fachoxml = FachoXML(xml, nsmap=NAMESPACES)
|
fachoxml = FachoXML(xml,nsmap=NAMESPACES)
|
||||||
|
|
||||||
# Obtener Signature
|
# Obtener Signature
|
||||||
signature = fachoxml.builder.xpath(fachoxml.root, '//ds:Signature')
|
signature = fachoxml.builder.xpath(fachoxml.root, '//ds:Signature')
|
||||||
@@ -711,8 +509,8 @@ class DianXMLExtensionSignerVerifier:
|
|||||||
if isinstance(self._pkcs12_path_or_bytes, str):
|
if isinstance(self._pkcs12_path_or_bytes, str):
|
||||||
pkcs12_data = open(self._pkcs12_path_or_bytes, 'rb').read()
|
pkcs12_data = open(self._pkcs12_path_or_bytes, 'rb').read()
|
||||||
ctx = xades.XAdESContext()
|
ctx = xades.XAdESContext()
|
||||||
ctx.load_pkcs12(pkcs12.load_key_and_certificates(
|
ctx.load_pkcs12(OpenSSL.crypto.load_pkcs12(pkcs12_data,
|
||||||
pkcs12_data, self._passphrase))
|
self._passphrase))
|
||||||
try:
|
try:
|
||||||
if self._localpolicy:
|
if self._localpolicy:
|
||||||
with mock_xades_policy():
|
with mock_xades_policy():
|
||||||
@@ -720,5 +518,5 @@ class DianXMLExtensionSignerVerifier:
|
|||||||
else:
|
else:
|
||||||
ctx.verify(signature)
|
ctx.verify(signature)
|
||||||
return True
|
return True
|
||||||
except BaseException:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -1,27 +1,24 @@
|
|||||||
# This file is part of facho. The COPYRIGHT file at the top level of
|
# This file is part of facho. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
# import hashlib
|
import hashlib
|
||||||
# from functools import reduce
|
from functools import reduce
|
||||||
# import copy
|
import copy
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime, date
|
||||||
# from collections import defaultdict
|
from collections import defaultdict
|
||||||
import decimal
|
import decimal
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
import typing
|
||||||
|
|
||||||
from ..data.dian import codelist
|
from ..data.dian import codelist
|
||||||
|
|
||||||
DECIMAL_PRECISION = 6
|
DECIMAL_PRECISION = 6
|
||||||
|
|
||||||
|
|
||||||
class AmountCurrencyError(TypeError):
|
class AmountCurrencyError(TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Currency:
|
class Currency:
|
||||||
code: str
|
code: str
|
||||||
@@ -32,7 +29,6 @@ class Currency:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.code
|
return self.code
|
||||||
|
|
||||||
|
|
||||||
class Collection:
|
class Collection:
|
||||||
|
|
||||||
def __init__(self, array):
|
def __init__(self, array):
|
||||||
@@ -49,7 +45,6 @@ class Collection:
|
|||||||
def sum(self):
|
def sum(self):
|
||||||
return sum(self.array)
|
return sum(self.array)
|
||||||
|
|
||||||
|
|
||||||
class AmountCollection(Collection):
|
class AmountCollection(Collection):
|
||||||
|
|
||||||
def sum(self):
|
def sum(self):
|
||||||
@@ -58,13 +53,10 @@ class AmountCollection(Collection):
|
|||||||
total += v
|
total += v
|
||||||
return total
|
return total
|
||||||
|
|
||||||
|
|
||||||
class Amount:
|
class Amount:
|
||||||
def __init__(
|
def __init__(self, amount: int or float or str or Amount, currency: Currency = Currency('COP')):
|
||||||
self, amount: int | float | str | "Amount",
|
|
||||||
currency: Currency = Currency('COP')):
|
|
||||||
|
|
||||||
# DIAN 1.7.-2020: 1.2.3.1
|
#DIAN 1.7.-2020: 1.2.3.1
|
||||||
if isinstance(amount, Amount):
|
if isinstance(amount, Amount):
|
||||||
if amount < Amount(0.0):
|
if amount < Amount(0.0):
|
||||||
raise ValueError('amount must be positive >= 0')
|
raise ValueError('amount must be positive >= 0')
|
||||||
@@ -75,16 +67,14 @@ class Amount:
|
|||||||
if float(amount) < 0:
|
if float(amount) < 0:
|
||||||
raise ValueError('amount must be positive >= 0')
|
raise ValueError('amount must be positive >= 0')
|
||||||
|
|
||||||
self.amount = Decimal(
|
self.amount = Decimal(amount, decimal.Context(prec=DECIMAL_PRECISION,
|
||||||
amount, decimal.Context(
|
#DIAN 1.7.-2020: 1.2.1.1
|
||||||
prec=DECIMAL_PRECISION,
|
rounding=decimal.ROUND_HALF_EVEN ))
|
||||||
# DIAN 1.7.-2020: 1.2.1.1
|
|
||||||
rounding=decimal.ROUND_HALF_EVEN))
|
|
||||||
self.currency = currency
|
self.currency = currency
|
||||||
|
|
||||||
def fromNumber(self, val):
|
def fromNumber(self, val):
|
||||||
return Amount(val, currency=self.currency)
|
return Amount(val, currency=self.currency)
|
||||||
|
|
||||||
def round(self, prec):
|
def round(self, prec):
|
||||||
return Amount(round(self.amount, prec), currency=self.currency)
|
return Amount(round(self.amount, prec), currency=self.currency)
|
||||||
|
|
||||||
@@ -102,8 +92,7 @@ class Amount:
|
|||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if not self.is_same_currency(other):
|
if not self.is_same_currency(other):
|
||||||
raise AmountCurrencyError()
|
raise AmountCurrencyError()
|
||||||
return round(self.amount, DECIMAL_PRECISION) == round(
|
return round(self.amount, DECIMAL_PRECISION) == round(other.amount, DECIMAL_PRECISION)
|
||||||
other.amount, DECIMAL_PRECISION)
|
|
||||||
|
|
||||||
def _cast(self, val):
|
def _cast(self, val):
|
||||||
if type(val) in [int, float]:
|
if type(val) in [int, float]:
|
||||||
@@ -111,7 +100,7 @@ class Amount:
|
|||||||
if isinstance(val, Amount):
|
if isinstance(val, Amount):
|
||||||
return val
|
return val
|
||||||
raise TypeError("cant cast to amount")
|
raise TypeError("cant cast to amount")
|
||||||
|
|
||||||
def __add__(self, rother):
|
def __add__(self, rother):
|
||||||
other = self._cast(rother)
|
other = self._cast(rother)
|
||||||
if not self.is_same_currency(other):
|
if not self.is_same_currency(other):
|
||||||
@@ -135,14 +124,14 @@ class Amount:
|
|||||||
|
|
||||||
def truncate_as_string(self, prec):
|
def truncate_as_string(self, prec):
|
||||||
parts = str(self.float()).split('.', 1)
|
parts = str(self.float()).split('.', 1)
|
||||||
return '%s.%s' % (parts[0], parts[1][0:prec].ljust(prec, '0'))
|
return '%s.%s' % (parts[0], parts[1][0:prec].ljust(prec,'0'))
|
||||||
|
|
||||||
def float(self):
|
def float(self):
|
||||||
return float(round(self.amount, DECIMAL_PRECISION))
|
return float(round(self.amount, DECIMAL_PRECISION))
|
||||||
|
|
||||||
|
|
||||||
class Quantity:
|
class Quantity:
|
||||||
|
|
||||||
def __init__(self, val, code):
|
def __init__(self, val, code):
|
||||||
if type(val) not in [float, int]:
|
if type(val) not in [float, int]:
|
||||||
raise ValueError('val expected int or float')
|
raise ValueError('val expected int or float')
|
||||||
@@ -164,7 +153,6 @@ class Quantity:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Item:
|
class Item:
|
||||||
scheme_name: str
|
scheme_name: str
|
||||||
@@ -175,10 +163,10 @@ class Item:
|
|||||||
|
|
||||||
|
|
||||||
class StandardItem(Item):
|
class StandardItem(Item):
|
||||||
def __init__(self, id_: str, description: str = '', name: str = ''):
|
def __init__(self, id_: str, description: str = ''):
|
||||||
super().__init__(id=id_,
|
super().__init__(id=id_,
|
||||||
description=description,
|
description=description,
|
||||||
scheme_name=name,
|
scheme_name='',
|
||||||
scheme_id='999',
|
scheme_id='999',
|
||||||
scheme_agency_id='')
|
scheme_agency_id='')
|
||||||
|
|
||||||
@@ -189,9 +177,9 @@ class UNSPSCItem(Item):
|
|||||||
description=description,
|
description=description,
|
||||||
scheme_name='UNSPSC',
|
scheme_name='UNSPSC',
|
||||||
scheme_id='001',
|
scheme_id='001',
|
||||||
scheme_agency_id='10')
|
scheme_agency_id='10')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Country:
|
class Country:
|
||||||
code: str
|
code: str
|
||||||
@@ -202,7 +190,6 @@ class Country:
|
|||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.Paises[self.code]['name']
|
self.name = codelist.Paises[self.code]['name']
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CountrySubentity:
|
class CountrySubentity:
|
||||||
code: str
|
code: str
|
||||||
@@ -213,7 +200,6 @@ class CountrySubentity:
|
|||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.Departamento[self.code]['name']
|
self.name = codelist.Departamento[self.code]['name']
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class City:
|
class City:
|
||||||
code: str
|
code: str
|
||||||
@@ -224,22 +210,13 @@ class City:
|
|||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.Municipio[self.code]['name']
|
self.name = codelist.Municipio[self.code]['name']
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PostalZone:
|
|
||||||
code: str = ''
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Address:
|
class Address:
|
||||||
name: str
|
name: str
|
||||||
street: str = ''
|
street: str = ''
|
||||||
city: City = field(default_factory=lambda: City('05001'))
|
city: City = City('05001')
|
||||||
country: Country = field(default_factory=lambda: Country('CO'))
|
country: Country = Country('CO')
|
||||||
countrysubentity: CountrySubentity = field(
|
countrysubentity: CountrySubentity = CountrySubentity('05')
|
||||||
default_factory=lambda: CountrySubentity('05'))
|
|
||||||
postalzone: PostalZone = field(default_factory=lambda: PostalZone(''))
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PartyIdentification:
|
class PartyIdentification:
|
||||||
@@ -260,7 +237,6 @@ class PartyIdentification:
|
|||||||
if self.type_fiscal not in codelist.TipoIdFiscal:
|
if self.type_fiscal not in codelist.TipoIdFiscal:
|
||||||
raise ValueError("type_fiscal [%s] not found" % (self.type_fiscal))
|
raise ValueError("type_fiscal [%s] not found" % (self.type_fiscal))
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Responsability:
|
class Responsability:
|
||||||
codes: list
|
codes: list
|
||||||
@@ -280,17 +256,28 @@ class Responsability:
|
|||||||
raise ValueError("code %s not found" % (code))
|
raise ValueError("code %s not found" % (code))
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TaxScheme:
|
||||||
|
code: str
|
||||||
|
name: str = ''
|
||||||
|
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if self.code not in codelist.TipoImpuesto:
|
||||||
|
raise ValueError("code not found")
|
||||||
|
self.name = codelist.TipoImpuesto[self.code]['name']
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Party:
|
class Party:
|
||||||
name: str
|
name: str
|
||||||
ident: str
|
ident: str
|
||||||
responsability_code: list[Responsability]
|
responsability_code: typing.List[Responsability]
|
||||||
responsability_regime_code: str
|
responsability_regime_code: str
|
||||||
organization_code: str
|
organization_code: str
|
||||||
tax_scheme: TaxScheme = field(default_factory=lambda: TaxScheme('01'))
|
tax_scheme: TaxScheme = TaxScheme('01')
|
||||||
|
|
||||||
phone: str = ''
|
phone: str = ''
|
||||||
address: Address = field(default_factory=lambda: Address(''))
|
address: Address = Address('')
|
||||||
email: str = ''
|
email: str = ''
|
||||||
legal_name: str = ''
|
legal_name: str = ''
|
||||||
legal_company_ident: str = ''
|
legal_company_ident: str = ''
|
||||||
@@ -317,8 +304,8 @@ class TaxScheme:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class TaxSubTotal:
|
class TaxSubTotal:
|
||||||
percent: float
|
percent: float
|
||||||
scheme: TaxScheme | None = None
|
scheme: typing.Optional[TaxScheme] = None
|
||||||
tax_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
tax_amount: Amount = Amount(0.0)
|
||||||
|
|
||||||
def calculate(self, invline):
|
def calculate(self, invline):
|
||||||
if self.percent is not None:
|
if self.percent is not None:
|
||||||
@@ -328,11 +315,12 @@ class TaxSubTotal:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class TaxTotal:
|
class TaxTotal:
|
||||||
subtotals: list
|
subtotals: list
|
||||||
tax_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
tax_amount: Amount = Amount(0.0)
|
||||||
taxable_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
taxable_amount: Amount = Amount(0.0)
|
||||||
|
|
||||||
def calculate(self, invline):
|
def calculate(self, invline):
|
||||||
self.taxable_amount = invline.total_amount
|
self.taxable_amount = invline.total_amount
|
||||||
|
|
||||||
for subtax in self.subtotals:
|
for subtax in self.subtotals:
|
||||||
subtax.calculate(invline)
|
subtax.calculate(invline)
|
||||||
self.tax_amount += subtax.tax_amount
|
self.tax_amount += subtax.tax_amount
|
||||||
@@ -345,40 +333,6 @@ class TaxTotalOmit(TaxTotal):
|
|||||||
def calculate(self, invline):
|
def calculate(self, invline):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class WithholdingTaxSubTotal:
|
|
||||||
percent: float
|
|
||||||
scheme: TaxScheme | None = None
|
|
||||||
tax_amount: Amount = field(default_factory=lambda: 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 = field(default_factory=lambda: Amount(0.0))
|
|
||||||
taxable_amount: Amount = field(default_factory=lambda: 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
|
@dataclass
|
||||||
class Price:
|
class Price:
|
||||||
amount: Amount
|
amount: Amount
|
||||||
@@ -394,7 +348,6 @@ class Price:
|
|||||||
|
|
||||||
self.amount *= self.quantity
|
self.amount *= self.quantity
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PaymentMean:
|
class PaymentMean:
|
||||||
DEBIT = '01'
|
DEBIT = '01'
|
||||||
@@ -412,24 +365,8 @@ class PaymentMean:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PrePaidPayment:
|
class PrePaidPayment:
|
||||||
# DIAN 1.7.-2020: FBD03
|
#DIAN 1.7.-2020: FBD03
|
||||||
paid_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
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
|
@dataclass
|
||||||
@@ -438,7 +375,6 @@ class BillingReference:
|
|||||||
uuid: str
|
uuid: str
|
||||||
date: date
|
date: date
|
||||||
|
|
||||||
|
|
||||||
class CreditNoteDocumentReference(BillingReference):
|
class CreditNoteDocumentReference(BillingReference):
|
||||||
"""
|
"""
|
||||||
ident: Prefijo + Numero de la factura relacionada
|
ident: Prefijo + Numero de la factura relacionada
|
||||||
@@ -454,7 +390,6 @@ class DebitNoteDocumentReference(BillingReference):
|
|||||||
date: fecha de emision de la factura relacionada
|
date: fecha de emision de la factura relacionada
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class InvoiceDocumentReference(BillingReference):
|
class InvoiceDocumentReference(BillingReference):
|
||||||
"""
|
"""
|
||||||
ident: Prefijo + Numero de la nota credito relacionada
|
ident: Prefijo + Numero de la nota credito relacionada
|
||||||
@@ -462,7 +397,6 @@ class InvoiceDocumentReference(BillingReference):
|
|||||||
date: fecha de emision de la nota credito relacionada
|
date: fecha de emision de la nota credito relacionada
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AllowanceChargeReason:
|
class AllowanceChargeReason:
|
||||||
code: str
|
code: str
|
||||||
@@ -475,26 +409,22 @@ class AllowanceChargeReason:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AllowanceCharge:
|
class AllowanceCharge:
|
||||||
# DIAN 1.7.-2020: FAQ03
|
#DIAN 1.7.-2020: FAQ03
|
||||||
charge_indicator: bool = True
|
charge_indicator: bool = True
|
||||||
amount: Amount = field(default_factory=lambda: Amount(0.0))
|
amount: Amount = Amount(0.0)
|
||||||
reason: AllowanceChargeReason = None
|
reason: AllowanceChargeReason = None
|
||||||
|
|
||||||
# Valor Base para calcular el descuento o el cargo
|
#Valor Base para calcular el descuento o el cargo
|
||||||
base_amount: Amount | None = field(
|
base_amount: typing.Optional[Amount] = Amount(0.0)
|
||||||
default_factory=lambda: Amount(0.0))
|
|
||||||
|
|
||||||
# Porcentaje: Porcentaje que aplicar.
|
# Porcentaje: Porcentaje que aplicar.
|
||||||
multiplier_factor_numeric: Amount = field(
|
multiplier_factor_numeric: Amount = Amount(1.0)
|
||||||
default_factory=lambda: Amount(1.0))
|
|
||||||
|
|
||||||
def isCharge(self):
|
def isCharge(self):
|
||||||
charge_indicator = self.charge_indicator is True
|
return self.charge_indicator == True
|
||||||
return charge_indicator
|
|
||||||
|
|
||||||
def isDiscount(self):
|
def isDiscount(self):
|
||||||
charge_indicator = self.charge_indicator is False
|
return self.charge_indicator == False
|
||||||
return charge_indicator
|
|
||||||
|
|
||||||
def asCharge(self):
|
def asCharge(self):
|
||||||
self.charge_indicator = True
|
self.charge_indicator = True
|
||||||
@@ -508,13 +438,11 @@ class AllowanceCharge:
|
|||||||
def set_base_amount(self, amount):
|
def set_base_amount(self, amount):
|
||||||
self.base_amount = amount
|
self.base_amount = amount
|
||||||
|
|
||||||
|
|
||||||
class AllowanceChargeAsDiscount(AllowanceCharge):
|
class AllowanceChargeAsDiscount(AllowanceCharge):
|
||||||
def __init__(self, amount: Amount = Amount(0.0)):
|
def __init__(self, amount: Amount = Amount(0.0)):
|
||||||
self.charge_indicator = False
|
self.charge_indicator = False
|
||||||
self.amount = amount
|
self.amount = amount
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class InvoiceLine:
|
class InvoiceLine:
|
||||||
# RESOLUCION 0004: pagina 155
|
# RESOLUCION 0004: pagina 155
|
||||||
@@ -526,10 +454,9 @@ class InvoiceLine:
|
|||||||
# ya que al reportar los totales es sobre
|
# ya que al reportar los totales es sobre
|
||||||
# la factura y el percent es unico por type_code
|
# la factura y el percent es unico por type_code
|
||||||
# de subtotal
|
# de subtotal
|
||||||
tax: TaxTotal | None
|
tax: typing.Optional[TaxTotal]
|
||||||
withholding: WithholdingTaxTotal | None
|
|
||||||
allowance_charge: list[AllowanceCharge] = dataclasses.field(
|
allowance_charge: typing.List[AllowanceCharge] = dataclasses.field(default_factory=list)
|
||||||
default_factory=list)
|
|
||||||
|
|
||||||
def add_allowance_charge(self, charge):
|
def add_allowance_charge(self, charge):
|
||||||
if not isinstance(charge, AllowanceCharge):
|
if not isinstance(charge, AllowanceCharge):
|
||||||
@@ -540,7 +467,7 @@ class InvoiceLine:
|
|||||||
@property
|
@property
|
||||||
def total_amount_without_charge(self):
|
def total_amount_without_charge(self):
|
||||||
return (self.quantity * self.price.amount)
|
return (self.quantity * self.price.amount)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total_amount(self):
|
def total_amount(self):
|
||||||
charge = AmountCollection(self.allowance_charge)\
|
charge = AmountCollection(self.allowance_charge)\
|
||||||
@@ -572,17 +499,8 @@ class InvoiceLine:
|
|||||||
def taxable_amount(self):
|
def taxable_amount(self):
|
||||||
return self.tax.taxable_amount
|
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):
|
def calculate(self):
|
||||||
self.tax.calculate(self)
|
self.tax.calculate(self)
|
||||||
self.withholding.calculate(self)
|
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if not isinstance(self.quantity, Quantity):
|
if not isinstance(self.quantity, Quantity):
|
||||||
@@ -591,22 +509,18 @@ class InvoiceLine:
|
|||||||
if self.tax is None:
|
if self.tax is None:
|
||||||
self.tax = TaxTotalOmit()
|
self.tax = TaxTotalOmit()
|
||||||
|
|
||||||
if self.withholding is None:
|
|
||||||
self.withholding = WithholdingTaxTotalOmit()
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LegalMonetaryTotal:
|
class LegalMonetaryTotal:
|
||||||
line_extension_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
line_extension_amount: Amount = Amount(0.0)
|
||||||
tax_exclusive_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
tax_exclusive_amount: Amount = Amount(0.0)
|
||||||
tax_inclusive_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
tax_inclusive_amount: Amount = Amount(0.0)
|
||||||
charge_total_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
charge_total_amount: Amount = Amount(0.0)
|
||||||
allowance_total_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
allowance_total_amount: Amount = Amount(0.0)
|
||||||
payable_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
payable_amount: Amount = Amount(0.0)
|
||||||
prepaid_amount: Amount = field(default_factory=lambda: Amount(0.0))
|
prepaid_amount: Amount = Amount(0.0)
|
||||||
|
|
||||||
def calculate(self):
|
def calculate(self):
|
||||||
# DIAN 1.7.-2020: FAU14
|
#DIAN 1.7.-2020: FAU14
|
||||||
self.payable_amount = \
|
self.payable_amount = \
|
||||||
self.tax_inclusive_amount \
|
self.tax_inclusive_amount \
|
||||||
+ self.allowance_total_amount \
|
+ self.allowance_total_amount \
|
||||||
@@ -614,29 +528,22 @@ class LegalMonetaryTotal:
|
|||||||
- self.prepaid_amount
|
- self.prepaid_amount
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class NationalSalesInvoiceDocumentType(str):
|
class NationalSalesInvoiceDocumentType(str):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# 6.1.3
|
# 6.1.3
|
||||||
return '01'
|
return '01'
|
||||||
|
|
||||||
|
|
||||||
class CreditNoteDocumentType(str):
|
class CreditNoteDocumentType(str):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# 6.1.3
|
# 6.1.3
|
||||||
return '91'
|
return '91'
|
||||||
|
|
||||||
|
|
||||||
class DebitNoteDocumentType(str):
|
class DebitNoteDocumentType(str):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# 6.1.3
|
# 6.1.3
|
||||||
return '92'
|
return '92'
|
||||||
|
|
||||||
|
|
||||||
class CreditNoteSupportDocumentType(str):
|
|
||||||
def __str__(self):
|
|
||||||
return '95'
|
|
||||||
|
|
||||||
|
|
||||||
class Invoice:
|
class Invoice:
|
||||||
def __init__(self, type_code: str):
|
def __init__(self, type_code: str):
|
||||||
if str(type_code) not in codelist.TipoDocumento:
|
if str(type_code) not in codelist.TipoDocumento:
|
||||||
@@ -656,7 +563,6 @@ class Invoice:
|
|||||||
self.invoice_allowance_charge = []
|
self.invoice_allowance_charge = []
|
||||||
self.invoice_prepaid_payment = []
|
self.invoice_prepaid_payment = []
|
||||||
self.invoice_billing_reference = None
|
self.invoice_billing_reference = None
|
||||||
self.invoice_discrepancy_response = None
|
|
||||||
self.invoice_type_code = str(type_code)
|
self.invoice_type_code = str(type_code)
|
||||||
self.invoice_ident_prefix = None
|
self.invoice_ident_prefix = None
|
||||||
|
|
||||||
@@ -682,8 +588,7 @@ class Invoice:
|
|||||||
if len(prefix) <= 4:
|
if len(prefix) <= 4:
|
||||||
self.invoice_ident_prefix = prefix
|
self.invoice_ident_prefix = prefix
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError('ident prefix failed to get, expected 0 to 4 chars')
|
||||||
'ident prefix failed to get, expected 0 to 4 chars')
|
|
||||||
|
|
||||||
def set_ident(self, ident: str):
|
def set_ident(self, ident: str):
|
||||||
"""
|
"""
|
||||||
@@ -714,7 +619,7 @@ class Invoice:
|
|||||||
|
|
||||||
def _get_codelist_tipo_operacion(self):
|
def _get_codelist_tipo_operacion(self):
|
||||||
return codelist.TipoOperacionF
|
return codelist.TipoOperacionF
|
||||||
|
|
||||||
def set_operation_type(self, operation):
|
def set_operation_type(self, operation):
|
||||||
if operation not in self._get_codelist_tipo_operacion():
|
if operation not in self._get_codelist_tipo_operacion():
|
||||||
raise ValueError("operation not found")
|
raise ValueError("operation not found")
|
||||||
@@ -733,9 +638,6 @@ class Invoice:
|
|||||||
def set_billing_reference(self, billing_reference: BillingReference):
|
def set_billing_reference(self, billing_reference: BillingReference):
|
||||||
self.invoice_billing_reference = billing_reference
|
self.invoice_billing_reference = billing_reference
|
||||||
|
|
||||||
def set_discrepancy_response(self, billing_response: BillingResponse):
|
|
||||||
self.invoice_discrepancy_response = billing_response
|
|
||||||
|
|
||||||
def accept(self, visitor):
|
def accept(self, visitor):
|
||||||
visitor.visit_payment_mean(self.invoice_payment_mean)
|
visitor.visit_payment_mean(self.invoice_payment_mean)
|
||||||
visitor.visit_customer(self.invoice_customer)
|
visitor.visit_customer(self.invoice_customer)
|
||||||
@@ -747,34 +649,29 @@ class Invoice:
|
|||||||
|
|
||||||
def _calculate_legal_monetary_total(self):
|
def _calculate_legal_monetary_total(self):
|
||||||
for invline in self.invoice_lines:
|
for invline in self.invoice_lines:
|
||||||
self.invoice_legal_monetary_total.line_extension_amount +=\
|
self.invoice_legal_monetary_total.line_extension_amount += invline.total_amount
|
||||||
invline.total_amount
|
self.invoice_legal_monetary_total.tax_exclusive_amount += invline.total_tax_exclusive_amount
|
||||||
self.invoice_legal_monetary_total.tax_exclusive_amount +=\
|
#DIAN 1.7.-2020: FAU6
|
||||||
invline.total_tax_exclusive_amount
|
self.invoice_legal_monetary_total.tax_inclusive_amount += invline.total_tax_inclusive_amount
|
||||||
# DIAN 1.7.-2020: FAU6
|
|
||||||
self.invoice_legal_monetary_total.tax_inclusive_amount +=\
|
|
||||||
invline.total_tax_inclusive_amount
|
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAU08
|
#DIAN 1.7.-2020: FAU08
|
||||||
self.invoice_legal_monetary_total.allowance_total_amount =\
|
self.invoice_legal_monetary_total.allowance_total_amount = AmountCollection(self.invoice_allowance_charge)\
|
||||||
AmountCollection(self.invoice_allowance_charge)\
|
|
||||||
.filter(lambda charge: charge.isDiscount())\
|
.filter(lambda charge: charge.isDiscount())\
|
||||||
.map(lambda charge: charge.amount)\
|
.map(lambda charge: charge.amount)\
|
||||||
.sum()
|
.sum()
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAU10
|
#DIAN 1.7.-2020: FAU10
|
||||||
self.invoice_legal_monetary_total.charge_total_amount =\
|
self.invoice_legal_monetary_total.charge_total_amount = AmountCollection(self.invoice_allowance_charge)\
|
||||||
AmountCollection(self.invoice_allowance_charge)\
|
|
||||||
.filter(lambda charge: charge.isCharge())\
|
.filter(lambda charge: charge.isCharge())\
|
||||||
.map(lambda charge: charge.amount)\
|
.map(lambda charge: charge.amount)\
|
||||||
.sum()
|
.sum()
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAU12
|
#DIAN 1.7.-2020: FAU12
|
||||||
self.invoice_legal_monetary_total.prepaid_amount = AmountCollection(
|
self.invoice_legal_monetary_total.prepaid_amount = AmountCollection(self.invoice_prepaid_payment)\
|
||||||
self.invoice_prepaid_payment).map(
|
.map(lambda paid: paid.paid_amount)\
|
||||||
lambda paid: paid.paid_amount).sum()
|
.sum()
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAU14
|
#DIAN 1.7.-2020: FAU14
|
||||||
self.invoice_legal_monetary_total.calculate()
|
self.invoice_legal_monetary_total.calculate()
|
||||||
|
|
||||||
def _refresh_charges_base_amount(self):
|
def _refresh_charges_base_amount(self):
|
||||||
@@ -782,21 +679,18 @@ class Invoice:
|
|||||||
for invline in self.invoice_lines:
|
for invline in self.invoice_lines:
|
||||||
if invline.allowance_charge:
|
if invline.allowance_charge:
|
||||||
# TODO actualmente solo uno de los cargos es permitido
|
# TODO actualmente solo uno de los cargos es permitido
|
||||||
raise ValueError(
|
raise ValueError('allowance charge in invoice exclude invoice line')
|
||||||
'allowance charge in invoice exclude invoice line')
|
|
||||||
|
|
||||||
# cargos a nivel de factura
|
# cargos a nivel de factura
|
||||||
for charge in self.invoice_allowance_charge:
|
for charge in self.invoice_allowance_charge:
|
||||||
charge.set_base_amount(
|
charge.set_base_amount(self.invoice_legal_monetary_total.line_extension_amount)
|
||||||
self.invoice_legal_monetary_total.line_extension_amount)
|
|
||||||
|
|
||||||
def calculate(self):
|
def calculate(self):
|
||||||
for invline in self.invoice_lines:
|
for invline in self.invoice_lines:
|
||||||
invline.calculate()
|
invline.calculate()
|
||||||
self._calculate_legal_monetary_total()
|
self._calculate_legal_monetary_total()
|
||||||
self._refresh_charges_base_amount()
|
self._refresh_charges_base_amount()
|
||||||
|
|
||||||
|
|
||||||
class NationalSalesInvoice(Invoice):
|
class NationalSalesInvoice(Invoice):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(NationalSalesInvoiceDocumentType())
|
super().__init__(NationalSalesInvoiceDocumentType())
|
||||||
@@ -812,7 +706,7 @@ class CreditNote(Invoice):
|
|||||||
|
|
||||||
def _get_codelist_tipo_operacion(self):
|
def _get_codelist_tipo_operacion(self):
|
||||||
return codelist.TipoOperacionNC
|
return codelist.TipoOperacionNC
|
||||||
|
|
||||||
def _check_ident_prefix(self, prefix):
|
def _check_ident_prefix(self, prefix):
|
||||||
if len(prefix) != 6:
|
if len(prefix) != 6:
|
||||||
raise ValueError('prefix must be 6 length')
|
raise ValueError('prefix must be 6 length')
|
||||||
@@ -841,30 +735,3 @@ class DebitNote(Invoice):
|
|||||||
if not self.invoice_ident_prefix:
|
if not self.invoice_ident_prefix:
|
||||||
self.invoice_ident_prefix = self.invoice_ident[0:6]
|
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
|
|
||||||
|
|||||||
@@ -6,19 +6,16 @@ from .. import form
|
|||||||
from ..fe import fe_from_string
|
from ..fe import fe_from_string
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
def billing_reference(xmldocument: str, klass: form.BillingReference) -> form.BillingReference:
|
||||||
def billing_reference(
|
|
||||||
xmldocument: str,
|
|
||||||
klass: form.BillingReference) -> form.BillingReference:
|
|
||||||
"""
|
"""
|
||||||
construye BillingReference desde XMLDOCUMENT
|
construye BillingReference desde XMLDOCUMENT
|
||||||
usando KLASS como clase.
|
usando KLASS como clase.
|
||||||
"""
|
"""
|
||||||
if not issubclass(klass, form.BillingReference):
|
if not issubclass(klass, form.BillingReference):
|
||||||
raise TypeError('klass expected subclass of BillingReference')
|
raise TypeError('klass expected subclass of BillingReference')
|
||||||
|
|
||||||
fachoxml = fe_from_string(xmldocument)
|
fachoxml = fe_from_string(xmldocument)
|
||||||
|
|
||||||
uid = fachoxml.get_element_text('./cbc:ID')
|
uid = fachoxml.get_element_text('./cbc:ID')
|
||||||
uuid = fachoxml.get_element_text('./cbc:UUID')
|
uuid = fachoxml.get_element_text('./cbc:UUID')
|
||||||
issue_date = fachoxml.get_element_text('./cbc:IssueDate')
|
issue_date = fachoxml.get_element_text('./cbc:IssueDate')
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
from .invoice import DIANInvoiceXML
|
from .invoice import *
|
||||||
from .credit_note import DIANCreditNoteXML
|
from .credit_note import *
|
||||||
from .debit_note import DIANDebitNoteXML
|
from .debit_note import *
|
||||||
from .utils import DIANWrite, DIANWriteSigned
|
from .utils import *
|
||||||
from .attached_document import AttachedDocument
|
from .attached_document import *
|
||||||
from .support_document import DIANSupportDocumentXML
|
|
||||||
from .support_document_credit_note import DIANSupportDocumentCreditNoteXML
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'DIANInvoiceXML',
|
|
||||||
'DIANCreditNoteXML',
|
|
||||||
'DIANDebitNoteXML',
|
|
||||||
'DIANWrite',
|
|
||||||
'DIANWriteSigned',
|
|
||||||
'AttachedDocument',
|
|
||||||
'DIANSupportDocumentXML',
|
|
||||||
'DIANSupportDocumentCreditNoteXML',
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ from .. import fe
|
|||||||
|
|
||||||
__all__ = ['AttachedDocument']
|
__all__ = ['AttachedDocument']
|
||||||
|
|
||||||
|
|
||||||
class AttachedDocument():
|
class AttachedDocument():
|
||||||
|
|
||||||
def __init__(self, id):
|
def __init__(self, id):
|
||||||
schema =\
|
schema = 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2'
|
||||||
'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2'
|
|
||||||
self.fexml = fe.FeXML('AttachedDocument', schema)
|
self.fexml = fe.FeXML('AttachedDocument', schema)
|
||||||
self.fexml.set_element('./cbc:ID', id)
|
self.fexml.set_element('./cbc:ID', id)
|
||||||
|
|
||||||
def toFachoXML(self):
|
def toFachoXML(self):
|
||||||
return self.fexml
|
return self.fexml
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
# from .. import fe
|
from .. import fe
|
||||||
# from ..form import *
|
from ..form import *
|
||||||
from .invoice import DIANInvoiceXML
|
from .invoice import DIANInvoiceXML
|
||||||
|
|
||||||
__all__ = ['DIANCreditNoteXML']
|
__all__ = ['DIANCreditNoteXML']
|
||||||
|
|
||||||
|
|
||||||
class DIANCreditNoteXML(DIANInvoiceXML):
|
class DIANCreditNoteXML(DIANInvoiceXML):
|
||||||
"""
|
"""
|
||||||
DianInvoiceXML mapea objeto form.Invoice a XML segun
|
DianInvoiceXML mapea objeto form.Invoice a XML segun
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
# from .. import fe
|
from .. import fe
|
||||||
# from ..form import *
|
from ..form import *
|
||||||
from .invoice import DIANInvoiceXML
|
from .invoice import DIANInvoiceXML
|
||||||
|
|
||||||
__all__ = ['DIANDebitNoteXML']
|
__all__ = ['DIANDebitNoteXML']
|
||||||
|
|
||||||
|
|
||||||
class DIANDebitNoteXML(DIANInvoiceXML):
|
class DIANDebitNoteXML(DIANInvoiceXML):
|
||||||
"""
|
"""
|
||||||
DianInvoiceXML mapea objeto form.Invoice a XML segun
|
DianInvoiceXML mapea objeto form.Invoice a XML segun
|
||||||
@@ -20,24 +19,19 @@ class DIANDebitNoteXML(DIANInvoiceXML):
|
|||||||
def tag_document_concilied(fexml):
|
def tag_document_concilied(fexml):
|
||||||
return 'Debited'
|
return 'Debited'
|
||||||
|
|
||||||
# DIAN 1.7.-2020: DAU03
|
#DIAN 1.7.-2020: DAU03
|
||||||
def set_legal_monetary(fexml, invoice):
|
def set_legal_monetary(fexml, invoice):
|
||||||
fexml.set_element_amount(
|
fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:LineExtensionAmount',
|
||||||
'./cac:RequestedMonetaryTotal/cbc:LineExtensionAmount',
|
invoice.invoice_legal_monetary_total.line_extension_amount)
|
||||||
invoice.invoice_legal_monetary_total.line_extension_amount)
|
|
||||||
|
|
||||||
fexml.set_element_amount(
|
fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:TaxExclusiveAmount',
|
||||||
'./cac:RequestedMonetaryTotal/cbc:TaxExclusiveAmount',
|
invoice.invoice_legal_monetary_total.tax_exclusive_amount)
|
||||||
invoice.invoice_legal_monetary_total.tax_exclusive_amount)
|
|
||||||
|
|
||||||
fexml.set_element_amount(
|
fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:TaxInclusiveAmount',
|
||||||
'./cac:RequestedMonetaryTotal/cbc:TaxInclusiveAmount',
|
invoice.invoice_legal_monetary_total.tax_inclusive_amount)
|
||||||
invoice.invoice_legal_monetary_total.tax_inclusive_amount)
|
|
||||||
|
|
||||||
fexml.set_element_amount(
|
fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:ChargeTotalAmount',
|
||||||
'./cac:RequestedMonetaryTotal/cbc:ChargeTotalAmount',
|
invoice.invoice_legal_monetary_total.charge_total_amount)
|
||||||
invoice.invoice_legal_monetary_total.charge_total_amount)
|
|
||||||
|
|
||||||
fexml.set_element_amount(
|
fexml.set_element_amount('./cac:RequestedMonetaryTotal/cbc:PayableAmount',
|
||||||
'./cac:RequestedMonetaryTotal/cbc:PayableAmount',
|
invoice.invoice_legal_monetary_total.payable_amount)
|
||||||
invoice.invoice_legal_monetary_total.payable_amount)
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,690 +0,0 @@
|
|||||||
from .. import fe
|
|
||||||
from ..form import (
|
|
||||||
Amount, DebitNoteDocumentReference, CreditNoteDocumentReference,
|
|
||||||
InvoiceDocumentReference, TaxTotalOmit, WithholdingTaxTotalOmit
|
|
||||||
)
|
|
||||||
|
|
||||||
from collections import defaultdict
|
|
||||||
from datetime import datetime
|
|
||||||
# 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
|
|
||||||
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"""
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# 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'
|
|
||||||
@@ -2,30 +2,18 @@ from .. import fe
|
|||||||
|
|
||||||
__all__ = ['DIANWrite', 'DIANWriteSigned']
|
__all__ = ['DIANWrite', 'DIANWriteSigned']
|
||||||
|
|
||||||
|
|
||||||
def DIANWrite(xml, filename):
|
def DIANWrite(xml, filename):
|
||||||
document = xml.tostring(xml_declaration=True, encoding='UTF-8')
|
document = xml.tostring(xml_declaration=True, encoding='UTF-8')
|
||||||
with open(filename, 'w') as f:
|
with open(filename, 'w') as f:
|
||||||
f.write(document)
|
f.write(document)
|
||||||
|
|
||||||
|
|
||||||
def DIANWriteSigned(
|
def DIANWriteSigned(xml, filename, private_key, passphrase, use_cache_policy=False, dian_signer=None):
|
||||||
xml,
|
document = xml.tostring(xml_declaration=True, encoding='UTF-8').encode('utf-8')
|
||||||
filename,
|
|
||||||
private_key,
|
|
||||||
passphrase,
|
|
||||||
use_cache_policy=False,
|
|
||||||
dian_signer=None):
|
|
||||||
document = xml.tostring(
|
|
||||||
xml_declaration=True,
|
|
||||||
encoding='UTF-8').encode('utf-8')
|
|
||||||
if dian_signer is None:
|
if dian_signer is None:
|
||||||
dian_signer = fe.DianXMLExtensionSigner
|
dian_signer = fe.DianXMLExtensionSigner
|
||||||
|
|
||||||
signer = dian_signer(
|
signer = dian_signer(private_key, passphrase=passphrase, localpolicy=use_cache_policy)
|
||||||
private_key,
|
|
||||||
passphrase=passphrase,
|
|
||||||
localpolicy=use_cache_policy)
|
|
||||||
|
|
||||||
with open(filename, 'w') as f:
|
with open(filename, 'w') as f:
|
||||||
f.write(signer.sign_xml_string(document))
|
f.write(signer.sign_xml_string(document))
|
||||||
|
|||||||
@@ -8,91 +8,21 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import typing
|
||||||
|
|
||||||
from .. import fe
|
from .. import fe
|
||||||
|
from .. import form
|
||||||
from ..data.dian import codelist
|
from ..data.dian import codelist
|
||||||
|
|
||||||
from .amount import Amount
|
from .devengado import *
|
||||||
from .deduccion import (
|
from .deduccion import *
|
||||||
Deduccion,
|
from .trabajador import *
|
||||||
DeduccionFondoPension,
|
from .empleador import *
|
||||||
DeduccionSalud,
|
from .pago import *
|
||||||
)
|
|
||||||
from .devengado import (
|
|
||||||
Devengado,
|
|
||||||
DevengadoBasico,
|
|
||||||
DevengadoHoraExtra,
|
|
||||||
DevengadoHorasExtrasDiarias,
|
|
||||||
DevengadoHorasExtrasDiariasDominicalesYFestivos,
|
|
||||||
DevengadoHorasExtrasNocturnas,
|
|
||||||
DevengadoHorasExtrasNocturnasDominicalesYFestivos,
|
|
||||||
DevengadoHorasRecargoDiariasDominicalesYFestivos,
|
|
||||||
DevengadoHorasRecargoNocturno,
|
|
||||||
DevengadoHorasRecargoNocturnoDominicalesYFestivos,
|
|
||||||
DevengadoTransporte,
|
|
||||||
)
|
|
||||||
from .empleador import Empleador
|
|
||||||
from .exception import DIANNominaIndividualError
|
|
||||||
from .lugar import Lugar
|
from .lugar import Lugar
|
||||||
from .pago import (
|
|
||||||
FormaPago,
|
|
||||||
MetodoPago,
|
|
||||||
Pago,
|
|
||||||
)
|
|
||||||
from .trabajador import (
|
|
||||||
LugarTrabajo,
|
|
||||||
SubTipoTrabajador,
|
|
||||||
TipoContrato,
|
|
||||||
TipoDocumento,
|
|
||||||
TipoTrabajador,
|
|
||||||
Trabajador,
|
|
||||||
)
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'Amount',
|
|
||||||
'Deduccion',
|
|
||||||
'DeduccionFondoPension',
|
|
||||||
'DeduccionSalud',
|
|
||||||
'Devengado',
|
|
||||||
'DevengadoBasico',
|
|
||||||
'DevengadoHoraExtra',
|
|
||||||
'DevengadoHorasExtrasDiarias',
|
|
||||||
'DevengadoHorasExtrasDiariasDominicalesYFestivos',
|
|
||||||
'DevengadoHorasExtrasNocturnas',
|
|
||||||
'DevengadoHorasExtrasNocturnasDominicalesYFestivos',
|
|
||||||
'DevengadoHorasRecargoDiariasDominicalesYFestivos',
|
|
||||||
'DevengadoHorasRecargoNocturno',
|
|
||||||
'DevengadoHorasRecargoNocturnoDominicalesYFestivos',
|
|
||||||
'DevengadoTransporte',
|
|
||||||
'DIANNominaIndividual',
|
|
||||||
'DIANNominaIndividualDeAjuste',
|
|
||||||
'DIANNominaXML',
|
|
||||||
'DIANNominaIndividualError',
|
|
||||||
'DianXMLExtensionSigner',
|
|
||||||
'Empleador',
|
|
||||||
'Fecha',
|
|
||||||
'FechaPago',
|
|
||||||
'FormaPago',
|
|
||||||
'InformacionGeneral',
|
|
||||||
'Lugar',
|
|
||||||
'LugarTrabajo',
|
|
||||||
'Metadata',
|
|
||||||
'MetodoPago',
|
|
||||||
'Novedad',
|
|
||||||
'NumeroSecuencia',
|
|
||||||
'Pago',
|
|
||||||
'Periodo',
|
|
||||||
'PeriodoNomina',
|
|
||||||
'Proveedor',
|
|
||||||
'SubTipoTrabajador',
|
|
||||||
'TipoContrato',
|
|
||||||
'TipoDocumento',
|
|
||||||
'TipoMoneda',
|
|
||||||
'TipoTrabajador',
|
|
||||||
'Trabajador',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
from .amount import Amount
|
||||||
|
from .exception import *
|
||||||
|
|
||||||
class Fecha:
|
class Fecha:
|
||||||
def __init__(self, fecha):
|
def __init__(self, fecha):
|
||||||
@@ -116,7 +46,6 @@ class Fecha:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class FechaPago(Fecha):
|
class FechaPago(Fecha):
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_element('./FechaPago', self.value)
|
fragment.set_element('./FechaPago', self.value)
|
||||||
@@ -124,20 +53,14 @@ class FechaPago(Fecha):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Novedad:
|
class Novedad:
|
||||||
# cune de nomina a relacionar
|
value: False
|
||||||
# NIE204
|
|
||||||
cune: str
|
|
||||||
# NIE199
|
|
||||||
activa: bool = False
|
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
if self.cune != "":
|
fragment.set_attributes('./Novedad',
|
||||||
fragment.set_attributes('./Novedad',
|
CUNENov=self.value,
|
||||||
CUNENov=self.cune,
|
)
|
||||||
)
|
|
||||||
|
|
||||||
def post_apply(self, fexml, scopexml, fragment):
|
def post_apply(self, fexml, scopexml, fragment):
|
||||||
scopexml.set_element('./Novedad', self.activa)
|
scopexml.set_element('./Novedad', "false")
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -153,43 +76,39 @@ class NumeroSecuencia:
|
|||||||
# NIE011
|
# NIE011
|
||||||
Consecutivo=self.consecutivo,
|
Consecutivo=self.consecutivo,
|
||||||
# NIE012
|
# NIE012
|
||||||
Numero=numero)
|
Numero = numero)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Periodo:
|
class Periodo:
|
||||||
fecha_ingreso: str | Fecha
|
fecha_ingreso: typing.Union[str, Fecha]
|
||||||
fecha_liquidacion_inicio: str | Fecha
|
fecha_liquidacion_inicio: typing.Union[str, Fecha]
|
||||||
fecha_liquidacion_fin: str | Fecha
|
fecha_liquidacion_fin: typing.Union[str, Fecha]
|
||||||
fecha_generacion: str | Fecha
|
fecha_generacion: typing.Union[str, Fecha]
|
||||||
|
|
||||||
tiempo_laborado: int = 1
|
tiempo_laborado: int = 1
|
||||||
fecha_retiro: str | Fecha | None = None
|
fecha_retiro: typing.Union[str, Fecha] = None
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.fecha_ingreso = Fecha.cast(self.fecha_ingreso)
|
self.fecha_ingreso = Fecha.cast(self.fecha_ingreso)
|
||||||
self.fecha_liquidacion_inicio = Fecha.cast(
|
self.fecha_liquidacion_inicio = Fecha.cast(self.fecha_liquidacion_inicio)
|
||||||
self.fecha_liquidacion_inicio)
|
|
||||||
self.fecha_liquidacion_fin = Fecha.cast(self.fecha_liquidacion_fin)
|
self.fecha_liquidacion_fin = Fecha.cast(self.fecha_liquidacion_fin)
|
||||||
self.fecha_retiro = Fecha.cast(self.fecha_retiro, optional=True)
|
self.fecha_retiro = Fecha.cast(self.fecha_retiro, optional=True)
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_attributes('./Periodo',
|
fragment.set_attributes('./Periodo',
|
||||||
# NIE002
|
#NIE002
|
||||||
FechaIngreso=self.fecha_ingreso,
|
FechaIngreso=self.fecha_ingreso,
|
||||||
# NIE003
|
#NIE003
|
||||||
FechaRetiro=self.fecha_retiro,
|
FechaRetiro=self.fecha_retiro,
|
||||||
# NIE004
|
#NIE004
|
||||||
FechaLiquidacionInicio=(
|
FechaLiquidacionInicio=self.fecha_liquidacion_inicio,
|
||||||
self.fecha_liquidacion_inicio),
|
#NIE005
|
||||||
# NIE005
|
|
||||||
FechaLiquidacionFin=self.fecha_liquidacion_fin,
|
FechaLiquidacionFin=self.fecha_liquidacion_fin,
|
||||||
# NIE006
|
#NIE006
|
||||||
TiempoLaborado=self.tiempo_laborado,
|
TiempoLaborado=self.tiempo_laborado,
|
||||||
# NIE008
|
#NIE008
|
||||||
FechaGen=self.fecha_generacion)
|
FechaGen=self.fecha_generacion)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Proveedor:
|
class Proveedor:
|
||||||
razon_social: str
|
razon_social: str
|
||||||
@@ -215,36 +134,30 @@ class Proveedor:
|
|||||||
def post_apply(self, fexml, scopexml, fragment):
|
def post_apply(self, fexml, scopexml, fragment):
|
||||||
cune_xpath = scopexml.xpath_from_root('/InformacionGeneral')
|
cune_xpath = scopexml.xpath_from_root('/InformacionGeneral')
|
||||||
cune = fexml.get_element_attribute(cune_xpath, 'CUNE')
|
cune = fexml.get_element_attribute(cune_xpath, 'CUNE')
|
||||||
|
|
||||||
|
ambiente = fexml.get_element_attribute(scopexml.xpath_from_root('/InformacionGeneral'), 'Ambiente')
|
||||||
|
codigo_qr = f"https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey={cune}"
|
||||||
|
|
||||||
ambiente = fexml.get_element_attribute(
|
if InformacionGeneral.AMBIENTE_PRUEBAS.same(ambiente):
|
||||||
scopexml.xpath_from_root('/InformacionGeneral'), 'Ambiente')
|
codigo_qr = f"https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey={cune}"
|
||||||
codigo_qr = (
|
|
||||||
f"https://catalogo-vpfe.dian.gov.co/document/"
|
|
||||||
f"searchqr?documentkey={cune}")
|
|
||||||
|
|
||||||
if InformacionGeneral.AMBIENTE_PRUEBAS == ambiente:
|
|
||||||
codigo_qr = (
|
|
||||||
f"https://catalogo-vpfe-hab.dian.gov.co/document/"
|
|
||||||
f"searchqr?documentkey={cune}")
|
|
||||||
elif ambiente is None:
|
elif ambiente is None:
|
||||||
raise RuntimeError('fail to get InformacionGeneral/@Ambiente')
|
raise RuntimeError('fail to get InformacionGeneral/@Ambiente')
|
||||||
|
|
||||||
scopexml.set_element('./CodigoQR', codigo_qr)
|
scopexml.set_element('./CodigoQR', codigo_qr)
|
||||||
|
scopexml.set_element('./Novedad', "false")
|
||||||
|
|
||||||
# NIE020
|
# NIE020
|
||||||
software_code = self._software_security_code(fexml, scopexml)
|
software_code = self._software_security_code(fexml, scopexml)
|
||||||
fexml.set_attributes(
|
fexml.set_attributes(scopexml.xpath_from_root('/ProveedorXML'), SoftwareSC=software_code)
|
||||||
scopexml.xpath_from_root('/ProveedorXML'),
|
|
||||||
SoftwareSC=software_code)
|
|
||||||
|
|
||||||
def _software_security_code(self, fexml, scopexml):
|
def _software_security_code(self, fexml, scopexml):
|
||||||
|
|
||||||
|
|
||||||
# 8.2
|
# 8.2
|
||||||
numero = fexml.get_element_attribute(
|
numero = fexml.get_element_attribute(scopexml.xpath_from_root('/NumeroSecuenciaXML'), 'Numero')
|
||||||
scopexml.xpath_from_root('/NumeroSecuenciaXML'), 'Numero')
|
|
||||||
if numero is None:
|
if numero is None:
|
||||||
raise RuntimeError('fallo obtener NumeroSequenciaXML/@Numero')
|
raise RuntimeError('fallo obtener NumeroSequenciaXML/@Numero')
|
||||||
|
|
||||||
id_software = self.software_id
|
id_software = self.software_id
|
||||||
software_pin = self.software_pin
|
software_pin = self.software_pin
|
||||||
|
|
||||||
@@ -254,8 +167,7 @@ class Proveedor:
|
|||||||
h = hashlib.sha384()
|
h = hashlib.sha384()
|
||||||
h.update(code.encode('utf-8'))
|
h.update(code.encode('utf-8'))
|
||||||
return h.hexdigest()
|
return h.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Metadata:
|
class Metadata:
|
||||||
novedad: Novedad
|
novedad: Novedad
|
||||||
@@ -264,33 +176,16 @@ class Metadata:
|
|||||||
lugar_generacion: Lugar
|
lugar_generacion: Lugar
|
||||||
proveedor: Proveedor
|
proveedor: Proveedor
|
||||||
|
|
||||||
def apply(
|
def apply(self, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml):
|
||||||
self,
|
self.novedad.apply(novedad)
|
||||||
novedad,
|
|
||||||
numero_secuencia_xml,
|
|
||||||
lugar_generacion_xml,
|
|
||||||
proveedor_xml):
|
|
||||||
if novedad:
|
|
||||||
self.novedad.apply(novedad)
|
|
||||||
self.secuencia.apply(numero_secuencia_xml)
|
self.secuencia.apply(numero_secuencia_xml)
|
||||||
self.lugar_generacion.apply(
|
self.lugar_generacion.apply(lugar_generacion_xml, './LugarGeneracionXML')
|
||||||
lugar_generacion_xml,
|
|
||||||
'./LugarGeneracionXML')
|
|
||||||
self.proveedor.apply(proveedor_xml)
|
self.proveedor.apply(proveedor_xml)
|
||||||
|
|
||||||
def post_apply(
|
def post_apply(self, fexml, scopexml, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml):
|
||||||
self,
|
|
||||||
fexml,
|
|
||||||
scopexml,
|
|
||||||
novedad,
|
|
||||||
numero_secuencia_xml,
|
|
||||||
lugar_generacion_xml,
|
|
||||||
proveedor_xml):
|
|
||||||
self.proveedor.post_apply(fexml, scopexml, proveedor_xml)
|
self.proveedor.post_apply(fexml, scopexml, proveedor_xml)
|
||||||
if novedad:
|
self.novedad.post_apply(fexml, scopexml, proveedor_xml)
|
||||||
self.novedad.post_apply(fexml, scopexml, proveedor_xml)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PeriodoNomina:
|
class PeriodoNomina:
|
||||||
code: str
|
code: str
|
||||||
@@ -301,7 +196,6 @@ class PeriodoNomina:
|
|||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.PeriodoNomina[self.code]['name']
|
self.name = codelist.PeriodoNomina[self.code]['name']
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TipoMoneda:
|
class TipoMoneda:
|
||||||
code: str
|
code: str
|
||||||
@@ -312,15 +206,15 @@ class TipoMoneda:
|
|||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.TipoMoneda[self.code]['name']
|
self.name = codelist.TipoMoneda[self.code]['name']
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class InformacionGeneral:
|
class InformacionGeneral:
|
||||||
@dataclass
|
@dataclass
|
||||||
class TIPO_AMBIENTE:
|
class TIPO_AMBIENTE:
|
||||||
valor: str
|
valor: str
|
||||||
|
|
||||||
def __eq__(self, other):
|
@classmethod
|
||||||
return self.valor == str(other)
|
def same(cls, value):
|
||||||
|
return cls.valor == str(value)
|
||||||
|
|
||||||
# TABLA 5.1.1
|
# TABLA 5.1.1
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -337,34 +231,11 @@ class InformacionGeneral:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
self.valor
|
self.valor
|
||||||
|
|
||||||
# TABLA 5.5.7
|
fecha_generacion: typing.Union[str, Fecha]
|
||||||
@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
|
|
||||||
|
|
||||||
fecha_generacion: str | Fecha
|
|
||||||
hora_generacion: str
|
hora_generacion: str
|
||||||
periodo_nomina: PeriodoNomina
|
periodo_nomina: PeriodoNomina
|
||||||
tipo_moneda: TipoMoneda
|
tipo_moneda: TipoMoneda
|
||||||
tipo_ambiente: TIPO_AMBIENTE
|
tipo_ambiente: TIPO_AMBIENTE
|
||||||
tipo_xml: TIPO_XML
|
|
||||||
software_pin: str
|
software_pin: str
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
@@ -373,26 +244,26 @@ class InformacionGeneral:
|
|||||||
def apply(self, fragment, version):
|
def apply(self, fragment, version):
|
||||||
fragment.set_attributes('./InformacionGeneral',
|
fragment.set_attributes('./InformacionGeneral',
|
||||||
# NIE022
|
# NIE022
|
||||||
Version=version,
|
Version = version,
|
||||||
# NIE023
|
# NIE023
|
||||||
Ambiente=self.tipo_ambiente.valor,
|
Ambiente = self.tipo_ambiente.valor,
|
||||||
# NIE202
|
# NIE202
|
||||||
# TABLA 5.5.2
|
# TABLA 5.5.2
|
||||||
# TODO(bit4bit) solo NominaIndividual
|
# TODO(bit4bit) solo NominaIndividual
|
||||||
TipoXML=self.tipo_xml.valor,
|
TipoXML = '103',
|
||||||
# NIE024
|
# NIE024
|
||||||
CUNE=None,
|
CUNE = None,
|
||||||
# NIE025
|
# NIE025
|
||||||
EncripCUNE='CUNE-SHA384',
|
EncripCUNE = 'CUNE-SHA384',
|
||||||
# NIE026
|
# NIE026
|
||||||
FechaGen=self.fecha_generacion,
|
FechaGen = self.fecha_generacion,
|
||||||
# NIE027
|
# NIE027
|
||||||
HoraGen=self.hora_generacion,
|
HoraGen = self.hora_generacion,
|
||||||
# NIE029
|
# NIE029
|
||||||
PeriodoNomina=self.periodo_nomina.code,
|
PeriodoNomina = self.periodo_nomina.code,
|
||||||
# NIE030
|
# NIE030
|
||||||
TipoMoneda=self.tipo_moneda.code,
|
TipoMoneda = self.tipo_moneda.code,
|
||||||
TRM=0
|
TRM = 0
|
||||||
# TODO(bit4bit) resto...
|
# TODO(bit4bit) resto...
|
||||||
# .....
|
# .....
|
||||||
)
|
)
|
||||||
@@ -421,64 +292,63 @@ class InformacionGeneral:
|
|||||||
h = hashlib.sha384()
|
h = hashlib.sha384()
|
||||||
h.update(cune.encode('utf-8'))
|
h.update(cune.encode('utf-8'))
|
||||||
cune_hash = h.hexdigest()
|
cune_hash = h.hexdigest()
|
||||||
|
|
||||||
fragment.set_attributes(
|
fragment.set_attributes(
|
||||||
'./InformacionGeneral',
|
'./InformacionGeneral',
|
||||||
# NIE024
|
# NIE024
|
||||||
CUNE=cune_hash
|
CUNE = cune_hash
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionSigner(fe.DianXMLExtensionSigner):
|
class DianXMLExtensionSigner(fe.DianXMLExtensionSigner):
|
||||||
|
|
||||||
def __init__(self, pkcs12_path, passphrase=None, localpolicy=True):
|
def __init__(self, pkcs12_path, passphrase=None, localpolicy=True):
|
||||||
super().__init__(
|
super().__init__(pkcs12_path, passphrase=passphrase, localpolicy=localpolicy)
|
||||||
pkcs12_path,
|
|
||||||
passphrase=passphrase,
|
|
||||||
localpolicy=localpolicy)
|
|
||||||
|
|
||||||
def _element_extension_content(self, fachoxml):
|
def _element_extension_content(self, fachoxml):
|
||||||
return fachoxml.builder.xpath(
|
return fachoxml.builder.xpath(fachoxml.root, './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
||||||
fachoxml.root,
|
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
|
||||||
|
|
||||||
|
|
||||||
class DIANNominaXML:
|
class DIANNominaXML:
|
||||||
def __init__(
|
def __init__(self, tag_document, xpath_ajuste=None,schemaLocation=None):
|
||||||
self,
|
|
||||||
tag_document,
|
|
||||||
xpath_ajuste=None,
|
|
||||||
schemaLocation=None,
|
|
||||||
namespace_ajuste=None):
|
|
||||||
self.informacion_general_version = None
|
self.informacion_general_version = None
|
||||||
|
|
||||||
self.tag_document = tag_document
|
self.tag_document = tag_document
|
||||||
|
self.fexml = fe.FeXML(tag_document, "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste")
|
||||||
|
|
||||||
if namespace_ajuste:
|
if schemaLocation is not None:
|
||||||
self.fexml = fe.FeXML(tag_document, namespace_ajuste)
|
self.fexml.root.set(
|
||||||
|
"SchemaLocation",
|
||||||
|
"dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||||
|
)
|
||||||
|
self.fexml.root.set("change", schemaLocation)
|
||||||
else:
|
else:
|
||||||
self.fexml = fe.FeXML(
|
schemaLocation = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||||
tag_document,
|
self.fexml.root.set(
|
||||||
'dian:gov:co:facturaelectronica:NominaIndividual')
|
"SchemaLocation", "")
|
||||||
|
self.fexml.root.set(
|
||||||
|
"change", schemaLocation)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# self.fexml.root.set(
|
||||||
|
# "SchemaLocation",
|
||||||
|
# "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||||
|
#)
|
||||||
|
# self.fexml.root.set("change", schemaLocation)
|
||||||
|
|
||||||
self.fexml.root.set("SchemaLocation", "")
|
|
||||||
self.fexml.root.set("schemaLocation", schemaLocation)
|
|
||||||
|
|
||||||
# layout, la dian requiere que los elementos
|
# layout, la dian requiere que los elementos
|
||||||
# esten ordenados segun el anexo tecnico
|
# esten ordenados segun el anexo tecnico
|
||||||
self.fexml.placeholder_for(
|
self.fexml.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
|
||||||
self.fexml.placeholder_for('./TipoNota', optional=True)
|
self.fexml.placeholder_for('./TipoNota', optional=True)
|
||||||
|
|
||||||
self.root_fragment = self.fexml
|
self.root_fragment = self.fexml
|
||||||
if xpath_ajuste is not None:
|
if xpath_ajuste is not None:
|
||||||
self.root_fragment = self.fexml.fragment(xpath_ajuste)
|
self.root_fragment = self.fexml.fragment(xpath_ajuste)
|
||||||
self.root_fragment.placeholder_for(
|
self.root_fragment.placeholder_for('./ReemplazandoPredecesor', optional=True)
|
||||||
'./ReemplazandoPredecesor', optional=True)
|
self.root_fragment.placeholder_for('./EliminandoPredecesor', optional=True)
|
||||||
self.root_fragment.placeholder_for(
|
self.root_fragment.placeholder_for('./Novedad', optional=False)
|
||||||
'./EliminandoPredecesor', optional=True)
|
|
||||||
if not namespace_ajuste:
|
|
||||||
self.root_fragment.placeholder_for('./Novedad', optional=False)
|
|
||||||
self.root_fragment.placeholder_for('./Periodo')
|
self.root_fragment.placeholder_for('./Periodo')
|
||||||
self.root_fragment.placeholder_for('./NumeroSecuenciaXML')
|
self.root_fragment.placeholder_for('./NumeroSecuenciaXML')
|
||||||
self.root_fragment.placeholder_for('./LugarGeneracionXML')
|
self.root_fragment.placeholder_for('./LugarGeneracionXML')
|
||||||
@@ -490,20 +360,14 @@ class DIANNominaXML:
|
|||||||
self.root_fragment.placeholder_for('./Pago')
|
self.root_fragment.placeholder_for('./Pago')
|
||||||
self.root_fragment.placeholder_for('./FechasPagos')
|
self.root_fragment.placeholder_for('./FechasPagos')
|
||||||
self.root_fragment.placeholder_for('./Devengados/Basico')
|
self.root_fragment.placeholder_for('./Devengados/Basico')
|
||||||
self.root_fragment.placeholder_for(
|
self.root_fragment.placeholder_for('./Devengados/Transporte', optional=True)
|
||||||
'./Devengados/Transporte', optional=True)
|
|
||||||
if not namespace_ajuste:
|
self.novedad = self.root_fragment.fragment('./Novedad')
|
||||||
self.novedad = self.root_fragment.fragment('./Novedad')
|
self.informacion_general_xml = self.root_fragment.fragment('./InformacionGeneral')
|
||||||
else:
|
|
||||||
self.novedad = None
|
|
||||||
self.informacion_general_xml = self.root_fragment.fragment(
|
|
||||||
'./InformacionGeneral')
|
|
||||||
self.periodo_xml = self.root_fragment.fragment('./Periodo')
|
self.periodo_xml = self.root_fragment.fragment('./Periodo')
|
||||||
self.fecha_pagos_xml = self.root_fragment.fragment('./FechasPagos')
|
self.fecha_pagos_xml = self.root_fragment.fragment('./FechasPagos')
|
||||||
self.numero_secuencia_xml = self.root_fragment.fragment(
|
self.numero_secuencia_xml = self.root_fragment.fragment('./NumeroSecuenciaXML')
|
||||||
'./NumeroSecuenciaXML')
|
self.lugar_generacion_xml = self.root_fragment.fragment('./LugarGeneracionXML')
|
||||||
self.lugar_generacion_xml = self.root_fragment.fragment(
|
|
||||||
'./LugarGeneracionXML')
|
|
||||||
self.proveedor_xml = self.root_fragment.fragment('./ProveedorXML')
|
self.proveedor_xml = self.root_fragment.fragment('./ProveedorXML')
|
||||||
self.empleador = self.root_fragment.fragment('./Empleador')
|
self.empleador = self.root_fragment.fragment('./Empleador')
|
||||||
self.trabajador = self.root_fragment.fragment('./Trabajador')
|
self.trabajador = self.root_fragment.fragment('./Trabajador')
|
||||||
@@ -518,20 +382,13 @@ class DIANNominaXML:
|
|||||||
if not isinstance(metadata, Metadata):
|
if not isinstance(metadata, Metadata):
|
||||||
raise ValueError('se espera tipo Metadata')
|
raise ValueError('se espera tipo Metadata')
|
||||||
self.metadata = metadata
|
self.metadata = metadata
|
||||||
|
self.metadata.apply(self.novedad, self.numero_secuencia_xml, self.lugar_generacion_xml, self.proveedor_xml)
|
||||||
self.metadata.apply(
|
|
||||||
self.novedad,
|
|
||||||
self.numero_secuencia_xml,
|
|
||||||
self.lugar_generacion_xml,
|
|
||||||
self.proveedor_xml)
|
|
||||||
|
|
||||||
def asignar_informacion_general(self, general):
|
def asignar_informacion_general(self, general):
|
||||||
if not isinstance(general, InformacionGeneral):
|
if not isinstance(general, InformacionGeneral):
|
||||||
raise ValueError('se espera tipo InformacionGeneral')
|
raise ValueError('se espera tipo InformacionGeneral')
|
||||||
self.informacion_general = general
|
self.informacion_general = general
|
||||||
self.informacion_general.apply(
|
self.informacion_general.apply(self.informacion_general_xml, self.informacion_general_version)
|
||||||
self.informacion_general_xml,
|
|
||||||
self.informacion_general_version)
|
|
||||||
|
|
||||||
def asignar_periodo(self, periodo):
|
def asignar_periodo(self, periodo):
|
||||||
if not isinstance(periodo, Periodo):
|
if not isinstance(periodo, Periodo):
|
||||||
@@ -561,7 +418,7 @@ class DIANNominaXML:
|
|||||||
if not isinstance(trabajador, Trabajador):
|
if not isinstance(trabajador, Trabajador):
|
||||||
raise ValueError('se espera tipo Trabajador')
|
raise ValueError('se espera tipo Trabajador')
|
||||||
trabajador.apply(self.trabajador)
|
trabajador.apply(self.trabajador)
|
||||||
|
|
||||||
def adicionar_devengado(self, devengado):
|
def adicionar_devengado(self, devengado):
|
||||||
if not isinstance(devengado, Devengado):
|
if not isinstance(devengado, Devengado):
|
||||||
raise ValueError('se espera tipo Devengado')
|
raise ValueError('se espera tipo Devengado')
|
||||||
@@ -608,7 +465,7 @@ class DIANNominaXML:
|
|||||||
self.fexml.xpath_from_root('/Devengados/Basico'),
|
self.fexml.xpath_from_root('/Devengados/Basico'),
|
||||||
'se requiere DevengadoBasico'
|
'se requiere DevengadoBasico'
|
||||||
)
|
)
|
||||||
|
|
||||||
check_element(
|
check_element(
|
||||||
self.fexml.xpath_from_root('/Deducciones/Salud'),
|
self.fexml.xpath_from_root('/Deducciones/Salud'),
|
||||||
'se requiere DeduccionSalud'
|
'se requiere DeduccionSalud'
|
||||||
@@ -624,13 +481,10 @@ class DIANNominaXML:
|
|||||||
def informacion_general(self):
|
def informacion_general(self):
|
||||||
xpath = self.root_fragment.xpath_from_root('/InformacionGeneral')
|
xpath = self.root_fragment.xpath_from_root('/InformacionGeneral')
|
||||||
return {
|
return {
|
||||||
'cune': self.fexml.get_element_attribute(
|
'cune': self.fexml.get_element_attribute(cune_xpath, 'CUNE'),
|
||||||
xpath, 'CUNE'),
|
'fecha_generacion': self.fexml.get_element_attribute(xpath, 'FechaGen'),
|
||||||
'fecha_generacion': self.fexml.get_element_attribute(
|
'numero': self.fexml.get_element_attribute(self.root_fragment('/NumeroSecuenciaXML', 'Numero'))
|
||||||
xpath, 'FechaGen'),
|
}
|
||||||
'numero': self.fexml.get_element_attribute(
|
|
||||||
self.root_fragment(
|
|
||||||
'/NumeroSecuenciaXML', 'Numero'))}
|
|
||||||
|
|
||||||
def toFachoXML(self):
|
def toFachoXML(self):
|
||||||
self._devengados_total()
|
self._devengados_total()
|
||||||
@@ -638,78 +492,57 @@ class DIANNominaXML:
|
|||||||
self._comprobante_total()
|
self._comprobante_total()
|
||||||
|
|
||||||
if self.informacion_general is not None:
|
if self.informacion_general is not None:
|
||||||
# TODO(bit4bit) acoplamiento temporal
|
#TODO(bit4bit) acoplamiento temporal
|
||||||
# es importante el orden de ejecucion
|
# es importante el orden de ejecucion
|
||||||
|
|
||||||
self.informacion_general.post_apply(
|
self.informacion_general.post_apply(self.fexml, self.root_fragment, self.informacion_general_xml)
|
||||||
self.fexml, self.root_fragment, self.informacion_general_xml)
|
|
||||||
|
|
||||||
if self.metadata is not None:
|
if self.metadata is not None:
|
||||||
self.metadata.post_apply(
|
self.metadata.post_apply(self.fexml, self.root_fragment, self.novedad, self.numero_secuencia_xml, self.lugar_generacion_xml, self.proveedor_xml)
|
||||||
self.fexml,
|
|
||||||
self.root_fragment,
|
|
||||||
self.novedad,
|
|
||||||
self.numero_secuencia_xml,
|
|
||||||
self.lugar_generacion_xml,
|
|
||||||
self.proveedor_xml)
|
|
||||||
|
|
||||||
return self.fexml
|
return self.fexml
|
||||||
|
|
||||||
def _comprobante_total(self):
|
def _comprobante_total(self):
|
||||||
devengados_total = self.root_fragment.get_element_text_or_attribute(
|
devengados_total = self.root_fragment.get_element_text_or_attribute('./DevengadosTotal', '0.0')
|
||||||
'./DevengadosTotal', '0.0')
|
deducciones_total = self.root_fragment.get_element_text_or_attribute('./DeduccionesTotal', '0.0')
|
||||||
deducciones_total = self.root_fragment.get_element_text_or_attribute(
|
|
||||||
'./DeduccionesTotal', '0.0')
|
|
||||||
|
|
||||||
comprobante_total = Amount(devengados_total) - \
|
comprobante_total = Amount(devengados_total) - Amount(deducciones_total)
|
||||||
Amount(deducciones_total)
|
|
||||||
|
|
||||||
self.root_fragment.set_element(
|
self.root_fragment.set_element('./ComprobanteTotal', str(round(comprobante_total, 2)))
|
||||||
'./ComprobanteTotal', str(round(comprobante_total, 2)))
|
|
||||||
|
|
||||||
def _deducciones_total(self):
|
def _deducciones_total(self):
|
||||||
xpaths = [
|
xpaths = [
|
||||||
self.root_fragment.xpath_from_root(
|
self.root_fragment.xpath_from_root('/Deducciones/Salud/@Deduccion'),
|
||||||
'/Deducciones/Salud/@Deduccion'),
|
self.root_fragment.xpath_from_root('/Deducciones/FondoPension/@Deduccion')
|
||||||
self.root_fragment.xpath_from_root(
|
]
|
||||||
'/Deducciones/FondoPension/@Deduccion')]
|
|
||||||
deducciones = map(lambda valor: Amount(valor),
|
deducciones = map(lambda valor: Amount(valor),
|
||||||
self._values_of_xpaths(xpaths))
|
self._values_of_xpaths(xpaths))
|
||||||
|
|
||||||
deducciones_total = Amount(0.0)
|
deducciones_total = Amount(0.0)
|
||||||
|
|
||||||
for deduccion in deducciones:
|
for deduccion in deducciones:
|
||||||
deducciones_total += deduccion
|
deducciones_total += deduccion
|
||||||
|
|
||||||
self.root_fragment.set_element(
|
self.root_fragment.set_element('./DeduccionesTotal', str(round(deducciones_total, 2)))
|
||||||
'./DeduccionesTotal', str(round(deducciones_total, 2)))
|
|
||||||
|
|
||||||
def _devengados_total(self):
|
def _devengados_total(self):
|
||||||
xpaths = [
|
xpaths = [
|
||||||
self.root_fragment.xpath_from_root(
|
self.root_fragment.xpath_from_root('/Devengados/Basico/@SueldoTrabajado'),
|
||||||
'/Devengados/Basico/@SueldoTrabajado'),
|
self.root_fragment.xpath_from_root('/Devengados/Transporte/@AuxilioTransporte'),
|
||||||
self.root_fragment.xpath_from_root(
|
self.root_fragment.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojS'),
|
||||||
'/Devengados/Transporte/@AuxilioTransporte'),
|
self.root_fragment.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojNS')
|
||||||
self.root_fragment.xpath_from_root(
|
]
|
||||||
'/Devengados/Transporte/@ViaticoManuAlojS'),
|
|
||||||
self.root_fragment.xpath_from_root(
|
|
||||||
'/Devengados/Transporte/@ViaticoManuAlojNS')]
|
|
||||||
devengados = map(lambda valor: Amount(valor),
|
devengados = map(lambda valor: Amount(valor),
|
||||||
self._values_of_xpaths(xpaths))
|
self._values_of_xpaths(xpaths))
|
||||||
|
|
||||||
devengados_total = Amount(0.0)
|
devengados_total = Amount(0.0)
|
||||||
for devengado in devengados:
|
for devengado in devengados:
|
||||||
devengados_total += devengado
|
devengados_total += devengado
|
||||||
# TODO(bit4bit) nque valor va redondeado?
|
self.root_fragment.set_element('./Redondeo', str(round(0,2)))
|
||||||
# NIE186
|
self.root_fragment.set_element('./DevengadosTotal', str(round(devengados_total,2)))
|
||||||
self.root_fragment.set_element('./Redondeo', str(round(0, 2)))
|
|
||||||
self.root_fragment.set_element(
|
|
||||||
'./DevengadosTotal', str(round(devengados_total, 2)))
|
|
||||||
|
|
||||||
def _values_of_xpaths(self, xpaths):
|
def _values_of_xpaths(self, xpaths):
|
||||||
xpaths_values_of_values = map(
|
xpaths_values_of_values = map(lambda val: self.fexml.get_element_text_or_attribute(val, multiple=True), xpaths)
|
||||||
lambda val: self.fexml.get_element_text_or_attribute(
|
|
||||||
val, multiple=True), xpaths)
|
|
||||||
xpaths_values = []
|
xpaths_values = []
|
||||||
# toda esta carreta para hacer un aplano de lista
|
# toda esta carreta para hacer un aplano de lista
|
||||||
for xpath_values in xpaths_values_of_values:
|
for xpath_values in xpaths_values_of_values:
|
||||||
@@ -721,24 +554,14 @@ class DIANNominaXML:
|
|||||||
|
|
||||||
return filter(lambda val: val is not None, xpaths_values)
|
return filter(lambda val: val is not None, xpaths_values)
|
||||||
|
|
||||||
|
|
||||||
class DIANNominaIndividual(DIANNominaXML):
|
class DIANNominaIndividual(DIANNominaXML):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
schema = (
|
|
||||||
"dian:gov:co:facturaelectronica:NominaIndividual"
|
|
||||||
" NominaIndividualElectronicaXSD.xsd"
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__('NominaIndividual', schemaLocation=schema)
|
super().__init__('NominaIndividual', schemaLocation=schema)
|
||||||
self.informacion_general_version = (
|
self.informacion_general_version = 'V1.0: Documento Soporte de Pago de Nómina Electrónica'
|
||||||
'V1.0: Documento Soporte de Pago de Nómina Electrónica')
|
|
||||||
|
|
||||||
# TODO(bit4bit) confirmar que no tienen en comun con NominaIndividual
|
# TODO(bit4bit) confirmar que no tienen en comun con NominaIndividual
|
||||||
|
|
||||||
|
|
||||||
class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
||||||
|
|
||||||
class Reemplazar(DIANNominaXML):
|
class Reemplazar(DIANNominaXML):
|
||||||
@dataclass
|
@dataclass
|
||||||
class Predecesor:
|
class Predecesor:
|
||||||
@@ -747,43 +570,29 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
|||||||
fecha_generacion: str
|
fecha_generacion: str
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
# NIAE214
|
|
||||||
fragment.set_element('./TipoNota', '1')
|
fragment.set_element('./TipoNota', '1')
|
||||||
fragment.set_element(
|
fragment.set_element('./Reemplazar/ReemplazandoPredecesor', None,
|
||||||
'./Reemplazar/ReemplazandoPredecesor', None,
|
# NIAE090
|
||||||
# NIAE090
|
NumeroPred = self.numero,
|
||||||
NumeroPred=self.numero,
|
# NIAE191
|
||||||
# NIAE191
|
CUNEPred = self.cune,
|
||||||
CUNEPred=self.cune,
|
# NIAE192
|
||||||
# NIAE192
|
FechaGenPred = self.fecha_generacion
|
||||||
FechaGenPred=self.fecha_generacion
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
schema = (
|
super().__init__('NominaIndividualDeAjuste', './Reemplazar')
|
||||||
"dian:gov:co:facturaelectronica:NominaIndividualDeAjuste"
|
# NIAE214
|
||||||
" NominaIndividualDeAjusteElectronicaXSD.xsd"
|
# self.root_fragment.set_element('./TipoNota', '1')
|
||||||
)
|
|
||||||
|
|
||||||
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):
|
def asignar_predecesor(self, predecesor):
|
||||||
if not isinstance(predecesor, self.Predecesor):
|
if not isinstance(predecesor, self.Predecesor):
|
||||||
raise ValueError("se espera tipo Predecesor")
|
raise ValueError("se espera tipo Predecesor")
|
||||||
predecesor.apply(self.fexml)
|
predecesor.apply(self.fexml)
|
||||||
|
|
||||||
|
|
||||||
class Eliminar(DIANNominaXML):
|
class Eliminar(DIANNominaXML):
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Predecesor:
|
class Predecesor:
|
||||||
numero: str
|
numero: str
|
||||||
@@ -794,29 +603,19 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
|||||||
fragment.set_element('./TipoNota', '2')
|
fragment.set_element('./TipoNota', '2')
|
||||||
fragment.set_element('./Eliminar/EliminandoPredecesor', None,
|
fragment.set_element('./Eliminar/EliminandoPredecesor', None,
|
||||||
# NIAE090
|
# NIAE090
|
||||||
NumeroPred=self.numero,
|
NumeroPred = self.numero,
|
||||||
# NIAE191
|
# NIAE191
|
||||||
CUNEPred=self.cune,
|
CUNEPred = self.cune,
|
||||||
# NIAE192
|
# NIAE192
|
||||||
FechaGenPred=self.fecha_generacion
|
FechaGenPred = self.fecha_generacion
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
schema = (
|
schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||||
"dian:gov:co:facturaelectronica:NominaIndividualDeAjuste"
|
super().__init__('NominaIndividualDeAjuste', './Eliminar')
|
||||||
" NominaIndividualDeAjusteElectronicaXSD.xsd"
|
|
||||||
)
|
|
||||||
super().__init__(
|
|
||||||
'NominaIndividualDeAjuste',
|
|
||||||
'./Eliminar',
|
|
||||||
schemaLocation=schema,
|
|
||||||
namespace_ajuste=(
|
|
||||||
'dian:gov:co:facturaelectronica:'
|
|
||||||
'NominaIndividualDeAjuste'))
|
|
||||||
|
|
||||||
self.informacion_general_version = (
|
# self.root_fragment.set_element('./TipoNota', '2')
|
||||||
"V1.0: Nota de Ajuste de Documento Soporte de Pago de "
|
self.informacion_general_version = "V1.0: Nota de Ajuste de Documento Soporte de Pago de Nómina Electrónica"
|
||||||
"Nómina Electrónica")
|
|
||||||
|
|
||||||
def asignar_predecesor(self, predecesor):
|
def asignar_predecesor(self, predecesor):
|
||||||
if not isinstance(predecesor, self.Predecesor):
|
if not isinstance(predecesor, self.Predecesor):
|
||||||
@@ -824,4 +623,5 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
|||||||
predecesor.apply(self.fexml)
|
predecesor.apply(self.fexml)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||||
super().__init__('NominaIndividualDeAjuste')
|
super().__init__('NominaIndividualDeAjuste')
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from .. import form
|
from .. import form
|
||||||
|
|
||||||
|
|
||||||
class Amount(form.Amount):
|
class Amount(form.Amount):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
# al crear objetos de valor
|
# al crear objetos de valor
|
||||||
# se debe exportar en __all__
|
# se debe exportar en __all__
|
||||||
|
|
||||||
from .deduccion import Deduccion
|
from .deduccion import *
|
||||||
from .salud import DeduccionSalud
|
from .salud import *
|
||||||
from .fondo_pension import DeduccionFondoPension
|
from .fondo_pension import *
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Deduccion',
|
'Deduccion',
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from dataclasses import dataclass
|
|||||||
from ..amount import Amount
|
from ..amount import Amount
|
||||||
from .deduccion import Deduccion
|
from .deduccion import Deduccion
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DeduccionFondoPension(Deduccion):
|
class DeduccionFondoPension(Deduccion):
|
||||||
porcentaje: Amount
|
porcentaje: Amount
|
||||||
@@ -11,9 +10,9 @@ class DeduccionFondoPension(Deduccion):
|
|||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_element('./FondoPension', None,
|
fragment.set_element('./FondoPension', None,
|
||||||
append_=True,
|
append_ = True,
|
||||||
# NIE164
|
# NIE164
|
||||||
Porcentaje=str(round(self.porcentaje, 2)),
|
Porcentaje = str(round(self.porcentaje, 2)),
|
||||||
# NIE166
|
# NIE166
|
||||||
Deduccion=self.deduccion
|
Deduccion = self.deduccion
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from dataclasses import dataclass
|
|||||||
from ..amount import Amount
|
from ..amount import Amount
|
||||||
from .deduccion import Deduccion
|
from .deduccion import Deduccion
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DeduccionSalud(Deduccion):
|
class DeduccionSalud(Deduccion):
|
||||||
porcentaje: Amount
|
porcentaje: Amount
|
||||||
@@ -11,9 +10,10 @@ class DeduccionSalud(Deduccion):
|
|||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_element('./Salud', None,
|
fragment.set_element('./Salud', None,
|
||||||
append_=True,
|
append_ = True,
|
||||||
# NIE161
|
# NIE161
|
||||||
Porcentaje=str(round(self.porcentaje, 2)),
|
Porcentaje = str(round(self.porcentaje, 2)),
|
||||||
# NIE163
|
# NIE163
|
||||||
Deduccion=self.deduccion
|
Deduccion = self.deduccion
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from .. import form
|
from .. import form
|
||||||
|
|
||||||
|
|
||||||
class Departamento(form.CountrySubentity):
|
class Departamento(form.CountrySubentity):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
|
|
||||||
from .basico import DevengadoBasico
|
from .basico import *
|
||||||
from .transporte import DevengadoTransporte
|
from .transporte import *
|
||||||
from .devengado import Devengado
|
from .devengado import *
|
||||||
from .horas_extras import (
|
from .horas_extras import *
|
||||||
DevengadoHoraExtra,
|
|
||||||
DevengadoHorasExtrasDiarias,
|
|
||||||
DevengadoHorasExtrasNocturnas,
|
|
||||||
DevengadoHorasRecargoNocturno,
|
|
||||||
DevengadoHorasExtrasDiariasDominicalesYFestivos,
|
|
||||||
DevengadoHorasRecargoDiariasDominicalesYFestivos,
|
|
||||||
DevengadoHorasExtrasNocturnasDominicalesYFestivos,
|
|
||||||
DevengadoHorasRecargoNocturnoDominicalesYFestivos,
|
|
||||||
)
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Devengado',
|
'Devengado',
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ class DevengadoBasico(Devengado):
|
|||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.find_or_create_element('./Basico')
|
fragment.find_or_create_element('./Basico')
|
||||||
|
|
||||||
fragment.set_attributes('/Basico',
|
fragment.set_attributes('/Basico',
|
||||||
# NIE069
|
# NIE069
|
||||||
DiasTrabajados=str(self.dias_trabajados),
|
DiasTrabajados = str(self.dias_trabajados),
|
||||||
# NIE070
|
# NIE070
|
||||||
SueldoTrabajado=round(self.sueldo_trabajado, 2)
|
SueldoTrabajado = round(self.sueldo_trabajado, 2)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from ..amount import Amount
|
from ..amount import Amount
|
||||||
from .devengado import Devengado
|
from .devengado import Devengado
|
||||||
@@ -30,18 +30,17 @@ class DevengadoHoraExtra:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DevengadoHorasExtrasDiarias(Devengado):
|
class DevengadoHorasExtrasDiarias(Devengado):
|
||||||
horas_extras: list[DevengadoHoraExtra]
|
horas_extras: List[DevengadoHoraExtra]
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
hora_extra_xml = fragment.fragment('./HEDs')
|
hora_extra_xml = fragment.fragment('./HEDs')
|
||||||
for hora_extra in self.horas_extras:
|
for hora_extra in self.horas_extras:
|
||||||
hora_extra.apply('./HED', hora_extra_xml)
|
hora_extra.apply('./HED', hora_extra_xml)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DevengadoHorasExtrasNocturnas(Devengado):
|
class DevengadoHorasExtrasNocturnas(Devengado):
|
||||||
horas_extras: list[DevengadoHoraExtra]
|
horas_extras: List[DevengadoHoraExtra]
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
hora_extra_xml = fragment.fragment('./HENs')
|
hora_extra_xml = fragment.fragment('./HENs')
|
||||||
for hora_extra in self.horas_extras:
|
for hora_extra in self.horas_extras:
|
||||||
@@ -50,48 +49,44 @@ class DevengadoHorasExtrasNocturnas(Devengado):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DevengadoHorasRecargoNocturno(Devengado):
|
class DevengadoHorasRecargoNocturno(Devengado):
|
||||||
horas_extras: list[DevengadoHoraExtra]
|
horas_extras: List[DevengadoHoraExtra]
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
hora_extra_xml = fragment.fragment('./HRNs')
|
hora_extra_xml = fragment.fragment('./HRNs')
|
||||||
for hora_extra in self.horas_extras:
|
for hora_extra in self.horas_extras:
|
||||||
hora_extra.apply('./HRN', hora_extra_xml)
|
hora_extra.apply('./HRN', hora_extra_xml)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DevengadoHorasExtrasDiariasDominicalesYFestivos(Devengado):
|
class DevengadoHorasExtrasDiariasDominicalesYFestivos(Devengado):
|
||||||
horas_extras: list[DevengadoHoraExtra]
|
horas_extras: List[DevengadoHoraExtra]
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
hora_extra_xml = fragment.fragment('./HEDDFs')
|
hora_extra_xml = fragment.fragment('./HEDDFs')
|
||||||
for hora_extra in self.horas_extras:
|
for hora_extra in self.horas_extras:
|
||||||
hora_extra.apply('./HEDDF', hora_extra_xml)
|
hora_extra.apply('./HEDDF', hora_extra_xml)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DevengadoHorasRecargoDiariasDominicalesYFestivos(Devengado):
|
class DevengadoHorasRecargoDiariasDominicalesYFestivos(Devengado):
|
||||||
horas_extras: list[DevengadoHoraExtra]
|
horas_extras: List[DevengadoHoraExtra]
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
hora_extra_xml = fragment.fragment('./HRDDFs')
|
hora_extra_xml = fragment.fragment('./HRDDFs')
|
||||||
for hora_extra in self.horas_extras:
|
for hora_extra in self.horas_extras:
|
||||||
hora_extra.apply('./HRDDF', hora_extra_xml)
|
hora_extra.apply('./HRDDF', hora_extra_xml)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DevengadoHorasExtrasNocturnasDominicalesYFestivos(Devengado):
|
class DevengadoHorasExtrasNocturnasDominicalesYFestivos(Devengado):
|
||||||
horas_extras: list[DevengadoHoraExtra]
|
horas_extras: List[DevengadoHoraExtra]
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
hora_extra_xml = fragment.fragment('./HENDFs')
|
hora_extra_xml = fragment.fragment('./HENDFs')
|
||||||
for hora_extra in self.horas_extras:
|
for hora_extra in self.horas_extras:
|
||||||
hora_extra.apply('./HENDF', hora_extra_xml)
|
hora_extra.apply('./HENDF', hora_extra_xml)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DevengadoHorasRecargoNocturnoDominicalesYFestivos(Devengado):
|
class DevengadoHorasRecargoNocturnoDominicalesYFestivos(Devengado):
|
||||||
horas_extras: list[DevengadoHoraExtra]
|
horas_extras: List[DevengadoHoraExtra]
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
hora_extra_xml = fragment.fragment('./HRNDFs')
|
hora_extra_xml = fragment.fragment('./HRNDFs')
|
||||||
for hora_extra in self.horas_extras:
|
for hora_extra in self.horas_extras:
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from dataclasses import dataclass
|
|||||||
from ..amount import Amount
|
from ..amount import Amount
|
||||||
from .devengado import Devengado
|
from .devengado import Devengado
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DevengadoTransporte(Devengado):
|
class DevengadoTransporte(Devengado):
|
||||||
auxilio_transporte: Amount = None
|
auxilio_transporte: Amount = None
|
||||||
@@ -12,12 +11,11 @@ class DevengadoTransporte(Devengado):
|
|||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_element('./Transporte', None,
|
fragment.set_element('./Transporte', None,
|
||||||
append_=True,
|
append_ = True,
|
||||||
# NIE071
|
# NIE071
|
||||||
AuxilioTransporte=self.auxilio_transporte,
|
AuxilioTransporte = self.auxilio_transporte,
|
||||||
# NIE072
|
# NIE072
|
||||||
ViaticoManuAlojS=self.viatico_manutencion,
|
ViaticoManuAlojS = self.viatico_manutencion,
|
||||||
# NIE073
|
# NIE073
|
||||||
ViaticoManuAlojNS=(
|
ViaticoManuAlojNS = self.viatico_manutencion_no_salarial
|
||||||
self.viatico_manutencion_no_salarial)
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ from ..pais import Pais
|
|||||||
from ..departamento import Departamento
|
from ..departamento import Departamento
|
||||||
from ..municipio import Municipio
|
from ..municipio import Municipio
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Empleador:
|
class Empleador:
|
||||||
razon_social: str
|
razon_social: str
|
||||||
@@ -18,17 +17,19 @@ class Empleador:
|
|||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_attributes('./Empleador',
|
fragment.set_attributes('./Empleador',
|
||||||
# NIE033
|
# NIE033
|
||||||
NIT=self.nit,
|
NIT = self.nit,
|
||||||
# NIE034
|
# NIE034
|
||||||
DV=self.dv,
|
DV = self.dv,
|
||||||
# NIE035
|
# NIE035
|
||||||
Pais=self.pais.code,
|
Pais = self.pais.code,
|
||||||
# NIE036
|
# NIE036
|
||||||
DepartamentoEstado=self.departamento.code,
|
DepartamentoEstado = self.departamento.code,
|
||||||
# NIE037
|
# NIE037
|
||||||
MunicipioCiudad=self.municipio.code,
|
MunicipioCiudad = self.municipio.code,
|
||||||
# NIE038
|
# NIE038
|
||||||
Direccion=self.direccion,
|
Direccion = self.direccion,
|
||||||
|
|
||||||
RazonSocial=self.razon_social
|
RazonSocial=self.razon_social
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import datetime
|
|||||||
|
|
||||||
from facho import fe
|
from facho import fe
|
||||||
|
|
||||||
|
|
||||||
class Habilitacion:
|
class Habilitacion:
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -17,19 +16,19 @@ class Habilitacion:
|
|||||||
self.metadata = metadata
|
self.metadata = metadata
|
||||||
|
|
||||||
def generar(self, zipname, fecha):
|
def generar(self, zipname, fecha):
|
||||||
fe.DianZIP(open(zipname, 'w'))
|
nominas = []
|
||||||
|
dianzip = fe.DianZIP(open(zipname, 'w'))
|
||||||
|
|
||||||
fechabase = datetime.datetime.now()
|
fechabase = datetime.datetime.now()
|
||||||
consecutivo = 0
|
consecutivo = 0
|
||||||
for _ in range(1, 11):
|
for _ in range(1, 11):
|
||||||
consecutivo += 1
|
consecutivo += 1
|
||||||
fechabase += datetime.timedelta(days=1)
|
fechabase += datetime.timedelta(days=1)
|
||||||
self._crear_nomina_individual()
|
nomina = self._crear_nomina_individual()
|
||||||
|
|
||||||
# pag 96
|
# pag 96
|
||||||
"nie%010d%s%08x.xml" % (
|
nombre = "nie%010d%s%08x.xml" % (int(self.nit), fecha.strftime('%s'), consecutivo)
|
||||||
int(self.nit), fecha.strftime('%s'), consecutivo)
|
|
||||||
|
|
||||||
def _crear_nomina_individual_reemplazar(self, nomina, fechabase):
|
def _crear_nomina_individual_reemplazar(self, nomina, fechabase):
|
||||||
metadata = self.metadata
|
metadata = self.metadata
|
||||||
|
|
||||||
@@ -37,15 +36,10 @@ class Habilitacion:
|
|||||||
|
|
||||||
nomina_ajuste = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
|
nomina_ajuste = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
|
||||||
self._poblar_nomina(nomina_ajuste, metadata, fecha, prefijo='R')
|
self._poblar_nomina(nomina_ajuste, metadata, fecha, prefijo='R')
|
||||||
nomina.informacion_general()
|
informacion_general = nomina.informacion_general()
|
||||||
|
|
||||||
def _poblar_nomina(
|
|
||||||
self,
|
def _poblar_nomina(self, nomina, metadata, fecha, prefijo='N', consecutivo='0001'):
|
||||||
nomina,
|
|
||||||
metadata,
|
|
||||||
fecha,
|
|
||||||
prefijo='N',
|
|
||||||
consecutivo='0001'):
|
|
||||||
nomina.asignar_fecha_pago(fecha)
|
nomina.asignar_fecha_pago(fecha)
|
||||||
|
|
||||||
nomina.asignar_metadata(fe.nomina.Metadata(
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
@@ -54,14 +48,14 @@ class Habilitacion:
|
|||||||
consecutivo=consecutivo
|
consecutivo=consecutivo
|
||||||
),
|
),
|
||||||
lugar_generacion=fe.nomina.Lugar(
|
lugar_generacion=fe.nomina.Lugar(
|
||||||
pais=fe.nomina.Pais(
|
pais = fe.nomina.Pais(
|
||||||
code='CO'
|
code = 'CO'
|
||||||
),
|
),
|
||||||
departamento=fe.nomina.Departamento(
|
departamento = fe.nomina.Departamento(
|
||||||
code='05'
|
code = '05'
|
||||||
),
|
),
|
||||||
municipio=fe.nomina.Municipio(
|
municipio = fe.nomina.Municipio(
|
||||||
code='05001'
|
code = '05001'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
proveedor=fe.nomina.Proveedor(
|
proveedor=fe.nomina.Proveedor(
|
||||||
@@ -78,14 +72,14 @@ class Habilitacion:
|
|||||||
fecha_liquidacion_fin=fecha,
|
fecha_liquidacion_fin=fecha,
|
||||||
fecha_generacion=fecha,
|
fecha_generacion=fecha,
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
fecha_generacion=fecha,
|
fecha_generacion = fecha,
|
||||||
hora_generacion='20:09:00-05:00',
|
hora_generacion = '20:09:00-05:00',
|
||||||
tipo_ambiente=fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
||||||
software_pin=metadata.software_pin,
|
software_pin = metadata.software_pin,
|
||||||
periodo_nomina=fe.nomina.PeriodoNomina(code='1'),
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
tipo_moneda=fe.nomina.TipoMoneda(code='COP')
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.asignar_pago(fe.nomina.Pago(
|
nomina.asignar_pago(fe.nomina.Pago(
|
||||||
@@ -97,53 +91,53 @@ class Habilitacion:
|
|||||||
)
|
)
|
||||||
))
|
))
|
||||||
nomina.asignar_empleador(fe.nomina.Empleador(
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
nit=metadata.nit,
|
nit = metadata.nit,
|
||||||
dv='0',
|
dv = '0',
|
||||||
pais=fe.nomina.Pais(
|
pais = fe.nomina.Pais(
|
||||||
code='CO'
|
code = 'CO'
|
||||||
),
|
),
|
||||||
departamento=fe.nomina.Departamento(
|
departamento = fe.nomina.Departamento(
|
||||||
code='05'
|
code = '05'
|
||||||
),
|
),
|
||||||
municipio=fe.nomina.Municipio(
|
municipio = fe.nomina.Municipio(
|
||||||
code='05001'
|
code = '05001'
|
||||||
),
|
),
|
||||||
direccion='calle etrivial'
|
direccion = 'calle etrivial'
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.asignar_trabajador(fe.nomina.Trabajador(
|
nomina.asignar_trabajador(fe.nomina.Trabajador(
|
||||||
tipo_contrato=fe.nomina.TipoContrato(
|
tipo_contrato = fe.nomina.TipoContrato(
|
||||||
code='1'
|
code = '1'
|
||||||
),
|
),
|
||||||
alto_riesgo=False,
|
alto_riesgo = False,
|
||||||
tipo_documento=fe.nomina.TipoDocumento(
|
tipo_documento = fe.nomina.TipoDocumento(
|
||||||
code='11'
|
code = '11'
|
||||||
),
|
),
|
||||||
primer_apellido='gnu',
|
primer_apellido = 'gnu',
|
||||||
segundo_apellido='emacs',
|
segundo_apellido = 'emacs',
|
||||||
primer_nombre='facho',
|
primer_nombre = 'facho',
|
||||||
lugar_trabajo=fe.nomina.LugarTrabajo(
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
pais=fe.nomina.Pais(code='CO'),
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
departamento=fe.nomina.Departamento(code='05'),
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
municipio=fe.nomina.Municipio(code='05001'),
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
direccion='calle facho'
|
direccion = 'calle facho'
|
||||||
),
|
),
|
||||||
numero_documento=metadata.nit,
|
numero_documento = metadata.nit,
|
||||||
tipo=fe.nomina.TipoTrabajador(
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
code='01'
|
code = '01'
|
||||||
),
|
),
|
||||||
salario_integral=True,
|
salario_integral = True,
|
||||||
sueldo=fe.nomina.Amount(1_500_000)
|
sueldo = fe.nomina.Amount(1_500_000)
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
dias_trabajados=60,
|
dias_trabajados = 60,
|
||||||
sueldo_trabajado=fe.nomina.Amount(3_500_000)
|
sueldo_trabajado = fe.nomina.Amount(3_500_000)
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
porcentaje=fe.nomina.Amount(19),
|
porcentaje = fe.nomina.Amount(19),
|
||||||
deduccion=fe.nomina.Amount(1_000_000)
|
deduccion = fe.nomina.Amount(1_000_000)
|
||||||
))
|
))
|
||||||
|
|
||||||
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||||
@@ -158,3 +152,4 @@ class Habilitacion:
|
|||||||
|
|
||||||
nomina = fe.nomina.DIANNominaIndividual()
|
nomina = fe.nomina.DIANNominaIndividual()
|
||||||
self._poblar_nomina(nomina, metadata, fecha)
|
self._poblar_nomina(nomina, metadata, fecha)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from .departamento import Departamento
|
|||||||
from .municipio import Municipio
|
from .municipio import Municipio
|
||||||
from facho.fe.data.dian import codelist
|
from facho.fe.data.dian import codelist
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Lugar:
|
class Lugar:
|
||||||
pais: Pais
|
pais: Pais
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from .. import form
|
from .. import form
|
||||||
|
|
||||||
|
|
||||||
class Municipio(form.City):
|
class Municipio(form.City):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from dataclasses import dataclass
|
|||||||
from .forma_pago import FormaPago
|
from .forma_pago import FormaPago
|
||||||
from .metodo_pago import MetodoPago
|
from .metodo_pago import MetodoPago
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Pago:
|
class Pago:
|
||||||
forma: FormaPago
|
forma: FormaPago
|
||||||
@@ -12,6 +11,6 @@ class Pago:
|
|||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_attributes('./Pago',
|
fragment.set_attributes('./Pago',
|
||||||
# NIE064
|
# NIE064
|
||||||
Forma=self.forma.code,
|
Forma = self.forma.code,
|
||||||
# NIE065
|
# NIE065
|
||||||
Metodo=self.metodo.code)
|
Metodo = self.metodo.code)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from facho.fe.data.dian import codelist
|
from facho.fe.data.dian import codelist
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FormaPago:
|
class FormaPago:
|
||||||
code: str
|
code: str
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from facho.fe.data.dian import codelist
|
from facho.fe.data.dian import codelist
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MetodoPago:
|
class MetodoPago:
|
||||||
code: str
|
code: str
|
||||||
@@ -12,3 +11,4 @@ class MetodoPago:
|
|||||||
if self.code not in codelist.MediosPago:
|
if self.code not in codelist.MediosPago:
|
||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.MediosPago[self.code]['name']
|
self.name = codelist.MediosPago[self.code]['name']
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
from .. import form
|
from .. import form
|
||||||
|
|
||||||
|
|
||||||
class Pais(form.Country):
|
class Pais(form.Country):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from ..amount import Amount
|
from ..amount import Amount
|
||||||
|
|
||||||
from .tipo_contrato import TipoContrato
|
from .tipo_contrato import *
|
||||||
from .tipo_documento import TipoDocumento
|
from .tipo_documento import *
|
||||||
from .lugar_trabajo import LugarTrabajo
|
from .lugar_trabajo import *
|
||||||
from .tipo_trabajador import TipoTrabajador
|
from .tipo_trabajador import *
|
||||||
from .sub_tipo_trabajador import SubTipoTrabajador
|
from .sub_tipo_trabajador import *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -28,47 +29,45 @@ class Trabajador:
|
|||||||
|
|
||||||
codigo_trabajador: str = None
|
codigo_trabajador: str = None
|
||||||
otros_nombres: str = None
|
otros_nombres: str = None
|
||||||
sub_tipo: SubTipoTrabajador = field(
|
sub_tipo: SubTipoTrabajador = SubTipoTrabajador(code='00')
|
||||||
default_factory=lambda: SubTipoTrabajador(code="00")
|
|
||||||
)
|
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_attributes(
|
fragment.set_attributes('./Trabajador',
|
||||||
"./Trabajador",
|
# NIE041
|
||||||
# NIE041
|
TipoTrabajador = self.tipo.code,
|
||||||
TipoTrabajador=self.tipo.code,
|
# NIE042
|
||||||
# NIE042
|
SubTipoTrabajador = self.sub_tipo.code,
|
||||||
SubTipoTrabajador=self.sub_tipo.code,
|
# NIE043
|
||||||
# NIE043
|
AltoRiesgoPension = str(self.alto_riesgo).lower(),
|
||||||
AltoRiesgoPension=str(self.alto_riesgo).lower(),
|
# NIE044
|
||||||
# NIE044
|
TipoDocumento = self.tipo_documento.code,
|
||||||
TipoDocumento=self.tipo_documento.code,
|
# NIE045
|
||||||
# NIE045
|
NumeroDocumento = self.numero_documento,
|
||||||
NumeroDocumento=self.numero_documento,
|
# NIE046
|
||||||
# NIE046
|
PrimerApellido = self.primer_apellido,
|
||||||
PrimerApellido=self.primer_apellido,
|
# NIE047
|
||||||
# NIE047
|
SegundoApellido = self.segundo_apellido,
|
||||||
SegundoApellido=self.segundo_apellido,
|
# NIE048
|
||||||
# NIE048
|
PrimerNombre = self.primer_nombre,
|
||||||
PrimerNombre=self.primer_nombre,
|
# NIE049
|
||||||
# NIE049
|
OtrosNombres = self.otros_nombres,
|
||||||
OtrosNombres=self.otros_nombres,
|
# NIE050
|
||||||
# NIE050
|
LugarTrabajoPais = self.lugar_trabajo.pais.code,
|
||||||
LugarTrabajoPais=self.lugar_trabajo.pais.code,
|
|
||||||
# NIE051
|
# NIE051
|
||||||
LugarTrabajoDepartamentoEstado=(
|
LugarTrabajoDepartamentoEstado = self.lugar_trabajo.departamento.code,
|
||||||
self.lugar_trabajo.departamento.code
|
|
||||||
),
|
# NIE052
|
||||||
# NIE052
|
LugarTrabajoMunicipioCiudad = self.lugar_trabajo.municipio.code,
|
||||||
LugarTrabajoMunicipioCiudad=self.lugar_trabajo.municipio.code,
|
|
||||||
# NIE053
|
# NIE053
|
||||||
LugarTrabajoDireccion=self.lugar_trabajo.direccion,
|
LugarTrabajoDireccion = self.lugar_trabajo.direccion,
|
||||||
# NIE056
|
# NIE056
|
||||||
SalarioIntegral=str(self.salario_integral).lower(),
|
SalarioIntegral = str(self.salario_integral).lower(),
|
||||||
# NIE061
|
# NIE061
|
||||||
TipoContrato=self.tipo_contrato.code,
|
TipoContrato = self.tipo_contrato.code,
|
||||||
# NIE062
|
# NIE062
|
||||||
Sueldo=str(self.sueldo),
|
Sueldo = str(self.sueldo),
|
||||||
# NIE063
|
# NIE063
|
||||||
CodigoTrabajador=self.codigo_trabajador,
|
CodigoTrabajador = self.codigo_trabajador
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from . import *
|
||||||
from ..pais import Pais
|
from ..pais import Pais
|
||||||
from ..departamento import Departamento
|
from ..departamento import Departamento
|
||||||
from ..municipio import Municipio
|
from ..municipio import Municipio
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LugarTrabajo:
|
class LugarTrabajo:
|
||||||
pais: Pais
|
pais: Pais
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from facho.fe.data.dian import codelist
|
from facho.fe.data.dian import codelist
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SubTipoTrabajador:
|
class SubTipoTrabajador:
|
||||||
code: str
|
code: str
|
||||||
name: str = ""
|
name: str = ''
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if self.code not in codelist.SubTipoTrabajador:
|
if self.code not in codelist.SubTipoTrabajador:
|
||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.SubTipoTrabajador[self.code]["name"]
|
self.name = codelist.SubTipoTrabajador[self.code]['name']
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from facho.fe.data.dian import codelist
|
from facho.fe.data.dian import codelist
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TipoContrato:
|
class TipoContrato:
|
||||||
code: str
|
code: str
|
||||||
name: str = ""
|
name: str = ''
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if self.code not in codelist.TipoContrato:
|
if self.code not in codelist.TipoContrato:
|
||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.TipoContrato[self.code]["name"]
|
self.name = codelist.TipoContrato[self.code]['name']
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from facho.fe.data.dian import codelist
|
from facho.fe.data.dian import codelist
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TipoDocumento:
|
class TipoDocumento:
|
||||||
code: str
|
code: str
|
||||||
name: str = ""
|
name: str = ''
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if self.code not in codelist.TipoIdFiscal:
|
if self.code not in codelist.TipoIdFiscal:
|
||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.TipoIdFiscal[self.code]["name"]
|
self.name = codelist.TipoIdFiscal[self.code]['name']
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from facho.fe.data.dian import codelist
|
from facho.fe.data.dian import codelist
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TipoTrabajador:
|
class TipoTrabajador:
|
||||||
code: str
|
code: str
|
||||||
name: str = ""
|
name: str = ''
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if self.code not in codelist.TipoTrabajador:
|
if self.code not in codelist.TipoTrabajador:
|
||||||
raise ValueError("code [%s] not found" % (self.code))
|
raise ValueError("code [%s] not found" % (self.code))
|
||||||
self.name = codelist.TipoTrabajador[self.code]["name"]
|
self.name = codelist.TipoTrabajador[self.code]['name']
|
||||||
|
|||||||
1499
poetry.lock
generated
1499
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,79 +0,0 @@
|
|||||||
[build-system]
|
|
||||||
requires = ["setuptools>=68", "wheel"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "facho"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Facturacion Electronica Colombia"
|
|
||||||
readme = "README.rst"
|
|
||||||
license = { text = "GPL-3.0-or-later" }
|
|
||||||
authors = [
|
|
||||||
{ name = "Jovany Leandro G.C", email = "bit4bit@riseup.net" },
|
|
||||||
]
|
|
||||||
keywords = ["facho"]
|
|
||||||
classifiers = [
|
|
||||||
"Development Status :: 2 - Pre-Alpha",
|
|
||||||
"Intended Audience :: Developers",
|
|
||||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
||||||
"Natural Language :: English",
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
"Programming Language :: Python :: 3.12",
|
|
||||||
"Programming Language :: Python :: 3.13",
|
|
||||||
]
|
|
||||||
requires-python = ">=3.10"
|
|
||||||
dependencies = [
|
|
||||||
"Click>=8.1.7",
|
|
||||||
"zeep>=4.2.1",
|
|
||||||
"lxml>=5.2.2",
|
|
||||||
"cryptography>=41.0.0",
|
|
||||||
"pyOpenSSL>=23.2.0",
|
|
||||||
"xmlsig>=0.1.9",
|
|
||||||
"xades>=1.0.0",
|
|
||||||
"xmlsec>=1.3.12",
|
|
||||||
"python-dateutil>=2.9.0",
|
|
||||||
# usamos esta dependencia en runtime
|
|
||||||
# para forzar uso de policy_id de archivo local
|
|
||||||
"mock>=5.1.0",
|
|
||||||
"xmlschema>=3.0.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[project.scripts]
|
|
||||||
facho = "facho.cli:main"
|
|
||||||
|
|
||||||
[project.urls]
|
|
||||||
Repository = "https://github.com/bit4bit/facho"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
|
||||||
build = ">=1.2.2"
|
|
||||||
coverage = ">=7.8.0"
|
|
||||||
flake8 = ">=7.0.0"
|
|
||||||
pytest = ">=9.1.1,<10.0.0"
|
|
||||||
tox = ">=4.23.2"
|
|
||||||
|
|
||||||
|
|
||||||
[tool.setuptools]
|
|
||||||
packages = { find = { exclude = ["tests*"] } }
|
|
||||||
|
|
||||||
[tool.setuptools.package-data]
|
|
||||||
"*" = ["*.gc", "*.xsd", "politicadefirmav2.pdf"]
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
|
||||||
testpaths = ["tests"]
|
|
||||||
|
|
||||||
[tool.bumpversion]
|
|
||||||
current_version = "0.1.0"
|
|
||||||
commit = true
|
|
||||||
tag = true
|
|
||||||
|
|
||||||
[[tool.bumpversion.files]]
|
|
||||||
filename = "pyproject.toml"
|
|
||||||
search = 'version = "{current_version}"'
|
|
||||||
replace = 'version = "{new_version}"'
|
|
||||||
|
|
||||||
[[tool.bumpversion.files]]
|
|
||||||
filename = "facho/__init__.py"
|
|
||||||
search = "__version__ = '{current_version}'"
|
|
||||||
replace = "__version__ = '{new_version}'"
|
|
||||||
129
scrips/AJU00001.py
Normal file
129
scrips/AJU00001.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
from facho import fe
|
||||||
|
|
||||||
|
SOFTWARE_PIN='20234'
|
||||||
|
SOFTWARE_ID='100b0d10-0ca0-4ad4-a894-b704a568cbf3'
|
||||||
|
NIT='901575528'
|
||||||
|
DV='2'
|
||||||
|
|
||||||
|
def extensions(nomina):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def nomina():
|
||||||
|
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
|
||||||
|
|
||||||
|
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Eliminar.Predecesor(
|
||||||
|
numero='A000001',
|
||||||
|
fecha_generacion='2025-03-23',
|
||||||
|
cune = '38e3a0863b2cc46e0746d0d97d0b305125292f24c0e478f9dd4f4a097c4403ae4e52d96d90f8b5702fc5eac8bc71004b',
|
||||||
|
))
|
||||||
|
|
||||||
|
# nomina.asignar_fecha_pago('2024-04-30')
|
||||||
|
|
||||||
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
|
novedad=fe.nomina.Novedad(False),
|
||||||
|
secuencia=fe.nomina.NumeroSecuencia(
|
||||||
|
prefijo='AJU',
|
||||||
|
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(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit=NIT,
|
||||||
|
dv=DV,
|
||||||
|
software_id=SOFTWARE_ID,
|
||||||
|
software_pin=SOFTWARE_PIN
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_periodo(fe.nomina.Periodo(
|
||||||
|
fecha_ingreso= '2022-01-05',
|
||||||
|
fecha_liquidacion_inicio='2024-04-01',
|
||||||
|
fecha_liquidacion_fin='2024-04-30',
|
||||||
|
fecha_generacion='2024-04-30'
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
|
fecha_generacion = '2024-04-30',
|
||||||
|
hora_generacion = '08:01:00-05:00',
|
||||||
|
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
||||||
|
software_pin = SOFTWARE_PIN,
|
||||||
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_pago(fe.nomina.Pago(
|
||||||
|
forma=fe.nomina.FormaPago(
|
||||||
|
code='1',
|
||||||
|
),
|
||||||
|
metodo=fe.nomina.MetodoPago(
|
||||||
|
code='10'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
|
razon_social='BICI PIZZA S.A.S',
|
||||||
|
nit = NIT,
|
||||||
|
dv = DV,
|
||||||
|
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 = 'GONZALEZ',
|
||||||
|
segundo_apellido = '',
|
||||||
|
primer_nombre = 'JUAN',
|
||||||
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
|
direccion = 'CL 35C 102-17 BL 7 AP 101'
|
||||||
|
),
|
||||||
|
numero_documento = NIT,
|
||||||
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
|
code = '01'
|
||||||
|
),
|
||||||
|
salario_integral = False,
|
||||||
|
sueldo = fe.nomina.Amount(2400000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
|
dias_trabajados = 30,
|
||||||
|
sueldo_trabajado = fe.nomina.Amount(2400000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
|
porcentaje = fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(96000)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||||
|
porcentaje=fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(96000)
|
||||||
|
))
|
||||||
|
return nomina
|
||||||
|
|
||||||
89
scrips/AJU00001.xml
Normal file
89
scrips/AJU00001.xml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<NominaIndividualDeAjuste xmlns="dian:gov:co:facturaelectronica:NominaIndividualDeAjuste" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" SchemaLocation="" xsi:schemaLocation="dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"><ext:UBLExtensions><ext:UBLExtension><ext:ExtensionContent><ds:Signature Id="xmlsig-3fde635a-ad2d-4667-84f5-5f4207e64319">
|
||||||
|
<ds:SignedInfo>
|
||||||
|
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||||
|
<ds:Reference Id="xmldsig-3fde635a-ad2d-4667-84f5-5f4207e64319-ref0" URI="">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>v3gLXFVP20p3X5RTkooSR2z/9jmFi4R6YbPQlKHLRwo=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference Id="xmldsig-3fde635a-ad2d-4667-84f5-5f4207e64319-ref1" URI="#xmldsig-3fde635a-ad2d-4667-84f5-5f4207e64319-KeyInfo">
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>4vxQuFc85SS7cssuTdGgdTC/9qxq5XFRvGMQDp+1xeM=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
<ds:Reference URI="#xmldsig-3fde635a-ad2d-4667-84f5-5f4207e64319-signedprops" Type="http://uri.etsi.org/01903#SignedProperties">
|
||||||
|
<ds:Transforms>
|
||||||
|
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
</ds:Transforms>
|
||||||
|
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<ds:DigestValue>CRSEul95G+Fqlnj1I1vKAj4c2HRsHJgpqcsYs+JJd/4=</ds:DigestValue>
|
||||||
|
</ds:Reference>
|
||||||
|
</ds:SignedInfo>
|
||||||
|
<ds:SignatureValue>O6ZPJ5b6iosFTKFV0CBoAAJqeQ3XmI73tKILKe5OG7idjWjVDKSlwVNOpTMw3uaM
|
||||||
|
qPt95yAzEYcy6f1NiHE5I6DhwmJhrpUJ1RlJZkSm0RAH4YUIWBStue+MbZIcPZqx
|
||||||
|
7TKS3O80DIGlZGAhn7MpP1AfevHD42ubDzLeVPM8dA205ZV6htmuknBO1rhNy7Te
|
||||||
|
J4ph/bk8eJc5N2d33ImlTJv32zc1Yyg4Vg7i6BbL2ngduRlPLoaac2VEDKs7JJxp
|
||||||
|
RZJi3N9e5RLkpzK5s+5+1tvHFf19yKR+zvGfb5i8GzKK/a5WPJ2aDYAtLuvUvLum
|
||||||
|
VmU3yzMVKAIAhsU8aa+E8w==</ds:SignatureValue>
|
||||||
|
<ds:KeyInfo Id="xmldsig-3fde635a-ad2d-4667-84f5-5f4207e64319-KeyInfo">
|
||||||
|
<ds:X509Data>
|
||||||
|
<ds:X509Certificate>MIIH8TCCBdmgAwIBAgIIQxaPJd4YTlMwDQYJKoZIhvcNAQELBQAwgbYxIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMSYwJAYDVQQDEx1DQSBBTkRF
|
||||||
|
UyBTQ0QgUy5BLiBDbGFzZSBJSSB2MzEwMC4GA1UECxMnRGl2aXNpb24gZGUgY2Vy
|
||||||
|
dGlmaWNhY2lvbiBlbnRpZGFkIGZpbmFsMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDAS
|
||||||
|
BgNVBAcTC0JvZ290YSBELkMuMQswCQYDVQQGEwJDTzAeFw0yNDA1MTYwNTAwMDBa
|
||||||
|
Fw0yNTA1MTYwNDU5MDBaMIIBQDEtMCsGA1UECRMkVFYgNDYgQyA0MiBFU1RFIDc4
|
||||||
|
OSBDT1JSIFNBTlRBIEVMRU5BMSIwIAYJKoZIhvcNAQkBFhNiaWNpcGl6emFAZ21h
|
||||||
|
aWwuY29tMRowGAYDVQQDExFCSUNJIFBJWlpBIFMuQS5TLjETMBEGA1UEBRMKOTAx
|
||||||
|
NTc1NTI4MjE2MDQGA1UEDBMtRW1pc29yIEZhY3R1cmEgRWxlY3Ryb25pY2EgLSBQ
|
||||||
|
ZXJzb25hIEp1cmlkaWNhMTswOQYDVQQLEzJFbWl0aWRvIHBvciBBbmRlcyBTQ0Qg
|
||||||
|
QWMgMjYgNjkgQyAwMyBUb3JyZSBCIE9mIDcwMTEQMA4GA1UEChMHR0VSRU5URTES
|
||||||
|
MBAGA1UEBwwJTUVERUxMw41OMRIwEAYDVQQIEwlBTlRJT1FVSUExCzAJBgNVBAYT
|
||||||
|
AkNPMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5J1O+4ZedrSBUsb+
|
||||||
|
9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5/wra04OU57cS1/+/
|
||||||
|
yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/PbswnrKukFU2acxISwT
|
||||||
|
Lu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SIiqqPwHKh+6EDIoou
|
||||||
|
jo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891KBA9Yebdw7m/+ufu
|
||||||
|
+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWnspvDK97D8YG0MeifP
|
||||||
|
YveIPwIDAQABo4ICdDCCAnAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRA/iZp
|
||||||
|
RzInMtGsIcgu7M+N1TVo6DBvBggrBgEFBQcBAQRjMGEwNgYIKwYBBQUHMAKGKmh0
|
||||||
|
dHA6Ly9jZXJ0cy5hbmRlc3NjZC5jb20uY28vQ2xhc2VJSXYzLmNydDAnBggrBgEF
|
||||||
|
BQcwAYYbaHR0cDovL29jc3AuYW5kZXNzY2QuY29tLmNvMB4GA1UdEQQXMBWBE2Jp
|
||||||
|
Y2lwaXp6YUBnbWFpbC5jb20wggEjBgNVHSAEggEaMIIBFjCBwQYNKwYBBAGB9EgB
|
||||||
|
AgYIADCBrzCBrAYIKwYBBQUHAgIwgZ8MgZxMYSB1dGlsaXphY2nDs24gZGUgZXN0
|
||||||
|
ZSBjZXJ0aWZpY2FkbyBlc3TDoSBzdWpldGEgYSBsYSBQQyBkZSBGYWN0dXJhY2nD
|
||||||
|
s24gRWxlY3Ryw7NuaWNhIHkgRFBDIGVzdGFibGVjaWRhcyBwb3IgQW5kZXMgU0NE
|
||||||
|
LiBDw7NkaWdvIGRlIEFjcmVkaXRhY2nDs246IDE2LUVDRC0wMDQwUAYNKwYBBAGB
|
||||||
|
9EgBAQEKADA/MD0GCCsGAQUFBwIBFjFodHRwczovL3d3dy5hbmRlc3NjZC5jb20u
|
||||||
|
Y28vZG9jcy9EUENfQW5kZXNTQ0QucGRmMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
|
||||||
|
BgEFBQcDBDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLmFuZGVzc2NkLmNv
|
||||||
|
bS5jby9DbGFzZUlJdjMuY3JsMB0GA1UdDgQWBBRKPoh3BJM7SxEL0UXkSne2MyFO
|
||||||
|
jjAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQELBQADggIBAA6Zzor3kpJ6vNKv
|
||||||
|
TAeHaMfmJ/PaghQ1+Lab7Pwk+lsPsMETFu/IpEK5qij2bV54UNnqyLYOZtIbnWTG
|
||||||
|
qgT7QxQvy+/of/I3zzF+kH4/Lp2TSlHaDEb/airCZ3I2G23M9iaZzSwYuOsOaGwp
|
||||||
|
4ovkXlYwQ7FVNfIIoAq95m9cBAigb06bRIlVBVTQq44hQFQQG6aSIT7SSPtCwPhB
|
||||||
|
5CJzG09pmgbxizqN/yxdjWdfW6Av79dh6K4uQT++Vtyp5DuAkmfn0ehayrUbDLkH
|
||||||
|
9jQFF128U5pnOPfKWf22acXqQBapesUSV/HZUZ3PXoWeHWXcMdz0azxOEunS4+px
|
||||||
|
fs5UzInRAmEcYwJHqJT3irFz+J2RsZ0WnJHrTGqFoXniQQH8QbCHehDTGN7/v/v1
|
||||||
|
LQBr5PQBnSEWhmrQ9uFrwPyMMg3yd+L75TaHLZ0MTSVezAG52oM9jBiU5tYXkSio
|
||||||
|
EfPdIsGlG74BybULGSG2OlTINlblj/lj7pL67V+gY9EGN1zzNKL5sW4YXlXewa6K
|
||||||
|
dTpLmmzWzI8Cm+tOuuJDSHSwMjn525O+Z/oyKLjdQdyfg1KnZYwNZFpMmCwfP5nd
|
||||||
|
cm4F7Anzb9HX9ciluAxc6as9TsNoDDTSAGPuUr0QvXqXd9ZCgXdNzdFeiaYknLP5
|
||||||
|
hT4f5CoO2M8qcG+CH7HnkaOHrSuK</ds:X509Certificate>
|
||||||
|
</ds:X509Data>
|
||||||
|
<ds:KeyValue>
|
||||||
|
<ds:RSAKeyValue>
|
||||||
|
<ds:Modulus>5J1O+4ZedrSBUsb+9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5
|
||||||
|
/wra04OU57cS1/+/yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/Pbs
|
||||||
|
wnrKukFU2acxISwTLu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SI
|
||||||
|
iqqPwHKh+6EDIooujo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891
|
||||||
|
KBA9Yebdw7m/+ufu+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWns
|
||||||
|
pvDK97D8YG0MeifPYveIPw==</ds:Modulus>
|
||||||
|
<ds:Exponent>AQAB</ds:Exponent>
|
||||||
|
</ds:RSAKeyValue>
|
||||||
|
</ds:KeyValue>
|
||||||
|
</ds:KeyInfo>
|
||||||
|
<ds:Object><xades:QualifyingProperties Target="#xmlsig-3fde635a-ad2d-4667-84f5-5f4207e64319" Id="XadesObjects"><xades:SignedProperties Id="xmldsig-3fde635a-ad2d-4667-84f5-5f4207e64319-signedprops"><xades:SignedSignatureProperties><xades:SigningTime>2025-04-13T18:25:09.305178</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>YcIPspAVFcNg+B/galYrdCLYvLIEwFI4KWdSzcuupPY=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>C=CO, L=Bogota D.C., O=Andes SCD, OU=Division de certificacion entidad final, CN=CA ANDES SCD S.A. Clase II v3, OID.1.2.840.113549.1.9.1=info@andesscd.com.co</ds:X509IssuerName><ds:X509SerialNumber>4834208642831502931</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate><xades:SignaturePolicyIdentifier><xades:SignaturePolicyId><xades:SigPolicyId><xades:Identifier>https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf</xades:Identifier><xades:Description>Política de firma para facturas electrónicas de la República de Colombia.</xades:Description></xades:SigPolicyId><xades:SigPolicyHash><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>dMoMvtcG5aIzgYo0tIsSQeVJBDnUnfSOfBpxXrmor0Y=</ds:DigestValue></xades:SigPolicyHash></xades:SignaturePolicyId></xades:SignaturePolicyIdentifier><xades:SignerRole><xades:ClaimedRoles><xades:ClaimedRole>supplier</xades:ClaimedRole></xades:ClaimedRoles></xades:SignerRole></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object></ds:Signature></ext:ExtensionContent></ext:UBLExtension></ext:UBLExtensions><TipoNota>2</TipoNota><Eliminar><EliminandoPredecesor NumeroPred="A000001" CUNEPred="38e3a0863b2cc46e0746d0d97d0b305125292f24c0e478f9dd4f4a097c4403ae4e52d96d90f8b5702fc5eac8bc71004b" FechaGenPred="2025-03-23"/><Novedad CUNENov="False">false</Novedad><Periodo FechaIngreso="2022-01-05" FechaLiquidacionInicio="2024-04-01" FechaLiquidacionFin="2024-04-30" TiempoLaborado="1" FechaGen="2024-04-30"/><NumeroSecuenciaXML Prefijo="AJU" Consecutivo="00001" Numero="AJU00001"/><LugarGeneracionXML Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Idioma="es"/><ProveedorXML NIT="901575528" DV="2" SoftwareID="100b0d10-0ca0-4ad4-a894-b704a568cbf3" RazonSocial="BICI PIZZA S.A.S" SoftwareSC="181675298da86622f2c4213f75cf67f434a34169373602ddfe1cedbc86be3d5a2dd3a8b3df431d8f1f0d3477cf30a387"/><CodigoQR>https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey=19a695aad7a8fa12c4c2c4c07dbed5a5daf39ba43b333503cc23a1c7a09295ddf222c0e278762ca67a48874e9c68efc6</CodigoQR><InformacionGeneral Version="V1.0: Nota de Ajuste de Documento Soporte de Pago de Nómina Electrónica" Ambiente="2" TipoXML="103" EncripCUNE="CUNE-SHA384" FechaGen="2024-04-30" HoraGen="08:01:00-05:00" PeriodoNomina="1" TipoMoneda="COP" TRM="0" CUNE="19a695aad7a8fa12c4c2c4c07dbed5a5daf39ba43b333503cc23a1c7a09295ddf222c0e278762ca67a48874e9c68efc6"/><Empleador NIT="901575528" DV="2" Pais="CO" DepartamentoEstado="05" MunicipioCiudad="05001" Direccion="calle etrivial" RazonSocial="BICI PIZZA S.A.S"/><Trabajador TipoTrabajador="01" SubTipoTrabajador="00" AltoRiesgoPension="false" TipoDocumento="11" NumeroDocumento="901575528" PrimerApellido="GONZALEZ" SegundoApellido="" PrimerNombre="JUAN" LugarTrabajoPais="CO" LugarTrabajoDepartamentoEstado="05" LugarTrabajoMunicipioCiudad="05001" LugarTrabajoDireccion="CL 35C 102-17 BL 7 AP 101" SalarioIntegral="false" TipoContrato="1" Sueldo="2400000.0"/><Pago Forma="1" Metodo="10"/><FechasPagos/><Devengados><Basico DiasTrabajados="30" SueldoTrabajado="2400000.00"/></Devengados><Deducciones><Salud Porcentaje="4.00" Deduccion="96000.0"/><FondoPension Porcentaje="4.00" Deduccion="96000.0"/></Deducciones><Redondeo>0</Redondeo><DevengadosTotal>2400000.00</DevengadosTotal><DeduccionesTotal>192000.00</DeduccionesTotal><ComprobanteTotal>2208000.00</ComprobanteTotal></Eliminar></NominaIndividualDeAjuste>
|
||||||
BIN
scrips/AJU00001.zip
Normal file
BIN
scrips/AJU00001.zip
Normal file
Binary file not shown.
BIN
scrips/Certificado.pfx
Normal file
BIN
scrips/Certificado.pfx
Normal file
Binary file not shown.
1
scrips/nomina.csv
Normal file
1
scrips/nomina.csv
Normal file
@@ -0,0 +1 @@
|
|||||||
|
N,0000011,JUAN,GONZALEZ,CARDONA,71380802,CL 35C 102-17 BL 7 AP 101,2400000,30,96000,96000,140606,2400000,2024-04-30,2022-01-05,2024-04-01,2024-04-30,2024-04-30,08:01:00``
|
||||||
|
178
scrips/nomina.sh
Executable file
178
scrips/nomina.sh
Executable file
@@ -0,0 +1,178 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SOFTWARE_PIN='20234'
|
||||||
|
SOFTWARE_ID='100b0d10-0ca0-4ad4-a894-b704a568cbf3'
|
||||||
|
NIT='901575528'
|
||||||
|
DV='2'
|
||||||
|
TIPO_AMBIENTE='AMBIENTE_PRUEBAS'
|
||||||
|
RAZON_SOCIAL='BICI PIZZA S.A.S'
|
||||||
|
SET_PRUEBAS='be4d232c-9c7b-4542-b24d-6044c4e316ce'
|
||||||
|
PASSPHARASE='7U3XbtZ76W'
|
||||||
|
#La ruta donde se encuentren estos archivos
|
||||||
|
LLAVE_PRIVADA='privada.pem'
|
||||||
|
LLAVE_PUBLICA='publica.pem'
|
||||||
|
CERTIFICADO='Certificado.pfx'
|
||||||
|
HABILITACION='True'
|
||||||
|
ARCHIVO_CSV='./nomina.csv'
|
||||||
|
|
||||||
|
IFS=,
|
||||||
|
while read line; do
|
||||||
|
|
||||||
|
field=( $line )
|
||||||
|
|
||||||
|
Prefijo=${field[0]}
|
||||||
|
Numero=${field[1]}
|
||||||
|
Nombre=${field[2]}
|
||||||
|
P_Apellido=${field[3]}
|
||||||
|
S_Apellifo=${field[4]}
|
||||||
|
Cedula=${field[5]}
|
||||||
|
Direccion=${field[6]}
|
||||||
|
Salario=${field[7]}
|
||||||
|
Sueldo=${field[12]}
|
||||||
|
Dias=${field[8]}
|
||||||
|
Salud=${field[9]}
|
||||||
|
Pension=${field[10]}
|
||||||
|
AuxTp=${field[11]}
|
||||||
|
Pago=${field[13]}
|
||||||
|
Ingreso=${field[14]}
|
||||||
|
Inicio=${field[15]}
|
||||||
|
Fin=${field[16]}
|
||||||
|
Generacion=${field[17]}
|
||||||
|
Hora=${field[18]}
|
||||||
|
|
||||||
|
echo ${Pago}
|
||||||
|
echo "
|
||||||
|
from facho import fe
|
||||||
|
|
||||||
|
SOFTWARE_PIN='${SOFTWARE_PIN}'
|
||||||
|
SOFTWARE_ID='${SOFTWARE_ID}'
|
||||||
|
NIT='${NIT}'
|
||||||
|
DV='${DV}'
|
||||||
|
|
||||||
|
def extensions(nomina):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def nomina():
|
||||||
|
nomina = fe.nomina.DIANNominaIndividual()
|
||||||
|
|
||||||
|
nomina.asignar_fecha_pago('${Pago}')
|
||||||
|
|
||||||
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
|
novedad=fe.nomina.Novedad(value='false'),
|
||||||
|
secuencia=fe.nomina.NumeroSecuencia(
|
||||||
|
prefijo='${Prefijo}',
|
||||||
|
consecutivo='${Numero}'
|
||||||
|
),
|
||||||
|
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(
|
||||||
|
razon_social='${RAZON_SOCIAL}',
|
||||||
|
nit=NIT,
|
||||||
|
dv=DV,
|
||||||
|
software_id=SOFTWARE_ID,
|
||||||
|
software_pin=SOFTWARE_PIN
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_periodo(fe.nomina.Periodo(
|
||||||
|
fecha_ingreso= '${Ingreso}',
|
||||||
|
fecha_liquidacion_inicio='${Inicio}',
|
||||||
|
fecha_liquidacion_fin='${Fin}',
|
||||||
|
fecha_generacion='${Generacion}'
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
|
fecha_generacion = '${Generacion}',
|
||||||
|
hora_generacion = '${Hora}-05:00',
|
||||||
|
tipo_ambiente = fe.nomina.InformacionGeneral.${TIPO_AMBIENTE},
|
||||||
|
software_pin = SOFTWARE_PIN,
|
||||||
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_pago(fe.nomina.Pago(
|
||||||
|
forma=fe.nomina.FormaPago(
|
||||||
|
code='1',
|
||||||
|
),
|
||||||
|
metodo=fe.nomina.MetodoPago(
|
||||||
|
code='10'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
|
razon_social='${RAZON_SOCIAL}',
|
||||||
|
nit = NIT,
|
||||||
|
dv = DV,
|
||||||
|
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 = '${P_Apellido}',
|
||||||
|
segundo_apellido = '${S_Apellido}',
|
||||||
|
primer_nombre = '${Nombre}',
|
||||||
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
|
direccion = '${Direccion}'
|
||||||
|
),
|
||||||
|
numero_documento = NIT,
|
||||||
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
|
code = '01'
|
||||||
|
),
|
||||||
|
salario_integral = False,
|
||||||
|
sueldo = fe.nomina.Amount(${Sueldo})
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
|
dias_trabajados = ${field[8]},
|
||||||
|
sueldo_trabajado = fe.nomina.Amount(${Salario})
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
|
porcentaje = fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(${Salud})
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||||
|
porcentaje=fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(${Pension})
|
||||||
|
))
|
||||||
|
return nomina
|
||||||
|
" > "${Prefijo}${Numero}".py
|
||||||
|
facho generate-nomina --private-key ${CERTIFICADO} --passphrase ${PASSPHARASE} --use-cache-policy --sign "${field[0]}${field[1]}".py "${Prefijo}${Numero}".xml
|
||||||
|
CUNE=`grep -oP "<CodigoQR>(.*)</CodigoQR>" "${Prefijo}${Numero}".xml | sed -n 's/.*documentkey=\([^<]*\)<\/CodigoQR>.*/\1/p'`
|
||||||
|
zip "${field[0]}${field[1]}".zip "${field[0]}${field[1]}".xml
|
||||||
|
if [ "$HABILITACION" == "True" ];then
|
||||||
|
facho soap-send-test-set-async --private-key ${LLAVE_PRIVADA} --public-key ${LLAVE_PUBLICA} --habilitacion --password ${PASSPHARASE} --test-setid ${SET_PRUEBAS} "${field[0]}${field[1]}".xml "${field[0]}${field[1]}".zip
|
||||||
|
else
|
||||||
|
facho soap-send-nomina-sync --private-key ${LLAVE_PRIVADA} --public-key ${LLAVE_PUBLICA} --password ${PASSPHARASE} "${field[0]}${field[1]}".xml "${field[0]}${field[1]}".zip --produccion
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
done < ${ARCHIVO_CSV}
|
||||||
|
|
||||||
1
scrips/nomina_ajuste.csv
Normal file
1
scrips/nomina_ajuste.csv
Normal file
@@ -0,0 +1 @@
|
|||||||
|
AJU,00001,JUAN,GONZALEZ,CARDONA,71380802,CL 35C 102-17 BL 7 AP 101,2400000,30,96000,96000,140606,2400000,2024-04-30,2022-01-05,2024-04-01,2024-04-30,2024-04-30,08:01:00
|
||||||
|
182
scrips/nomina_ajuste.sh
Executable file
182
scrips/nomina_ajuste.sh
Executable file
@@ -0,0 +1,182 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SOFTWARE_PIN='20234'
|
||||||
|
SOFTWARE_ID='100b0d10-0ca0-4ad4-a894-b704a568cbf3'
|
||||||
|
NIT='901575528'
|
||||||
|
DV='2'
|
||||||
|
TIPO_AMBIENTE='AMBIENTE_PRUEBAS'
|
||||||
|
RAZON_SOCIAL='BICI PIZZA S.A.S'
|
||||||
|
SET_PRUEBAS='be4d232c-9c7b-4542-b24d-6044c4e316ce'
|
||||||
|
PASSPHARASE='7U3XbtZ76W'
|
||||||
|
#La ruta donde se encuentren estos archivos
|
||||||
|
LLAVE_PRIVADA='privada.pem'
|
||||||
|
LLAVE_PUBLICA='publica.pem'
|
||||||
|
CERTIFICADO='Certificado.pfx'
|
||||||
|
HABILITACION='True'
|
||||||
|
ARCHIVO_CSV='./nomina_ajuste.csv'
|
||||||
|
|
||||||
|
IFS=,
|
||||||
|
while read line; do
|
||||||
|
|
||||||
|
field=($line)
|
||||||
|
|
||||||
|
Prefijo=${field[0]}
|
||||||
|
Numero=${field[1]}
|
||||||
|
Nombre=${field[2]}
|
||||||
|
P_Apellido=${field[3]}
|
||||||
|
S_Apellifo=${field[4]}
|
||||||
|
Cedula=${field[5]}
|
||||||
|
Direccion=${field[6]}
|
||||||
|
Salario=${field[7]}
|
||||||
|
Sueldo=${field[12]}
|
||||||
|
Dias=${field[8]}
|
||||||
|
Salud=${field[9]}
|
||||||
|
Pension=${field[10]}
|
||||||
|
AuxTp=${field[11]}
|
||||||
|
Pago=${field[13]}
|
||||||
|
Ingreso=${field[14]}
|
||||||
|
Inicio=${field[15]}
|
||||||
|
Fin=${field[16]}
|
||||||
|
Generacion=${field[17]}
|
||||||
|
Hora=${field[18]}
|
||||||
|
|
||||||
|
echo ${Pago}
|
||||||
|
echo "
|
||||||
|
from facho import fe
|
||||||
|
|
||||||
|
SOFTWARE_PIN='${SOFTWARE_PIN}'
|
||||||
|
SOFTWARE_ID='${SOFTWARE_ID}'
|
||||||
|
NIT='${NIT}'
|
||||||
|
DV='${DV}'
|
||||||
|
|
||||||
|
def extensions(nomina):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def nomina():
|
||||||
|
nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
|
||||||
|
|
||||||
|
nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Eliminar.Predecesor(
|
||||||
|
numero='A000001',
|
||||||
|
fecha_generacion='2025-03-23',
|
||||||
|
cune = '38e3a0863b2cc46e0746d0d97d0b305125292f24c0e478f9dd4f4a097c4403ae4e52d96d90f8b5702fc5eac8bc71004b',
|
||||||
|
))
|
||||||
|
|
||||||
|
# nomina.asignar_fecha_pago('${Pago}')
|
||||||
|
|
||||||
|
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||||
|
novedad=fe.nomina.Novedad(False),
|
||||||
|
secuencia=fe.nomina.NumeroSecuencia(
|
||||||
|
prefijo='${Prefijo}',
|
||||||
|
consecutivo='${Numero}'
|
||||||
|
),
|
||||||
|
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(
|
||||||
|
razon_social='${RAZON_SOCIAL}',
|
||||||
|
nit=NIT,
|
||||||
|
dv=DV,
|
||||||
|
software_id=SOFTWARE_ID,
|
||||||
|
software_pin=SOFTWARE_PIN
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_periodo(fe.nomina.Periodo(
|
||||||
|
fecha_ingreso= '${Ingreso}',
|
||||||
|
fecha_liquidacion_inicio='${Inicio}',
|
||||||
|
fecha_liquidacion_fin='${Fin}',
|
||||||
|
fecha_generacion='${Generacion}'
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||||
|
fecha_generacion = '${Generacion}',
|
||||||
|
hora_generacion = '${Hora}-05:00',
|
||||||
|
tipo_ambiente = fe.nomina.InformacionGeneral.${TIPO_AMBIENTE},
|
||||||
|
software_pin = SOFTWARE_PIN,
|
||||||
|
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||||
|
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.asignar_pago(fe.nomina.Pago(
|
||||||
|
forma=fe.nomina.FormaPago(
|
||||||
|
code='1',
|
||||||
|
),
|
||||||
|
metodo=fe.nomina.MetodoPago(
|
||||||
|
code='10'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||||
|
razon_social='${RAZON_SOCIAL}',
|
||||||
|
nit = NIT,
|
||||||
|
dv = DV,
|
||||||
|
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 = '${P_Apellido}',
|
||||||
|
segundo_apellido = '${S_Apellido}',
|
||||||
|
primer_nombre = '${Nombre}',
|
||||||
|
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||||
|
pais = fe.nomina.Pais(code='CO'),
|
||||||
|
departamento = fe.nomina.Departamento(code='05'),
|
||||||
|
municipio = fe.nomina.Municipio(code='05001'),
|
||||||
|
direccion = '${Direccion}'
|
||||||
|
),
|
||||||
|
numero_documento = NIT,
|
||||||
|
tipo = fe.nomina.TipoTrabajador(
|
||||||
|
code = '01'
|
||||||
|
),
|
||||||
|
salario_integral = False,
|
||||||
|
sueldo = fe.nomina.Amount(${Sueldo})
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||||
|
dias_trabajados = ${field[8]},
|
||||||
|
sueldo_trabajado = fe.nomina.Amount(${Salario})
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||||
|
porcentaje = fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(${Salud})
|
||||||
|
))
|
||||||
|
|
||||||
|
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||||
|
porcentaje=fe.nomina.Amount(4),
|
||||||
|
deduccion = fe.nomina.Amount(${Pension})
|
||||||
|
))
|
||||||
|
return nomina
|
||||||
|
" >"${Prefijo}${Numero}".py
|
||||||
|
facho generate-nomina --private-key ${CERTIFICADO} --passphrase ${PASSPHARASE} --use-cache-policy --sign "${field[0]}${field[1]}".py "${Prefijo}${Numero}".xml
|
||||||
|
CUNE=$(grep -oP "<CodigoQR>(.*)</CodigoQR>" "${Prefijo}${Numero}".xml | sed -n 's/.*documentkey=\([^<]*\)<\/CodigoQR>.*/\1/p')
|
||||||
|
zip "${field[0]}${field[1]}".zip "${field[0]}${field[1]}".xml
|
||||||
|
if [ "$HABILITACION" == "True" ]; then
|
||||||
|
facho soap-send-test-set-async --private-key ${LLAVE_PRIVADA} --public-key ${LLAVE_PUBLICA} --habilitacion --password ${PASSPHARASE} --test-setid ${SET_PRUEBAS} "${field[0]}${field[1]}".xml "${field[0]}${field[1]}".zip
|
||||||
|
else
|
||||||
|
facho soap-send-nomina-sync --private-key ${LLAVE_PRIVADA} --public-key ${LLAVE_PUBLICA} --password ${PASSPHARASE} "${field[0]}${field[1]}".xml "${field[0]}${field[1]}".zip --produccion
|
||||||
|
fi
|
||||||
|
|
||||||
|
done <${ARCHIVO_CSV}
|
||||||
169
scrips/privada.pem
Normal file
169
scrips/privada.pem
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
Bag Attributes
|
||||||
|
localKeyID: 47 1D 7A 81 07 9A 0F 92 5D D8 E8 FD 6D 22 D2 A6 D9 20 23 40
|
||||||
|
friendlyName: BICI PIZZA S.A.S.
|
||||||
|
subject=street = TV 46 C 42 ESTE 789 CORR SANTA ELENA, emailAddress = bicipizza@gmail.com, CN = BICI PIZZA S.A.S., serialNumber = 9015755282, title = Emisor Factura Electronica - Persona Juridica, OU = Emitido por Andes SCD Ac 26 69 C 03 Torre B Of 701, O = GERENTE, L = MEDELL\C3\8DN, ST = ANTIOQUIA, C = CO
|
||||||
|
|
||||||
|
issuer=emailAddress = info@andesscd.com.co, CN = CA ANDES SCD S.A. Clase II v3, OU = Division de certificacion entidad final, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIH8TCCBdmgAwIBAgIIQxaPJd4YTlMwDQYJKoZIhvcNAQELBQAwgbYxIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMSYwJAYDVQQDEx1DQSBBTkRF
|
||||||
|
UyBTQ0QgUy5BLiBDbGFzZSBJSSB2MzEwMC4GA1UECxMnRGl2aXNpb24gZGUgY2Vy
|
||||||
|
dGlmaWNhY2lvbiBlbnRpZGFkIGZpbmFsMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDAS
|
||||||
|
BgNVBAcTC0JvZ290YSBELkMuMQswCQYDVQQGEwJDTzAeFw0yNDA1MTYwNTAwMDBa
|
||||||
|
Fw0yNTA1MTYwNDU5MDBaMIIBQDEtMCsGA1UECRMkVFYgNDYgQyA0MiBFU1RFIDc4
|
||||||
|
OSBDT1JSIFNBTlRBIEVMRU5BMSIwIAYJKoZIhvcNAQkBFhNiaWNpcGl6emFAZ21h
|
||||||
|
aWwuY29tMRowGAYDVQQDExFCSUNJIFBJWlpBIFMuQS5TLjETMBEGA1UEBRMKOTAx
|
||||||
|
NTc1NTI4MjE2MDQGA1UEDBMtRW1pc29yIEZhY3R1cmEgRWxlY3Ryb25pY2EgLSBQ
|
||||||
|
ZXJzb25hIEp1cmlkaWNhMTswOQYDVQQLEzJFbWl0aWRvIHBvciBBbmRlcyBTQ0Qg
|
||||||
|
QWMgMjYgNjkgQyAwMyBUb3JyZSBCIE9mIDcwMTEQMA4GA1UEChMHR0VSRU5URTES
|
||||||
|
MBAGA1UEBwwJTUVERUxMw41OMRIwEAYDVQQIEwlBTlRJT1FVSUExCzAJBgNVBAYT
|
||||||
|
AkNPMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5J1O+4ZedrSBUsb+
|
||||||
|
9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5/wra04OU57cS1/+/
|
||||||
|
yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/PbswnrKukFU2acxISwT
|
||||||
|
Lu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SIiqqPwHKh+6EDIoou
|
||||||
|
jo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891KBA9Yebdw7m/+ufu
|
||||||
|
+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWnspvDK97D8YG0MeifP
|
||||||
|
YveIPwIDAQABo4ICdDCCAnAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRA/iZp
|
||||||
|
RzInMtGsIcgu7M+N1TVo6DBvBggrBgEFBQcBAQRjMGEwNgYIKwYBBQUHMAKGKmh0
|
||||||
|
dHA6Ly9jZXJ0cy5hbmRlc3NjZC5jb20uY28vQ2xhc2VJSXYzLmNydDAnBggrBgEF
|
||||||
|
BQcwAYYbaHR0cDovL29jc3AuYW5kZXNzY2QuY29tLmNvMB4GA1UdEQQXMBWBE2Jp
|
||||||
|
Y2lwaXp6YUBnbWFpbC5jb20wggEjBgNVHSAEggEaMIIBFjCBwQYNKwYBBAGB9EgB
|
||||||
|
AgYIADCBrzCBrAYIKwYBBQUHAgIwgZ8MgZxMYSB1dGlsaXphY2nDs24gZGUgZXN0
|
||||||
|
ZSBjZXJ0aWZpY2FkbyBlc3TDoSBzdWpldGEgYSBsYSBQQyBkZSBGYWN0dXJhY2nD
|
||||||
|
s24gRWxlY3Ryw7NuaWNhIHkgRFBDIGVzdGFibGVjaWRhcyBwb3IgQW5kZXMgU0NE
|
||||||
|
LiBDw7NkaWdvIGRlIEFjcmVkaXRhY2nDs246IDE2LUVDRC0wMDQwUAYNKwYBBAGB
|
||||||
|
9EgBAQEKADA/MD0GCCsGAQUFBwIBFjFodHRwczovL3d3dy5hbmRlc3NjZC5jb20u
|
||||||
|
Y28vZG9jcy9EUENfQW5kZXNTQ0QucGRmMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
|
||||||
|
BgEFBQcDBDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLmFuZGVzc2NkLmNv
|
||||||
|
bS5jby9DbGFzZUlJdjMuY3JsMB0GA1UdDgQWBBRKPoh3BJM7SxEL0UXkSne2MyFO
|
||||||
|
jjAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQELBQADggIBAA6Zzor3kpJ6vNKv
|
||||||
|
TAeHaMfmJ/PaghQ1+Lab7Pwk+lsPsMETFu/IpEK5qij2bV54UNnqyLYOZtIbnWTG
|
||||||
|
qgT7QxQvy+/of/I3zzF+kH4/Lp2TSlHaDEb/airCZ3I2G23M9iaZzSwYuOsOaGwp
|
||||||
|
4ovkXlYwQ7FVNfIIoAq95m9cBAigb06bRIlVBVTQq44hQFQQG6aSIT7SSPtCwPhB
|
||||||
|
5CJzG09pmgbxizqN/yxdjWdfW6Av79dh6K4uQT++Vtyp5DuAkmfn0ehayrUbDLkH
|
||||||
|
9jQFF128U5pnOPfKWf22acXqQBapesUSV/HZUZ3PXoWeHWXcMdz0azxOEunS4+px
|
||||||
|
fs5UzInRAmEcYwJHqJT3irFz+J2RsZ0WnJHrTGqFoXniQQH8QbCHehDTGN7/v/v1
|
||||||
|
LQBr5PQBnSEWhmrQ9uFrwPyMMg3yd+L75TaHLZ0MTSVezAG52oM9jBiU5tYXkSio
|
||||||
|
EfPdIsGlG74BybULGSG2OlTINlblj/lj7pL67V+gY9EGN1zzNKL5sW4YXlXewa6K
|
||||||
|
dTpLmmzWzI8Cm+tOuuJDSHSwMjn525O+Z/oyKLjdQdyfg1KnZYwNZFpMmCwfP5nd
|
||||||
|
cm4F7Anzb9HX9ciluAxc6as9TsNoDDTSAGPuUr0QvXqXd9ZCgXdNzdFeiaYknLP5
|
||||||
|
hT4f5CoO2M8qcG+CH7HnkaOHrSuK
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
Bag Attributes: <No Attributes>
|
||||||
|
subject=emailAddress = info@andesscd.com.co, CN = ROOT CA ANDES SCD S.A., OU = Division de certificacion, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
issuer=emailAddress = info@andesscd.com.co, CN = ROOT CA ANDES SCD S.A., OU = Division de certificacion, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGKTCCBBGgAwIBAgIILDECIDXRkbIwDQYJKoZIhvcNAQELBQAwgaExIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMR8wHQYDVQQDExZST09UIENB
|
||||||
|
IEFOREVTIFNDRCBTLkEuMSIwIAYDVQQLExlEaXZpc2lvbiBkZSBjZXJ0aWZpY2Fj
|
||||||
|
aW9uMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDASBgNVBAcTC0JvZ290YSBELkMuMQsw
|
||||||
|
CQYDVQQGEwJDTzAeFw0xNjA5MjQxNjUwNTdaFw0zNTA3MDkxNjM2NTlaMIGhMSMw
|
||||||
|
IQYJKoZIhvcNAQkBFhRpbmZvQGFuZGVzc2NkLmNvbS5jbzEfMB0GA1UEAxMWUk9P
|
||||||
|
VCBDQSBBTkRFUyBTQ0QgUy5BLjEiMCAGA1UECxMZRGl2aXNpb24gZGUgY2VydGlm
|
||||||
|
aWNhY2lvbjESMBAGA1UEChMJQW5kZXMgU0NEMRQwEgYDVQQHEwtCb2dvdGEgRC5D
|
||||||
|
LjELMAkGA1UEBhMCQ08wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCc
|
||||||
|
svKA1BIq5MzsIQtZsf8QfaI6uzllLZCdnw1jczyTTE+xlygz9+Bv5ynFiWnZThLF
|
||||||
|
LMC3DSMVhAPBSYQ3qierOF/U7QE84NM0bHCKVK33MiA6ruu5804HsdVJuLqP6YCb
|
||||||
|
S+nH1Ygnw0q2fX/H094wBWb2Jr2oVe+ydDDjy1RYjZHXiZVekwZTb6oY+f2rE25w
|
||||||
|
nTNj1/3B4JfYPBbIDz6aRXPyeSBtI/RVKZBjD4NBXd4mCdXCE6/puOdvAbBWMhq7
|
||||||
|
9wLCQIgtU21nne6/YaEHISah2S5KTC4P1nS+1nHvxMxdC1cszv7mheP4/nszfAgU
|
||||||
|
LEeI6eL+lvBy+vjssT8dv+utofmj76QQdn2MkTb1paZaan4+3a+c1PsjTO7yZ86k
|
||||||
|
KDQDxfnYaGF9b7wOgIDvacqJlREpmlvT2DN+4YAp2RLnuK1+ws6dnS+e1t73qbnZ
|
||||||
|
Q7lntelAjFtKms3YIpXfs5sWUlPza1ozxEpmkSM4ZeuPKI6WF7YJuEo5s11Cu+Rw
|
||||||
|
CtBOIVjYZWMUipxwfZcT5L3vZYWPSkboDlWZGZFX4mu2srzfv2ac4Ij5M8/hTD/n
|
||||||
|
5WT2WzWcLId0xJuY9dZT/6XIrNZ6ZEFweEXxM7zHp3SrMfNSJZdG22d28gTmSyVg
|
||||||
|
FPCVop+bdW7fMo6rmCdfveih5LkBRbxE6SPUnztVcwIDAQABo2MwYTAdBgNVHQ4E
|
||||||
|
FgQU3RGSWqlsBAz+NKJYv+sd+98IsG8wDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME
|
||||||
|
GDAWgBTdEZJaqWwEDP40oli/6x373wiwbzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI
|
||||||
|
hvcNAQELBQADggIBAFpZLihgW/5L2ZpIoh3Jo+W281od5UoIMmnJ7zjnBsEj37d5
|
||||||
|
iIaQjBNKMQdiEfOHkHxb5TaBnil6nnlt5KyS+H+fmMThIKYOrmkS1kCtGF8Yn3JC
|
||||||
|
qLWuA3Nhq+3xerbhrrZrjKhdX/b+GWWBzRgeqguvAMnRDk87oWRWYFjFKt0u2pdT
|
||||||
|
DYzqORiAKgy06h7NTpfLfN5O5/BHpfoz7nLVrVDLFzZJH16HPBdvbcX7p2MjW+fl
|
||||||
|
WAO47E8CYEbK4wOJfK8L2s6lN3Zruq3RL/a9HSPGoI/Ftuu8YFDsU61k+JCWtFWX
|
||||||
|
lwO+MjkIOIygabsWqUAY9R4DVnCx2soXXN2vPUakHiBWC1V/s3xv2M7EgoyQfST7
|
||||||
|
fFoZdFt7r8v8lUljhjTPPrP8sCJ1FIn4w23hr5NjqQo8T1wo89nlupPFZ8aHqBVU
|
||||||
|
HsyQVQbuDsD4eEO0I37wBqd3fn7UWfZDec73kS8P0PMHMH8pCorHKkpeJtLDw2QP
|
||||||
|
FgYicFZ8u6fYjOYNikmQQe9c8FRJgwSYMeXQb0hf1dlC/WpJGO00Efwor99lS2cl
|
||||||
|
DegHOF5dv3wl7b+xvdzhUs3yqYiq9Qa/+N7oIPkgzhlltDabPRhIFLnJsmxfa/Kt
|
||||||
|
lF/MZ1Va+UjR+JQ1unNE/CTn6L5A4cavpOoI72N2elJRw+QP8icwGLApBp/W
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
Bag Attributes: <No Attributes>
|
||||||
|
subject=emailAddress = info@andesscd.com.co, CN = CA ANDES SCD S.A. Clase II v2, OU = Division de certificacion entidad final, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
issuer=emailAddress = info@andesscd.com.co, CN = ROOT CA ANDES SCD S.A., OU = Division de certificacion, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGrzCCBJegAwIBAgIIRLa0wz3hC2gwDQYJKoZIhvcNAQELBQAwgaExIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMR8wHQYDVQQDExZST09UIENB
|
||||||
|
IEFOREVTIFNDRCBTLkEuMSIwIAYDVQQLExlEaXZpc2lvbiBkZSBjZXJ0aWZpY2Fj
|
||||||
|
aW9uMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDASBgNVBAcTC0JvZ290YSBELkMuMQsw
|
||||||
|
CQYDVQQGEwJDTzAeFw0xOTA4MDYxNjE0NTNaFw0yNTExMTUxNzM0MzBaMIG2MSMw
|
||||||
|
IQYJKoZIhvcNAQkBFhRpbmZvQGFuZGVzc2NkLmNvbS5jbzEmMCQGA1UEAxMdQ0Eg
|
||||||
|
QU5ERVMgU0NEIFMuQS4gQ2xhc2UgSUkgdjIxMDAuBgNVBAsTJ0RpdmlzaW9uIGRl
|
||||||
|
IGNlcnRpZmljYWNpb24gZW50aWRhZCBmaW5hbDESMBAGA1UEChMJQW5kZXMgU0NE
|
||||||
|
MRQwEgYDVQQHEwtCb2dvdGEgRC5DLjELMAkGA1UEBhMCQ08wggIiMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4ICDwAwggIKAoICAQDOWKOiAg0IgACNXNyDCoAyaXo514UwF9oCqMjg
|
||||||
|
xAOhOe+g3lUDWTXtV6l8O1VXHQa86KZwqgT0mfw0HqePQYKC93n9+timuuT1FuAJ
|
||||||
|
Z9TnF/f6DQDzFQWsRVLdqV/hzNQ/rbOvPX8WN4Z97TyJaUtlxbENOKgOlzsW8hGe
|
||||||
|
eVrjDz9fk1e0TPem/CswuY+7Z/Pi4/EVz28UoTlfEMOg84ZutTomHOskIp6S86lw
|
||||||
|
X+ts15yChEf/dXBVkAMkBUpFc39iZWhhtewZo56Q8u9an5ZBQtOorB33LKFKn2P1
|
||||||
|
V95Cf2XPZqWqLrP1wRQn0XWB1uDF+eAyQzShGA0jrZGgdlaFW8J7bx8+YntJHqFi
|
||||||
|
jI3UVwqCyb+TGO9RRcTRp3OfAwAKCbh56gHacvF5KEGj36d0zofw808WBpnhrnvQ
|
||||||
|
ofPp48mowpbByzuIqVtX0utVXgzg4QdNBSQ6uhDnjB8ETzwuJcUokC1lXwBMSDa0
|
||||||
|
f5psC1yflyqdTOpSjZC8pMxwGUXhhvkfxDBaSsueExLpcKlolVojQRWm6C2oiumS
|
||||||
|
2lgeL4ydh8DFhi2llMLVCLZQLffG9ziTZtMd97n55NvXrVa4XbDIf4i5/XFrYgFy
|
||||||
|
R/rBZduYWDqxcwFnUP6HhTfuael8qNxKA3UWmxFK3ixNN5kaC/ErX3g4fC+KGqh4
|
||||||
|
LeljKQIDAQABo4HTMIHQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU3RGS
|
||||||
|
WqlsBAz+NKJYv+sd+98IsG8wNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhto
|
||||||
|
dHRwOi8vb2NzcC5hbmRlc3NjZC5jb20uY28wNAYDVR0fBC0wKzApoCegJYYjaHR0
|
||||||
|
cDovL2NybC5hbmRlc3NjZC5jb20uY28vUmFpei5jcmwwHQYDVR0OBBYEFDpXUNB3
|
||||||
|
Gz7Wi+r/l5nX/4QCSCkPMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC
|
||||||
|
AgEALA0nz8TvtoMZ70MBN7FFWZMqTXvkXY7mcnWImpTFLGzny+i119qODuItEf5G
|
||||||
|
977TzoTCxZC8DlPL1d88+YxAfYFRLXdb1HcDrNuWKMyoiFGH3vhNl+Ef//4zed98
|
||||||
|
DV5jtoaCofFt/JzPz2iA7Al2LZ1m0vAF0z12LAytHqSfob+5mdgWkBnLae0vaWU+
|
||||||
|
eGnoTkCYsasxca9oSKHDajqTvTa5WogibUaffcnb9LYaP3nkam9+favCyHHQW2lp
|
||||||
|
2xPPcP1gisvp99ga9Cwft7d/QHXNjseop2TwDoUHViUImaSpLz+2kWhkr2LOSTpL
|
||||||
|
43rWQhVQ/Y6SyYd3YWEBxJWwFvVlHvQ2wKwiE/z7kHnCP9ztPhS0umC1BMGq3pC4
|
||||||
|
fifzvx9218JjDIOVrKzwonCTj0vwQZ4FmTttAr0G+R5TrqqvgF1t/RTfhWIxhUTk
|
||||||
|
TR3xRpR/5mBtqrSmyojGtdVkwHq2dmmDIkjefSbxKDkkAkhDRt5CDeV913B3MvYm
|
||||||
|
UiMoOJmLyapIZjIko1HxzXBv3dPc5LYSKpG8rd9SjJtA7W8LQzAVUq8O32nO7edY
|
||||||
|
IvTrC11fLkdToGOxLmfTzZ+facUESteELfxchZoda6I9qH5Xa7Xka2M2mmkj0SGU
|
||||||
|
46KREw+DtpoUkpAQ7rLaZ+4stT0j1Z8soirB+EUk8oBLiTI=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
Bag Attributes
|
||||||
|
localKeyID: 47 1D 7A 81 07 9A 0F 92 5D D8 E8 FD 6D 22 D2 A6 D9 20 23 40
|
||||||
|
friendlyName: BICI PIZZA S.A.S.
|
||||||
|
Key Attributes: <No Attributes>
|
||||||
|
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIZXaHIVVK8xgCAggA
|
||||||
|
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECDiCo/ndioOzBIIEyOaIf6RezHh0
|
||||||
|
6knOjiQyjWvc12TOqcPORR5yFaddeAZ5aoaHLfozNzhafH08QSsxAN2PW9aJI38u
|
||||||
|
rejfKXiOx9X98zFs5LVvbcNYaSlJBT7nCTvIJSRUO/p3lkDXUnW3+jbO2uT2UOgk
|
||||||
|
exV198RS1fZjat1VyIf/3DTCHYJKLvC2D46F6NgsdadEkDSyrLvqcCW3HAbE3zw/
|
||||||
|
SmYmxGyEQVJWfgjTuzja07AFjWspls1rGXO9gdxcLXXHcDDfArkUPe9OTmeKMoXM
|
||||||
|
gtMuAAMJaQ3xpw3M7FaLHB0F0zXec5UhYTgs7n0jw/D2jTORqHqvAcZGRGuGnGwZ
|
||||||
|
QtuzISqBMqDEtdkVoobz0QURJP1QVj4X14xcQnaVbXCJq5uUdPlTkBvjHS11/tqX
|
||||||
|
X31wk2DmkGSsEtdLfeVupsWjd7C83IWEhZfj86lh0oxZORdR8n+JHyOI3bIFJqK0
|
||||||
|
z5tv8HN7RfBZI09wr8YNYU45IfVgOBy3PDbeQ50eAVJg1T8pbQQHwUZ+0e1MXSiI
|
||||||
|
iiAU/j0VQYsSMFVZizNozfMAJ5kjV5Pb+BqhrPb10h1o/H4O+46kVJYUXakeVdMk
|
||||||
|
mLUDBvWG3rwqXvwan9k+Zeld9/frDoa9BjEi7QhgkuyaduzT8yXIai3oOoniX5FH
|
||||||
|
kDL6NAp0oBoVu4jLOvsGvYX69qc6AiMTaJgYxE9Nvv/hjhE3zuyEvGcXfDhH9yhp
|
||||||
|
BpQMXH9S18l/WBWb7ebzp+qFPfxQ/BzFEVGEJrWZMbwZZsGYs/t8Ug9Q2dZjPweS
|
||||||
|
42UWQU5qSabwT/A+NGtdNvPUbNnG/hpZr5Rt89JTUnqxQSTvqydvx3sijNniIOdu
|
||||||
|
nHrCT51yHXUIXgD3DsxBoXF2pPCotRALdxfVpA0f2Vcs4ihEKRqEfZ+EGrHarRgJ
|
||||||
|
u11LpS312Un2Ua8jifli2YkAGZiWxQ2VraoNdZiTRcUktFEjWaI73uXeoPhXNvTO
|
||||||
|
PnD5sjZgYwTFfd90zvhN+8oPs8csFUV1UjLE+WZOm0qtNUJWOncBca1ceonWNiCq
|
||||||
|
0HNZF9nnn+qCIoNQ+7MHDBWRAh7h68Tsp22M3FqbayLmsDQWIaruN3Kw7VzDFubk
|
||||||
|
d9seJxsOos58kbq5x9MXnbY630+1qjvDZaUP/SWyytJJrI0g24h8EC59RfiYXeGR
|
||||||
|
Mv2M4YIVZUqH0bivzDwumzb8MR7vFQGHFU0bbQZtouvulWc/naHF1eX5a3jrkqeI
|
||||||
|
WJ0Ms8wlqxtYONJWzo90E26Z10PH62QbYM+4Lu6lgFVC6Idzsy19GkksrQNfghE7
|
||||||
|
XdDQb8BeS1Uer8qbt8IXSaS9X8jSTx29ccOE/ZFU8F0ZnxOR3s3hL+QMePictzyO
|
||||||
|
KVPOx7mUPrIbFg7NTMqRssmeYS4RXRShdR45cGtfrqHyrVsaO3x02ukB5LHNHfvV
|
||||||
|
3Dkrem7xf+m/T74GONuZJ5jNXsFz2rSY7PCxFTpPgHTPb56Kdmb+jaBj5vxfUjgA
|
||||||
|
ObioPS4HMPt/OKTREHpHbGFhlPD/RXDzh8K6dLPUbyMRZMUKIoDb2Mp8JYhOv0yO
|
||||||
|
oKVE7E/nYU6OtUGbS/qkuirpUeVmpvadTSuIaPA2KZYZJhKj0y0u5AO61k8ZLGKb
|
||||||
|
HPL9j6aYYJSt6dWdlY0Y6A==
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
135
scrips/publica.pem
Normal file
135
scrips/publica.pem
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
Bag Attributes
|
||||||
|
localKeyID: 47 1D 7A 81 07 9A 0F 92 5D D8 E8 FD 6D 22 D2 A6 D9 20 23 40
|
||||||
|
friendlyName: BICI PIZZA S.A.S.
|
||||||
|
subject=street = TV 46 C 42 ESTE 789 CORR SANTA ELENA, emailAddress = bicipizza@gmail.com, CN = BICI PIZZA S.A.S., serialNumber = 9015755282, title = Emisor Factura Electronica - Persona Juridica, OU = Emitido por Andes SCD Ac 26 69 C 03 Torre B Of 701, O = GERENTE, L = MEDELL\C3\8DN, ST = ANTIOQUIA, C = CO
|
||||||
|
|
||||||
|
issuer=emailAddress = info@andesscd.com.co, CN = CA ANDES SCD S.A. Clase II v3, OU = Division de certificacion entidad final, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIH8TCCBdmgAwIBAgIIQxaPJd4YTlMwDQYJKoZIhvcNAQELBQAwgbYxIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMSYwJAYDVQQDEx1DQSBBTkRF
|
||||||
|
UyBTQ0QgUy5BLiBDbGFzZSBJSSB2MzEwMC4GA1UECxMnRGl2aXNpb24gZGUgY2Vy
|
||||||
|
dGlmaWNhY2lvbiBlbnRpZGFkIGZpbmFsMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDAS
|
||||||
|
BgNVBAcTC0JvZ290YSBELkMuMQswCQYDVQQGEwJDTzAeFw0yNDA1MTYwNTAwMDBa
|
||||||
|
Fw0yNTA1MTYwNDU5MDBaMIIBQDEtMCsGA1UECRMkVFYgNDYgQyA0MiBFU1RFIDc4
|
||||||
|
OSBDT1JSIFNBTlRBIEVMRU5BMSIwIAYJKoZIhvcNAQkBFhNiaWNpcGl6emFAZ21h
|
||||||
|
aWwuY29tMRowGAYDVQQDExFCSUNJIFBJWlpBIFMuQS5TLjETMBEGA1UEBRMKOTAx
|
||||||
|
NTc1NTI4MjE2MDQGA1UEDBMtRW1pc29yIEZhY3R1cmEgRWxlY3Ryb25pY2EgLSBQ
|
||||||
|
ZXJzb25hIEp1cmlkaWNhMTswOQYDVQQLEzJFbWl0aWRvIHBvciBBbmRlcyBTQ0Qg
|
||||||
|
QWMgMjYgNjkgQyAwMyBUb3JyZSBCIE9mIDcwMTEQMA4GA1UEChMHR0VSRU5URTES
|
||||||
|
MBAGA1UEBwwJTUVERUxMw41OMRIwEAYDVQQIEwlBTlRJT1FVSUExCzAJBgNVBAYT
|
||||||
|
AkNPMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5J1O+4ZedrSBUsb+
|
||||||
|
9tjNPHI9RGeIJcJl3Wc/208OqMYcCwGLUkrYBgH78E7IayD5/wra04OU57cS1/+/
|
||||||
|
yBUWYR60oqkaH2/8OXkJMqmjisVM/b58m7zyMw4TAF8N/PbswnrKukFU2acxISwT
|
||||||
|
Lu36HC4hshWw8bEGP54szvv1xnwqcOAWNBCxcBuc9k1JD+SIiqqPwHKh+6EDIoou
|
||||||
|
jo0H15w3rAxkHQRvYe6/IrpvH2sqJl1I3dLv0iqy9+d2l891KBA9Yebdw7m/+ufu
|
||||||
|
+eqs+0zKrwV6QLhRFmceHzEkPMTFepc2COGf80OUNbI6WWnspvDK97D8YG0MeifP
|
||||||
|
YveIPwIDAQABo4ICdDCCAnAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRA/iZp
|
||||||
|
RzInMtGsIcgu7M+N1TVo6DBvBggrBgEFBQcBAQRjMGEwNgYIKwYBBQUHMAKGKmh0
|
||||||
|
dHA6Ly9jZXJ0cy5hbmRlc3NjZC5jb20uY28vQ2xhc2VJSXYzLmNydDAnBggrBgEF
|
||||||
|
BQcwAYYbaHR0cDovL29jc3AuYW5kZXNzY2QuY29tLmNvMB4GA1UdEQQXMBWBE2Jp
|
||||||
|
Y2lwaXp6YUBnbWFpbC5jb20wggEjBgNVHSAEggEaMIIBFjCBwQYNKwYBBAGB9EgB
|
||||||
|
AgYIADCBrzCBrAYIKwYBBQUHAgIwgZ8MgZxMYSB1dGlsaXphY2nDs24gZGUgZXN0
|
||||||
|
ZSBjZXJ0aWZpY2FkbyBlc3TDoSBzdWpldGEgYSBsYSBQQyBkZSBGYWN0dXJhY2nD
|
||||||
|
s24gRWxlY3Ryw7NuaWNhIHkgRFBDIGVzdGFibGVjaWRhcyBwb3IgQW5kZXMgU0NE
|
||||||
|
LiBDw7NkaWdvIGRlIEFjcmVkaXRhY2nDs246IDE2LUVDRC0wMDQwUAYNKwYBBAGB
|
||||||
|
9EgBAQEKADA/MD0GCCsGAQUFBwIBFjFodHRwczovL3d3dy5hbmRlc3NjZC5jb20u
|
||||||
|
Y28vZG9jcy9EUENfQW5kZXNTQ0QucGRmMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
|
||||||
|
BgEFBQcDBDA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vY3JsLmFuZGVzc2NkLmNv
|
||||||
|
bS5jby9DbGFzZUlJdjMuY3JsMB0GA1UdDgQWBBRKPoh3BJM7SxEL0UXkSne2MyFO
|
||||||
|
jjAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQELBQADggIBAA6Zzor3kpJ6vNKv
|
||||||
|
TAeHaMfmJ/PaghQ1+Lab7Pwk+lsPsMETFu/IpEK5qij2bV54UNnqyLYOZtIbnWTG
|
||||||
|
qgT7QxQvy+/of/I3zzF+kH4/Lp2TSlHaDEb/airCZ3I2G23M9iaZzSwYuOsOaGwp
|
||||||
|
4ovkXlYwQ7FVNfIIoAq95m9cBAigb06bRIlVBVTQq44hQFQQG6aSIT7SSPtCwPhB
|
||||||
|
5CJzG09pmgbxizqN/yxdjWdfW6Av79dh6K4uQT++Vtyp5DuAkmfn0ehayrUbDLkH
|
||||||
|
9jQFF128U5pnOPfKWf22acXqQBapesUSV/HZUZ3PXoWeHWXcMdz0azxOEunS4+px
|
||||||
|
fs5UzInRAmEcYwJHqJT3irFz+J2RsZ0WnJHrTGqFoXniQQH8QbCHehDTGN7/v/v1
|
||||||
|
LQBr5PQBnSEWhmrQ9uFrwPyMMg3yd+L75TaHLZ0MTSVezAG52oM9jBiU5tYXkSio
|
||||||
|
EfPdIsGlG74BybULGSG2OlTINlblj/lj7pL67V+gY9EGN1zzNKL5sW4YXlXewa6K
|
||||||
|
dTpLmmzWzI8Cm+tOuuJDSHSwMjn525O+Z/oyKLjdQdyfg1KnZYwNZFpMmCwfP5nd
|
||||||
|
cm4F7Anzb9HX9ciluAxc6as9TsNoDDTSAGPuUr0QvXqXd9ZCgXdNzdFeiaYknLP5
|
||||||
|
hT4f5CoO2M8qcG+CH7HnkaOHrSuK
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
Bag Attributes: <No Attributes>
|
||||||
|
subject=emailAddress = info@andesscd.com.co, CN = ROOT CA ANDES SCD S.A., OU = Division de certificacion, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
issuer=emailAddress = info@andesscd.com.co, CN = ROOT CA ANDES SCD S.A., OU = Division de certificacion, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGKTCCBBGgAwIBAgIILDECIDXRkbIwDQYJKoZIhvcNAQELBQAwgaExIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMR8wHQYDVQQDExZST09UIENB
|
||||||
|
IEFOREVTIFNDRCBTLkEuMSIwIAYDVQQLExlEaXZpc2lvbiBkZSBjZXJ0aWZpY2Fj
|
||||||
|
aW9uMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDASBgNVBAcTC0JvZ290YSBELkMuMQsw
|
||||||
|
CQYDVQQGEwJDTzAeFw0xNjA5MjQxNjUwNTdaFw0zNTA3MDkxNjM2NTlaMIGhMSMw
|
||||||
|
IQYJKoZIhvcNAQkBFhRpbmZvQGFuZGVzc2NkLmNvbS5jbzEfMB0GA1UEAxMWUk9P
|
||||||
|
VCBDQSBBTkRFUyBTQ0QgUy5BLjEiMCAGA1UECxMZRGl2aXNpb24gZGUgY2VydGlm
|
||||||
|
aWNhY2lvbjESMBAGA1UEChMJQW5kZXMgU0NEMRQwEgYDVQQHEwtCb2dvdGEgRC5D
|
||||||
|
LjELMAkGA1UEBhMCQ08wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCc
|
||||||
|
svKA1BIq5MzsIQtZsf8QfaI6uzllLZCdnw1jczyTTE+xlygz9+Bv5ynFiWnZThLF
|
||||||
|
LMC3DSMVhAPBSYQ3qierOF/U7QE84NM0bHCKVK33MiA6ruu5804HsdVJuLqP6YCb
|
||||||
|
S+nH1Ygnw0q2fX/H094wBWb2Jr2oVe+ydDDjy1RYjZHXiZVekwZTb6oY+f2rE25w
|
||||||
|
nTNj1/3B4JfYPBbIDz6aRXPyeSBtI/RVKZBjD4NBXd4mCdXCE6/puOdvAbBWMhq7
|
||||||
|
9wLCQIgtU21nne6/YaEHISah2S5KTC4P1nS+1nHvxMxdC1cszv7mheP4/nszfAgU
|
||||||
|
LEeI6eL+lvBy+vjssT8dv+utofmj76QQdn2MkTb1paZaan4+3a+c1PsjTO7yZ86k
|
||||||
|
KDQDxfnYaGF9b7wOgIDvacqJlREpmlvT2DN+4YAp2RLnuK1+ws6dnS+e1t73qbnZ
|
||||||
|
Q7lntelAjFtKms3YIpXfs5sWUlPza1ozxEpmkSM4ZeuPKI6WF7YJuEo5s11Cu+Rw
|
||||||
|
CtBOIVjYZWMUipxwfZcT5L3vZYWPSkboDlWZGZFX4mu2srzfv2ac4Ij5M8/hTD/n
|
||||||
|
5WT2WzWcLId0xJuY9dZT/6XIrNZ6ZEFweEXxM7zHp3SrMfNSJZdG22d28gTmSyVg
|
||||||
|
FPCVop+bdW7fMo6rmCdfveih5LkBRbxE6SPUnztVcwIDAQABo2MwYTAdBgNVHQ4E
|
||||||
|
FgQU3RGSWqlsBAz+NKJYv+sd+98IsG8wDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME
|
||||||
|
GDAWgBTdEZJaqWwEDP40oli/6x373wiwbzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI
|
||||||
|
hvcNAQELBQADggIBAFpZLihgW/5L2ZpIoh3Jo+W281od5UoIMmnJ7zjnBsEj37d5
|
||||||
|
iIaQjBNKMQdiEfOHkHxb5TaBnil6nnlt5KyS+H+fmMThIKYOrmkS1kCtGF8Yn3JC
|
||||||
|
qLWuA3Nhq+3xerbhrrZrjKhdX/b+GWWBzRgeqguvAMnRDk87oWRWYFjFKt0u2pdT
|
||||||
|
DYzqORiAKgy06h7NTpfLfN5O5/BHpfoz7nLVrVDLFzZJH16HPBdvbcX7p2MjW+fl
|
||||||
|
WAO47E8CYEbK4wOJfK8L2s6lN3Zruq3RL/a9HSPGoI/Ftuu8YFDsU61k+JCWtFWX
|
||||||
|
lwO+MjkIOIygabsWqUAY9R4DVnCx2soXXN2vPUakHiBWC1V/s3xv2M7EgoyQfST7
|
||||||
|
fFoZdFt7r8v8lUljhjTPPrP8sCJ1FIn4w23hr5NjqQo8T1wo89nlupPFZ8aHqBVU
|
||||||
|
HsyQVQbuDsD4eEO0I37wBqd3fn7UWfZDec73kS8P0PMHMH8pCorHKkpeJtLDw2QP
|
||||||
|
FgYicFZ8u6fYjOYNikmQQe9c8FRJgwSYMeXQb0hf1dlC/WpJGO00Efwor99lS2cl
|
||||||
|
DegHOF5dv3wl7b+xvdzhUs3yqYiq9Qa/+N7oIPkgzhlltDabPRhIFLnJsmxfa/Kt
|
||||||
|
lF/MZ1Va+UjR+JQ1unNE/CTn6L5A4cavpOoI72N2elJRw+QP8icwGLApBp/W
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
Bag Attributes: <No Attributes>
|
||||||
|
subject=emailAddress = info@andesscd.com.co, CN = CA ANDES SCD S.A. Clase II v2, OU = Division de certificacion entidad final, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
issuer=emailAddress = info@andesscd.com.co, CN = ROOT CA ANDES SCD S.A., OU = Division de certificacion, O = Andes SCD, L = Bogota D.C., C = CO
|
||||||
|
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGrzCCBJegAwIBAgIIRLa0wz3hC2gwDQYJKoZIhvcNAQELBQAwgaExIzAhBgkq
|
||||||
|
hkiG9w0BCQEWFGluZm9AYW5kZXNzY2QuY29tLmNvMR8wHQYDVQQDExZST09UIENB
|
||||||
|
IEFOREVTIFNDRCBTLkEuMSIwIAYDVQQLExlEaXZpc2lvbiBkZSBjZXJ0aWZpY2Fj
|
||||||
|
aW9uMRIwEAYDVQQKEwlBbmRlcyBTQ0QxFDASBgNVBAcTC0JvZ290YSBELkMuMQsw
|
||||||
|
CQYDVQQGEwJDTzAeFw0xOTA4MDYxNjE0NTNaFw0yNTExMTUxNzM0MzBaMIG2MSMw
|
||||||
|
IQYJKoZIhvcNAQkBFhRpbmZvQGFuZGVzc2NkLmNvbS5jbzEmMCQGA1UEAxMdQ0Eg
|
||||||
|
QU5ERVMgU0NEIFMuQS4gQ2xhc2UgSUkgdjIxMDAuBgNVBAsTJ0RpdmlzaW9uIGRl
|
||||||
|
IGNlcnRpZmljYWNpb24gZW50aWRhZCBmaW5hbDESMBAGA1UEChMJQW5kZXMgU0NE
|
||||||
|
MRQwEgYDVQQHEwtCb2dvdGEgRC5DLjELMAkGA1UEBhMCQ08wggIiMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4ICDwAwggIKAoICAQDOWKOiAg0IgACNXNyDCoAyaXo514UwF9oCqMjg
|
||||||
|
xAOhOe+g3lUDWTXtV6l8O1VXHQa86KZwqgT0mfw0HqePQYKC93n9+timuuT1FuAJ
|
||||||
|
Z9TnF/f6DQDzFQWsRVLdqV/hzNQ/rbOvPX8WN4Z97TyJaUtlxbENOKgOlzsW8hGe
|
||||||
|
eVrjDz9fk1e0TPem/CswuY+7Z/Pi4/EVz28UoTlfEMOg84ZutTomHOskIp6S86lw
|
||||||
|
X+ts15yChEf/dXBVkAMkBUpFc39iZWhhtewZo56Q8u9an5ZBQtOorB33LKFKn2P1
|
||||||
|
V95Cf2XPZqWqLrP1wRQn0XWB1uDF+eAyQzShGA0jrZGgdlaFW8J7bx8+YntJHqFi
|
||||||
|
jI3UVwqCyb+TGO9RRcTRp3OfAwAKCbh56gHacvF5KEGj36d0zofw808WBpnhrnvQ
|
||||||
|
ofPp48mowpbByzuIqVtX0utVXgzg4QdNBSQ6uhDnjB8ETzwuJcUokC1lXwBMSDa0
|
||||||
|
f5psC1yflyqdTOpSjZC8pMxwGUXhhvkfxDBaSsueExLpcKlolVojQRWm6C2oiumS
|
||||||
|
2lgeL4ydh8DFhi2llMLVCLZQLffG9ziTZtMd97n55NvXrVa4XbDIf4i5/XFrYgFy
|
||||||
|
R/rBZduYWDqxcwFnUP6HhTfuael8qNxKA3UWmxFK3ixNN5kaC/ErX3g4fC+KGqh4
|
||||||
|
LeljKQIDAQABo4HTMIHQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU3RGS
|
||||||
|
WqlsBAz+NKJYv+sd+98IsG8wNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhto
|
||||||
|
dHRwOi8vb2NzcC5hbmRlc3NjZC5jb20uY28wNAYDVR0fBC0wKzApoCegJYYjaHR0
|
||||||
|
cDovL2NybC5hbmRlc3NjZC5jb20uY28vUmFpei5jcmwwHQYDVR0OBBYEFDpXUNB3
|
||||||
|
Gz7Wi+r/l5nX/4QCSCkPMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC
|
||||||
|
AgEALA0nz8TvtoMZ70MBN7FFWZMqTXvkXY7mcnWImpTFLGzny+i119qODuItEf5G
|
||||||
|
977TzoTCxZC8DlPL1d88+YxAfYFRLXdb1HcDrNuWKMyoiFGH3vhNl+Ef//4zed98
|
||||||
|
DV5jtoaCofFt/JzPz2iA7Al2LZ1m0vAF0z12LAytHqSfob+5mdgWkBnLae0vaWU+
|
||||||
|
eGnoTkCYsasxca9oSKHDajqTvTa5WogibUaffcnb9LYaP3nkam9+favCyHHQW2lp
|
||||||
|
2xPPcP1gisvp99ga9Cwft7d/QHXNjseop2TwDoUHViUImaSpLz+2kWhkr2LOSTpL
|
||||||
|
43rWQhVQ/Y6SyYd3YWEBxJWwFvVlHvQ2wKwiE/z7kHnCP9ztPhS0umC1BMGq3pC4
|
||||||
|
fifzvx9218JjDIOVrKzwonCTj0vwQZ4FmTttAr0G+R5TrqqvgF1t/RTfhWIxhUTk
|
||||||
|
TR3xRpR/5mBtqrSmyojGtdVkwHq2dmmDIkjefSbxKDkkAkhDRt5CDeV913B3MvYm
|
||||||
|
UiMoOJmLyapIZjIko1HxzXBv3dPc5LYSKpG8rd9SjJtA7W8LQzAVUq8O32nO7edY
|
||||||
|
IvTrC11fLkdToGOxLmfTzZ+facUESteELfxchZoda6I9qH5Xa7Xka2M2mmkj0SGU
|
||||||
|
46KREw+DtpoUkpAQ7rLaZ+4stT0j1Z8soirB+EUk8oBLiTI=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
25
setup.cfg
Normal file
25
setup.cfg
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[bumpversion]
|
||||||
|
current_version = 0.1.0
|
||||||
|
commit = True
|
||||||
|
tag = True
|
||||||
|
|
||||||
|
[bumpversion:file:setup.py]
|
||||||
|
search = version='{current_version}'
|
||||||
|
replace = version='{new_version}'
|
||||||
|
|
||||||
|
[bumpversion:file:facho/__init__.py]
|
||||||
|
search = __version__ = '{current_version}'
|
||||||
|
replace = __version__ = '{new_version}'
|
||||||
|
|
||||||
|
[bdist_wheel]
|
||||||
|
universal = 1
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
exclude = docs
|
||||||
|
|
||||||
|
[aliases]
|
||||||
|
# Define setup.py command aliases here
|
||||||
|
test = pytest
|
||||||
|
|
||||||
|
[tool:pytest]
|
||||||
|
collect_ignore = ['setup.py']
|
||||||
72
setup.py
Normal file
72
setup.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#!/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.
|
||||||
|
|
||||||
|
"""The setup script."""
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
with open('README.rst') as readme_file:
|
||||||
|
readme = readme_file.read()
|
||||||
|
|
||||||
|
with open('HISTORY.rst') as history_file:
|
||||||
|
history = history_file.read()
|
||||||
|
|
||||||
|
requirements = ['Click>=8.1.7',
|
||||||
|
'zeep==4.2.1',
|
||||||
|
'lxml==5.2.2',
|
||||||
|
'cryptography==3.3.2',
|
||||||
|
'pyOpenSSL==20.0.1',
|
||||||
|
'xmlsig==0.1.7',
|
||||||
|
'xades==1.0.0',
|
||||||
|
'xmlsec==1.3.14',
|
||||||
|
'python-dateutil==2.9.0.post0',
|
||||||
|
# usamos esta dependencia en runtime
|
||||||
|
# para forzar uso de policy_id de archivo local
|
||||||
|
'mock>=5.1.0',
|
||||||
|
'xmlschema>=3.0.0' ]
|
||||||
|
|
||||||
|
setup_requirements = ['pytest-runner', ]
|
||||||
|
|
||||||
|
test_requirements = ['pytest', ]
|
||||||
|
|
||||||
|
setup(
|
||||||
|
author="Jovany Leandro G.C",
|
||||||
|
author_email='bit4bit@riseup.net',
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 2 - Pre-Alpha',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Programming Language :: Python :: 3.4',
|
||||||
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
],
|
||||||
|
description="Facturacion Electronica Colombia",
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'facho=facho.cli:main',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
install_requires=requirements,
|
||||||
|
license="GNU General Public License v3",
|
||||||
|
long_description=readme + '\n\n' + history,
|
||||||
|
long_description_content_type='text/x-rst',
|
||||||
|
include_package_data=True,
|
||||||
|
package_data = {
|
||||||
|
# If any package contains *.txt or *.rst files, include them:
|
||||||
|
'': ['*.gc', '*.xsd', 'politicadefirmav2.pdf']
|
||||||
|
},
|
||||||
|
keywords='facho',
|
||||||
|
name='facho',
|
||||||
|
packages=find_packages(exclude=("tests",)),
|
||||||
|
setup_requires=setup_requirements,
|
||||||
|
test_suite='tests',
|
||||||
|
tests_require=test_requirements,
|
||||||
|
url='https://github.com/bit4bit/facho',
|
||||||
|
version='0.2.0',
|
||||||
|
zip_safe=False,
|
||||||
|
)
|
||||||
@@ -1 +0,0 @@
|
|||||||
907e4444decc9e59c160a2fb3b6659b33dc5b632a5008922b9a62f83f757b1c448e47f5867f2b50dbdb96f48c7681168
|
|
||||||
@@ -2,82 +2,70 @@ import pytest
|
|||||||
import facho.fe.form as form
|
import facho.fe.form as form
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def simple_debit_note_without_lines():
|
def simple_debit_note_without_lines():
|
||||||
inv = form.DebitNote(form.InvoiceDocumentReference(
|
inv = form.DebitNote(form.InvoiceDocumentReference('1234', 'xx', datetime.now()))
|
||||||
'1234', 'xx', datetime.now()))
|
|
||||||
inv.set_period(datetime.now(), datetime.now())
|
inv.set_period(datetime.now(), datetime.now())
|
||||||
inv.set_issue(datetime.now())
|
inv.set_issue(datetime.now())
|
||||||
inv.set_ident('ABC123')
|
inv.set_ident('ABC123')
|
||||||
inv.set_operation_type('30')
|
inv.set_operation_type('30')
|
||||||
inv.set_payment_mean(form.PaymentMean(
|
inv.set_payment_mean(form.PaymentMean(form.PaymentMean.DEBIT, '41', datetime.now(), '1234'))
|
||||||
form.PaymentMean.DEBIT, '41', datetime.now(), '1234'))
|
|
||||||
inv.set_supplier(form.Party(
|
inv.set_supplier(form.Party(
|
||||||
name='facho-supplier',
|
name = 'facho-supplier',
|
||||||
ident=form.PartyIdentification('123', '', '31'),
|
ident = form.PartyIdentification('123','', '31'),
|
||||||
responsability_code=form.Responsability(['ZZ']),
|
responsability_code = form.Responsability(['O-07']),
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia'))
|
form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
inv.set_customer(form.Party(
|
inv.set_customer(form.Party(
|
||||||
name='facho-customer',
|
name = 'facho-customer',
|
||||||
ident=form.PartyIdentification('321', '', '31'),
|
ident = form.PartyIdentification('321', '', '31'),
|
||||||
responsability_code=form.Responsability(['ZZ']),
|
responsability_code = form.Responsability(['O-07']),
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia'))
|
form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
return inv
|
return inv
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def simple_credit_note_without_lines():
|
def simple_credit_note_without_lines():
|
||||||
inv = form.CreditNote(
|
inv = form.CreditNote(form.InvoiceDocumentReference('1234', 'xx', datetime.now()))
|
||||||
form.InvoiceDocumentReference(
|
|
||||||
'1234', 'xx', datetime.now()))
|
|
||||||
inv.set_period(datetime.now(), datetime.now())
|
inv.set_period(datetime.now(), datetime.now())
|
||||||
inv.set_issue(datetime.now())
|
inv.set_issue(datetime.now())
|
||||||
inv.set_ident('ABC123')
|
inv.set_ident('ABC123')
|
||||||
inv.set_operation_type('20')
|
inv.set_operation_type('20')
|
||||||
inv.set_payment_mean(
|
inv.set_payment_mean(form.PaymentMean(form.PaymentMean.DEBIT, '41', datetime.now(), '1234'))
|
||||||
form.PaymentMean(
|
|
||||||
form.PaymentMean.DEBIT,
|
|
||||||
'41',
|
|
||||||
datetime.now(),
|
|
||||||
'1234'))
|
|
||||||
inv.set_supplier(form.Party(
|
inv.set_supplier(form.Party(
|
||||||
name='facho-supplier',
|
name = 'facho-supplier',
|
||||||
ident=form.PartyIdentification('123', '', '31'),
|
ident = form.PartyIdentification('123','', '31'),
|
||||||
responsability_code=form.Responsability(['ZZ']),
|
responsability_code = form.Responsability(['O-07']),
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia'))
|
form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
inv.set_customer(form.Party(
|
inv.set_customer(form.Party(
|
||||||
name='facho-customer',
|
name = 'facho-customer',
|
||||||
ident=form.PartyIdentification('321', '', '31'),
|
ident = form.PartyIdentification('321', '', '31'),
|
||||||
responsability_code=form.Responsability(['ZZ']),
|
responsability_code = form.Responsability(['O-07']),
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia'))
|
form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
return inv
|
return inv
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def simple_invoice_without_lines():
|
def simple_invoice_without_lines():
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
@@ -85,37 +73,31 @@ def simple_invoice_without_lines():
|
|||||||
inv.set_issue(datetime.now())
|
inv.set_issue(datetime.now())
|
||||||
inv.set_ident('ABC123')
|
inv.set_ident('ABC123')
|
||||||
inv.set_operation_type('10')
|
inv.set_operation_type('10')
|
||||||
inv.set_payment_mean(
|
inv.set_payment_mean(form.PaymentMean(form.PaymentMean.DEBIT, '41', datetime.now(), '1234'))
|
||||||
form.PaymentMean(
|
|
||||||
form.PaymentMean.DEBIT,
|
|
||||||
'41',
|
|
||||||
datetime.now(),
|
|
||||||
'1234'))
|
|
||||||
inv.set_supplier(form.Party(
|
inv.set_supplier(form.Party(
|
||||||
name='facho-supplier',
|
name = 'facho-supplier',
|
||||||
ident=form.PartyIdentification('123', '', '31'),
|
ident = form.PartyIdentification('123','', '31'),
|
||||||
responsability_code=form.Responsability(['ZZ']),
|
responsability_code = form.Responsability(['O-07']),
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia'))
|
form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
inv.set_customer(form.Party(
|
inv.set_customer(form.Party(
|
||||||
name='facho-customer',
|
name = 'facho-customer',
|
||||||
ident=form.PartyIdentification('321', '', '31'),
|
ident = form.PartyIdentification('321', '', '31'),
|
||||||
responsability_code=form.Responsability(['ZZ']),
|
responsability_code = form.Responsability(['O-07']),
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia'))
|
form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
return inv
|
return inv
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def simple_invoice():
|
def simple_invoice():
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
@@ -123,48 +105,42 @@ def simple_invoice():
|
|||||||
inv.set_issue(datetime.now())
|
inv.set_issue(datetime.now())
|
||||||
inv.set_ident('ABC123')
|
inv.set_ident('ABC123')
|
||||||
inv.set_operation_type('10')
|
inv.set_operation_type('10')
|
||||||
inv.set_payment_mean(
|
inv.set_payment_mean(form.PaymentMean(form.PaymentMean.DEBIT, '41', datetime.now(), ' 1234'))
|
||||||
form.PaymentMean(
|
|
||||||
form.PaymentMean.DEBIT,
|
|
||||||
'41',
|
|
||||||
datetime.now(),
|
|
||||||
' 1234'))
|
|
||||||
inv.set_supplier(form.Party(
|
inv.set_supplier(form.Party(
|
||||||
name='facho-supplier',
|
name = 'facho-supplier',
|
||||||
ident=form.PartyIdentification('123', '', '31'),
|
ident = form.PartyIdentification('123','', '31'),
|
||||||
responsability_code=form.Responsability(['ZZ']),
|
responsability_code = form.Responsability(['O-07']),
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia'))
|
form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
inv.set_customer(form.Party(
|
inv.set_customer(form.Party(
|
||||||
name='facho-customer',
|
name = 'facho-customer',
|
||||||
ident=form.PartyIdentification('321', '', '31'),
|
ident = form.PartyIdentification('321','', '31'),
|
||||||
responsability_code=form.Responsability(['ZZ']),
|
responsability_code = form.Responsability(['O-07']),
|
||||||
responsability_regime_code='48',
|
responsability_regime_code = '48',
|
||||||
organization_code='1',
|
organization_code = '1',
|
||||||
address=form.Address(
|
address = form.Address(
|
||||||
'', '', form.City('05001', 'Medellín'),
|
'', '', form.City('05001', 'Medellín'),
|
||||||
form.Country('CO', 'Colombia'),
|
form.Country('CO', 'Colombia'),
|
||||||
form.CountrySubentity('05', 'Antioquia'))
|
form.CountrySubentity('05', 'Antioquia'))
|
||||||
))
|
))
|
||||||
|
|
||||||
inv.add_invoice_line(form.InvoiceLine(
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
description='productofacho',
|
description = 'producto facho',
|
||||||
item=form.StandardItem(9999),
|
item = form.StandardItem( 9999),
|
||||||
price=form.Price(form.Amount(100.0), '01', ''),
|
price = form.Price(form.Amount(100.0), '01', ''),
|
||||||
tax=form.TaxTotal(
|
tax = form.TaxTotal(
|
||||||
tax_amount=form.Amount(0.0),
|
tax_amount = form.Amount(0.0),
|
||||||
taxable_amount=form.Amount(0.0),
|
taxable_amount = form.Amount(0.0),
|
||||||
subtotals=[
|
subtotals = [
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
percent=19.0,
|
percent = 19.0,
|
||||||
)]),
|
)
|
||||||
withholding=form.WithholdingTaxTotal(
|
]
|
||||||
subtotals=[])
|
)
|
||||||
))
|
))
|
||||||
return inv
|
return inv
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ def test_amount_positive():
|
|||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
form.Amount(-1.0)
|
form.Amount(-1.0)
|
||||||
|
|
||||||
|
|
||||||
def test_amount_equals():
|
def test_amount_equals():
|
||||||
price1 = form.Amount(110.0)
|
price1 = form.Amount(110.0)
|
||||||
price2 = form.Amount(100 + 10.0)
|
price2 = form.Amount(100 + 10.0)
|
||||||
@@ -23,7 +22,6 @@ def test_amount_equals():
|
|||||||
assert price1 == form.Amount(10) * form.Amount(10) + form.Amount(10)
|
assert price1 == form.Amount(10) * form.Amount(10) + form.Amount(10)
|
||||||
assert form.Amount(110) == (form.Amount(1.10) * form.Amount(100))
|
assert form.Amount(110) == (form.Amount(1.10) * form.Amount(100))
|
||||||
|
|
||||||
|
|
||||||
def test_round_half_even():
|
def test_round_half_even():
|
||||||
# https://www.w3.org/TR/xpath-functions-31/#func-round-half-to-even
|
# https://www.w3.org/TR/xpath-functions-31/#func-round-half-to-even
|
||||||
assert form.Amount(0.5).round(0).float() == 0.0
|
assert form.Amount(0.5).round(0).float() == 0.0
|
||||||
@@ -32,20 +30,16 @@ def test_round_half_even():
|
|||||||
assert form.Amount(3.567812e+3).round(2).float() == 3567.81e0
|
assert form.Amount(3.567812e+3).round(2).float() == 3567.81e0
|
||||||
assert form.Amount(4.7564e-3).round(2).float() == 0.0e0
|
assert form.Amount(4.7564e-3).round(2).float() == 0.0e0
|
||||||
|
|
||||||
|
|
||||||
def test_round():
|
def test_round():
|
||||||
# Entre 0 y 5 Mantener el dígito menos significativo
|
# Entre 0 y 5 Mantener el dígito menos significativo
|
||||||
assert form.Amount(1.133).round(2) == form.Amount(1.13)
|
assert form.Amount(1.133).round(2) == form.Amount(1.13)
|
||||||
# Entre 6 y 9 Incrementar el dígito menos significativo
|
# Entre 6 y 9 Incrementar el dígito menos significativo
|
||||||
assert form.Amount(1.166).round(2) == form.Amount(1.17)
|
assert form.Amount(1.166).round(2) == form.Amount(1.17)
|
||||||
# 5, y el segundo dígito siguiente al dígito menos significativo es cero o
|
# 5, y el segundo dígito siguiente al dígito menos significativo es cero o par Mantener el dígito menos significativo
|
||||||
# par Mantener el dígito menos significativo
|
|
||||||
assert str(form.Amount(1.1542).round(2)) == str(form.Amount(1.15))
|
assert str(form.Amount(1.1542).round(2)) == str(form.Amount(1.15))
|
||||||
# 5, y el segundo dígito siguiente al dígito menos significativo es impar
|
# 5, y el segundo dígito siguiente al dígito menos significativo es impar Incrementar el dígito menos significativo
|
||||||
# Incrementar el dígito menos significativo
|
|
||||||
assert str(form.Amount(1.1563).round(2)) == str(form.Amount(1.16))
|
assert str(form.Amount(1.1563).round(2)) == str(form.Amount(1.16))
|
||||||
|
|
||||||
|
|
||||||
def test_amount_truncate():
|
def test_amount_truncate():
|
||||||
assert form.Amount(1.1569).truncate_as_string(2) == '1.15'
|
assert form.Amount(1.1569).truncate_as_string(2) == '1.15'
|
||||||
assert form.Amount(587.0700).truncate_as_string(2) == '587.07'
|
assert form.Amount(587.0700).truncate_as_string(2) == '587.07'
|
||||||
@@ -55,6 +49,5 @@ def test_amount_truncate():
|
|||||||
assert form.Amount(10000.02245).truncate_as_string(2) == '10000.02'
|
assert form.Amount(10000.02245).truncate_as_string(2) == '10000.02'
|
||||||
assert form.Amount(10000.02357).truncate_as_string(2) == '10000.02'
|
assert form.Amount(10000.02357).truncate_as_string(2) == '10000.02'
|
||||||
|
|
||||||
|
|
||||||
def test_amount_format():
|
def test_amount_format():
|
||||||
assert str(round(form.Amount(1.1569), 2)) == '1.16'
|
assert str(round(form.Amount(1.1569),2)) == '1.16'
|
||||||
|
|||||||
@@ -2,15 +2,16 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# This file is part of facho. The COPYRIGHT file at the top level of
|
# This file is part of facho. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
# from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# import pytest
|
import pytest
|
||||||
# from facho.fe import form_xml
|
from facho.fe import form_xml
|
||||||
|
|
||||||
# import helpers
|
import helpers
|
||||||
|
|
||||||
|
def test_xml_with_required_elements():
|
||||||
|
doc = form_xml.AttachedDocument(id='123')
|
||||||
|
|
||||||
# def test_xml_with_required_elements():
|
xml = doc.toFachoXML()
|
||||||
# doc = form_xml.AttachedDocument(id='123')
|
assert xml.get_element_text('/atd:AttachedDocument/cbc:ID') == '123'
|
||||||
# xml = doc.toFachoXML()
|
|
||||||
# assert xml.get_element_text('/atd:AttachedDocument/cbc:ID') == '123'
|
|
||||||
|
|||||||
@@ -4,7 +4,12 @@
|
|||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
from facho import facho
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
class FakeDianClient(dian.DianClient):
|
class FakeDianClient(dian.DianClient):
|
||||||
def __init__(self, username, password, resp):
|
def __init__(self, username, password, resp):
|
||||||
|
|||||||
@@ -4,26 +4,21 @@
|
|||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
"""Tests for `facho` package."""
|
"""Tests for `facho` package."""
|
||||||
from facho.fe.data.dian import codelist
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from facho.fe.data.dian import codelist
|
||||||
|
|
||||||
def test_tiporesponsabilidad():
|
def test_tiporesponsabilidad():
|
||||||
assert codelist.TipoResponsabilidad.short_name == 'TipoResponsabilidad'
|
assert codelist.TipoResponsabilidad.short_name == 'TipoResponsabilidad'
|
||||||
assert codelist.TipoResponsabilidad.by_name(
|
assert codelist.TipoResponsabilidad.by_name('Autorretenedor')['name'] == 'Autorretenedor'
|
||||||
'Autorretenedor')['name'] == 'Autorretenedor'
|
|
||||||
|
|
||||||
|
|
||||||
def test_tipoorganizacion():
|
def test_tipoorganizacion():
|
||||||
assert codelist.TipoOrganizacion.short_name == 'TipoOrganizacion'
|
assert codelist.TipoOrganizacion.short_name == 'TipoOrganizacion'
|
||||||
assert codelist.TipoOrganizacion.by_name(
|
assert codelist.TipoOrganizacion.by_name('Persona Natural')['name'] == 'Persona Natural'
|
||||||
'Persona Natural')['name'] == 'Persona Natural'
|
|
||||||
|
|
||||||
|
|
||||||
def test_tipodocumento():
|
def test_tipodocumento():
|
||||||
assert codelist.TipoDocumento.short_name == 'TipoDocumento'
|
assert codelist.TipoDocumento.short_name == 'TipoDocumento'
|
||||||
assert codelist.TipoDocumento.by_name(
|
assert codelist.TipoDocumento.by_name('Factura de Venta Nacional')['code'] == '01'
|
||||||
'Factura electrónica de Venta')['code'] == '01'
|
|
||||||
|
|
||||||
|
|
||||||
def test_departamento():
|
def test_departamento():
|
||||||
assert codelist.Departamento['05']['name'] == 'Antioquia'
|
assert codelist.Departamento['05']['name'] == 'Antioquia'
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
# from click.testing import CliRunner
|
#from click.testing import CliRunner
|
||||||
|
|
||||||
from facho import facho
|
from facho import facho
|
||||||
# from facho import cli
|
#from facho import cli
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml():
|
def test_facho_xml():
|
||||||
@@ -20,19 +20,18 @@ def test_facho_xml():
|
|||||||
invoice.text = 'Test'
|
invoice.text = 'Test'
|
||||||
assert xml.tostring() == '<root><Invoice>Test</Invoice></root>'
|
assert xml.tostring() == '<root><Invoice>Test</Invoice></root>'
|
||||||
|
|
||||||
xml.find_or_create_element('/root/Invoice/Line')
|
invoice_line = xml.find_or_create_element('/root/Invoice/Line')
|
||||||
assert xml.tostring() == '<root><Invoice>Test<Line/></Invoice></root>'
|
assert xml.tostring() == '<root><Invoice>Test<Line/></Invoice></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_with_attr():
|
def test_facho_xml_with_attr():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.find_or_create_element('/root/Invoice[id=123]')
|
invoice = xml.find_or_create_element('/root/Invoice[id=123]')
|
||||||
assert xml.tostring() == '<root><Invoice id="123"/></root>'
|
assert xml.tostring() == '<root><Invoice id="123"/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_idempotent():
|
def test_facho_xml_idempotent():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.find_or_create_element('/root/Invoice')
|
invoice = xml.find_or_create_element('/root/Invoice')
|
||||||
assert xml.tostring() == '<root><Invoice/></root>'
|
assert xml.tostring() == '<root><Invoice/></root>'
|
||||||
|
|
||||||
xml.find_or_create_element('/root/Invoice')
|
xml.find_or_create_element('/root/Invoice')
|
||||||
@@ -47,7 +46,6 @@ def test_facho_xml_idempotent():
|
|||||||
xml.find_or_create_element('/root/Invoice/Line')
|
xml.find_or_create_element('/root/Invoice/Line')
|
||||||
assert xml.tostring() == '<root><Invoice><Line/></Invoice></root>'
|
assert xml.tostring() == '<root><Invoice><Line/></Invoice></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_aliases():
|
def test_facho_xml_aliases():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.register_alias_xpath('Invoice', '/root/Invoice')
|
xml.register_alias_xpath('Invoice', '/root/Invoice')
|
||||||
@@ -56,42 +54,31 @@ def test_facho_xml_aliases():
|
|||||||
invoice.text = 'Test'
|
invoice.text = 'Test'
|
||||||
assert xml.tostring() == '<root><Invoice>Test</Invoice></root>'
|
assert xml.tostring() == '<root><Invoice>Test</Invoice></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xmlns():
|
def test_facho_xmlns():
|
||||||
xml = facho.FachoXML('root', nsmap={
|
xml = facho.FachoXML('root', nsmap={
|
||||||
'ext': 'https://ext',
|
'ext': 'https://ext',
|
||||||
'sts': 'https://sts',
|
'sts': 'https://sts',
|
||||||
})
|
})
|
||||||
|
|
||||||
invoiceAuthorization = xml.find_or_create_element(
|
invoiceAuthorization = xml.find_or_create_element('/root/ext:UBLExtensions/ext:UBLExtension/'
|
||||||
'/root/ext:UBLExtensions/ext:UBLExtension/'
|
'ext:ExtensionContent/sts:DianExtensions/'
|
||||||
'ext:ExtensionContent/sts:DianExtensions/'
|
'sts:InvoiceControl/sts:InvoiceAuthorization')
|
||||||
'sts:InvoiceControl/sts:InvoiceAuthorization')
|
assert xml.tostring().strip() == '<root xmlns:ext="https://ext" xmlns:sts="https://sts"><ext:UBLExtensions>'\
|
||||||
assert xml.tostring().strip() == (
|
'<ext:UBLExtension>'\
|
||||||
'<root xmlns:ext="https://ext" xmlns:sts="https://sts">'
|
'<ext:ExtensionContent>'\
|
||||||
'<ext:UBLExtensions>'
|
'<sts:DianExtensions>'\
|
||||||
'<ext:UBLExtension>'
|
'<sts:InvoiceControl>'\
|
||||||
'<ext:ExtensionContent>'
|
'<sts:InvoiceAuthorization/>'\
|
||||||
'<sts:DianExtensions>'
|
'</sts:InvoiceControl></sts:DianExtensions></ext:ExtensionContent></ext:UBLExtension></ext:UBLExtensions></root>'
|
||||||
'<sts:InvoiceControl>'
|
|
||||||
'<sts:InvoiceAuthorization/>'
|
|
||||||
'</sts:InvoiceControl></sts:DianExtensions>'
|
|
||||||
'</ext:ExtensionContent></ext:UBLExtension>'
|
|
||||||
'</ext:UBLExtensions></root>')
|
|
||||||
|
|
||||||
invoiceAuthorization.text = '123456789'
|
invoiceAuthorization.text = '123456789'
|
||||||
assert xml.tostring().strip() == (
|
assert xml.tostring().strip() == '<root xmlns:ext="https://ext" xmlns:sts="https://sts"><ext:UBLExtensions>'\
|
||||||
'<root xmlns:ext="https://ext" xmlns:sts="https://sts">'
|
'<ext:UBLExtension>'\
|
||||||
'<ext:UBLExtensions>'
|
'<ext:ExtensionContent>'\
|
||||||
'<ext:UBLExtension>'
|
'<sts:DianExtensions>'\
|
||||||
'<ext:ExtensionContent>'
|
'<sts:InvoiceControl>'\
|
||||||
'<sts:DianExtensions>'
|
'<sts:InvoiceAuthorization>123456789</sts:InvoiceAuthorization>'\
|
||||||
'<sts:InvoiceControl>'
|
'</sts:InvoiceControl></sts:DianExtensions></ext:ExtensionContent></ext:UBLExtension></ext:UBLExtensions></root>'
|
||||||
'<sts:InvoiceAuthorization>123456789</sts:InvoiceAuthorization>'
|
|
||||||
'</sts:InvoiceControl></sts:DianExtensions>'
|
|
||||||
'</ext:ExtensionContent></ext:UBLExtension>'
|
|
||||||
'</ext:UBLExtensions></root>')
|
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xmlns_idempotent():
|
def test_facho_xmlns_idempotent():
|
||||||
xml = facho.FachoXML('root', nsmap={
|
xml = facho.FachoXML('root', nsmap={
|
||||||
@@ -100,22 +87,16 @@ def test_facho_xmlns_idempotent():
|
|||||||
})
|
})
|
||||||
|
|
||||||
xml.find_or_create_element('/root/ext:Extension/sts:Sotoros')
|
xml.find_or_create_element('/root/ext:Extension/sts:Sotoros')
|
||||||
assert xml.tostring() == (
|
assert xml.tostring() == '<root xmlns:ext="https://ext" xmlns:sts="https://sts"><ext:Extension><sts:Sotoros/></ext:Extension></root>'
|
||||||
'<root xmlns:ext="https://ext" xmlns:sts="https://sts">'
|
|
||||||
'<ext:Extension><sts:Sotoros/></ext:Extension></root>')
|
|
||||||
|
|
||||||
xml.find_or_create_element('/root/ext:Extension/sts:Sotoros')
|
xml.find_or_create_element('/root/ext:Extension/sts:Sotoros')
|
||||||
assert xml.tostring() == (
|
assert xml.tostring() == '<root xmlns:ext="https://ext" xmlns:sts="https://sts"><ext:Extension><sts:Sotoros/></ext:Extension></root>'
|
||||||
'<root xmlns:ext="https://ext" xmlns:sts="https://sts">'
|
|
||||||
'<ext:Extension><sts:Sotoros/></ext:Extension></root>')
|
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_set_element_with_format():
|
def test_facho_xml_set_element_with_format():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.set_element('/root/Invoice', 1, format_='%02d')
|
invoice = xml.set_element('/root/Invoice', 1, format_='%02d')
|
||||||
assert xml.tostring() == '<root><Invoice>01</Invoice></root>'
|
assert xml.tostring() == '<root><Invoice>01</Invoice></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_fragment():
|
def test_facho_xml_fragment():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
invoice = xml.fragment('/root/Invoice')
|
invoice = xml.fragment('/root/Invoice')
|
||||||
@@ -135,10 +116,7 @@ def test_facho_xml_fragments():
|
|||||||
line = xml.fragment('/Invoice/Line', append=True)
|
line = xml.fragment('/Invoice/Line', append=True)
|
||||||
line.set_element('/Line/Id', 3)
|
line.set_element('/Line/Id', 3)
|
||||||
|
|
||||||
assert xml.tostring() == (
|
assert xml.tostring() == '<Invoice><Line><Id>1</Id></Line><Line><Id>2</Id></Line><Line><Id>3</Id></Line></Invoice>'
|
||||||
'<Invoice><Line><Id>1</Id></Line><Line><Id>2</Id></Line>'
|
|
||||||
'<Line><Id>3</Id></Line></Invoice>')
|
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_nested_fragments():
|
def test_facho_xml_nested_fragments():
|
||||||
xml = facho.FachoXML('Invoice')
|
xml = facho.FachoXML('Invoice')
|
||||||
@@ -150,20 +128,15 @@ def test_facho_xml_nested_fragments():
|
|||||||
|
|
||||||
party.set_element('/Party/LastName', 'test')
|
party.set_element('/Party/LastName', 'test')
|
||||||
|
|
||||||
assert xml.tostring() == (
|
assert xml.tostring() == '<Invoice><Party><Name>test</Name><Address><Line>line 1</Line></Address><LastName>test</LastName></Party></Invoice>'
|
||||||
'<Invoice><Party><Name>test</Name>'
|
|
||||||
'<Address><Line>line 1</Line></Address>'
|
|
||||||
'<LastName>test</LastName></Party></Invoice>')
|
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_get_element_text_of_fragment():
|
def test_facho_xml_get_element_text_of_fragment():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
invoice = xml.fragment('/root/Invoice')
|
invoice = xml.fragment('/root/Invoice')
|
||||||
invoice.set_element('/Invoice/Id', 1)
|
invoice.set_element('/Invoice/Id', 1)
|
||||||
|
|
||||||
assert invoice.get_element_text('/Invoice/Id') == '1'
|
assert invoice.get_element_text('/Invoice/Id') == '1'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_get_element_text():
|
def test_facho_xml_get_element_text():
|
||||||
xml = facho.FachoXML('Invoice')
|
xml = facho.FachoXML('Invoice')
|
||||||
xml.set_element('/Invoice/ID', 'ABC123')
|
xml.set_element('/Invoice/ID', 'ABC123')
|
||||||
@@ -174,7 +147,6 @@ def test_facho_xml_get_element_text():
|
|||||||
line.set_element('/Line/Quantity', 5)
|
line.set_element('/Line/Quantity', 5)
|
||||||
assert line.get_element_text('/Line/Quantity', format_=int) == 5
|
assert line.get_element_text('/Line/Quantity', format_=int) == 5
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_get_element_text_next_child():
|
def test_facho_xml_get_element_text_next_child():
|
||||||
xml = facho.FachoXML('Invoice')
|
xml = facho.FachoXML('Invoice')
|
||||||
xml.set_element('/Invoice/ID', 'ABC123')
|
xml.set_element('/Invoice/ID', 'ABC123')
|
||||||
@@ -194,32 +166,25 @@ def test_facho_xml_set_element_relative():
|
|||||||
|
|
||||||
assert xml.get_element_text('/Invoice/ID') == 'ABC123'
|
assert xml.get_element_text('/Invoice/ID') == 'ABC123'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_set_element_relative_with_namespace():
|
def test_facho_xml_set_element_relative_with_namespace():
|
||||||
xml = facho.FachoXML(
|
xml = facho.FachoXML('{%s}Invoice' % ('http://www.dian.gov.co/contratos/facturaelectronica/v1'),
|
||||||
'{%s}Invoice' %
|
nsmap={'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1'})
|
||||||
('http://www.dian.gov.co/contratos/facturaelectronica/v1'),
|
|
||||||
nsmap={
|
|
||||||
'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1'})
|
|
||||||
xml.set_element('./ID', 'ABC123')
|
xml.set_element('./ID', 'ABC123')
|
||||||
|
|
||||||
assert xml.get_element_text('/fe:Invoice/ID') == 'ABC123'
|
assert xml.get_element_text('/fe:Invoice/ID') == 'ABC123'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_fragment_relative():
|
def test_facho_xml_fragment_relative():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
invoice = xml.fragment('./Invoice')
|
invoice = xml.fragment('./Invoice')
|
||||||
invoice.set_element('./Id', 1)
|
invoice.set_element('./Id', 1)
|
||||||
assert xml.tostring() == '<root><Invoice><Id>1</Id></Invoice></root>'
|
assert xml.tostring() == '<root><Invoice><Id>1</Id></Invoice></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_get_element_fragment_relative():
|
def test_facho_xml_get_element_fragment_relative():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
invoice = xml.fragment('./Invoice')
|
invoice = xml.fragment('./Invoice')
|
||||||
invoice.set_element('./Id', 1)
|
invoice.set_element('./Id', 1)
|
||||||
assert invoice.get_element_text('./Id') == '1'
|
assert invoice.get_element_text('./Id') == '1'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_replacement_for():
|
def test_facho_xml_replacement_for():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.placeholder_for('./child/type')
|
xml.placeholder_for('./child/type')
|
||||||
@@ -227,47 +192,37 @@ def test_facho_xml_replacement_for():
|
|||||||
'./child/code', 'test')
|
'./child/code', 'test')
|
||||||
assert xml.tostring() == '<root><child><code>test</code></child></root>'
|
assert xml.tostring() == '<root><child><code>test</code></child></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_set_element_content_invalid_validation():
|
def test_facho_xml_set_element_content_invalid_validation():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
with pytest.raises(facho.FachoValueInvalid):
|
with pytest.raises(facho.FachoValueInvalid) as e:
|
||||||
xml.set_element_validator('./Id', lambda text, attrs: text == 'mero')
|
xml.set_element_validator('./Id', lambda text, attrs: text == 'mero')
|
||||||
xml.set_element('./Id', 'bad')
|
xml.set_element('./Id', 'bad')
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_set_element_content_valid_validation():
|
def test_facho_xml_set_element_content_valid_validation():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
xml.set_element_validator('./Id', lambda text, attrs: text == 'mero')
|
xml.set_element_validator('./Id', lambda text, attrs: text == 'mero')
|
||||||
xml.set_element('./Id', 'mero')
|
xml.set_element('./Id', 'mero')
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_set_element_attribute_invalid_validation():
|
def test_facho_xml_set_element_attribute_invalid_validation():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
with pytest.raises(facho.FachoValueInvalid):
|
with pytest.raises(facho.FachoValueInvalid) as e:
|
||||||
xml.set_element_validator(
|
xml.set_element_validator('./Id', lambda text, attrs: attrs['code'] == 'ABC')
|
||||||
'./Id', lambda text, attrs: attrs['code'] == 'ABC')
|
xml.set_element('./Id', 'mero', code = 'CBA')
|
||||||
xml.set_element('./Id', 'mero', code='CBA')
|
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_set_element_attribute_valid_validation():
|
def test_facho_xml_set_element_attribute_valid_validation():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
xml.set_element_validator(
|
xml.set_element_validator('./Id', lambda text, attrs: attrs['code'] == 'ABC')
|
||||||
'./Id',
|
xml.set_element('./Id', 'mero', code = 'ABC')
|
||||||
lambda text,
|
|
||||||
attrs: attrs['code'] == 'ABC')
|
|
||||||
xml.set_element('./Id', 'mero', code='ABC')
|
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_get_element_attribute():
|
def test_facho_xml_get_element_attribute():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.set_element('./Id', 'mero', code='ABC')
|
xml.set_element('./Id', 'mero', code = 'ABC')
|
||||||
assert xml.get_element_attribute('/root/Id', 'code') == 'ABC'
|
assert xml.get_element_attribute('/root/Id', 'code') == 'ABC'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_keep_orden_slibing():
|
def test_facho_xml_keep_orden_slibing():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.find_or_create_element('./A')
|
xml.find_or_create_element('./A')
|
||||||
@@ -278,16 +233,14 @@ def test_facho_xml_keep_orden_slibing():
|
|||||||
|
|
||||||
assert xml.tostring() == '<root><A/><A/><B/><B/><C/></root>'
|
assert xml.tostring() == '<root><A/><A/><B/><B/><C/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_placeholder_optional():
|
def test_facho_xml_placeholder_optional():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.placeholder_for('./A')
|
xml.placeholder_for('./A')
|
||||||
xml.placeholder_for('./B', optional=True)
|
xml.placeholder_for('./B', optional=True)
|
||||||
xml.placeholder_for('./C')
|
xml.placeholder_for('./C')
|
||||||
|
|
||||||
assert xml.tostring() == '<root><A/><C/></root>'
|
assert xml.tostring() == '<root><A/><C/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_placeholder_append_to_optional():
|
def test_facho_xml_placeholder_append_to_optional():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.placeholder_for('./A')
|
xml.placeholder_for('./A')
|
||||||
@@ -297,7 +250,6 @@ def test_facho_xml_placeholder_append_to_optional():
|
|||||||
xml.find_or_create_element('./B')
|
xml.find_or_create_element('./B')
|
||||||
assert xml.tostring() == '<root><A/><B/><C/></root>'
|
assert xml.tostring() == '<root><A/><B/><C/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_placeholder_set_element_to_optional():
|
def test_facho_xml_placeholder_set_element_to_optional():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.placeholder_for('./A')
|
xml.placeholder_for('./A')
|
||||||
@@ -307,7 +259,6 @@ def test_facho_xml_placeholder_set_element_to_optional():
|
|||||||
xml.set_element('./B', '2')
|
xml.set_element('./B', '2')
|
||||||
assert xml.tostring() == '<root><A/><B>2</B><C/></root>'
|
assert xml.tostring() == '<root><A/><B>2</B><C/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_placeholder_set_element_to_optional_with_append():
|
def test_facho_xml_placeholder_set_element_to_optional_with_append():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.placeholder_for('./A')
|
xml.placeholder_for('./A')
|
||||||
@@ -324,8 +275,8 @@ def test_facho_xml_set_attributes():
|
|||||||
xml.find_or_create_element('./A')
|
xml.find_or_create_element('./A')
|
||||||
|
|
||||||
xml.set_attributes('./A',
|
xml.set_attributes('./A',
|
||||||
value1='1',
|
value1 = '1',
|
||||||
value2='2'
|
value2 = '2'
|
||||||
)
|
)
|
||||||
assert xml.get_element_attribute('/root/A', 'value1') == '1'
|
assert xml.get_element_attribute('/root/A', 'value1') == '1'
|
||||||
assert xml.get_element_attribute('/root/A', 'value2') == '2'
|
assert xml.get_element_attribute('/root/A', 'value2') == '2'
|
||||||
@@ -336,14 +287,13 @@ def test_facho_xml_set_attributes_not_set_optional():
|
|||||||
xml.find_or_create_element('./A')
|
xml.find_or_create_element('./A')
|
||||||
|
|
||||||
xml.set_attributes('./A',
|
xml.set_attributes('./A',
|
||||||
value1=None,
|
value1 = None,
|
||||||
value2='2'
|
value2 = '2'
|
||||||
)
|
)
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
xml.get_element_attribute('/root/A', 'value1')
|
xml.get_element_attribute('/root/A', 'value1')
|
||||||
assert xml.get_element_attribute('/root/A', 'value2') == '2'
|
assert xml.get_element_attribute('/root/A', 'value2') == '2'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_placeholder_with_fragment():
|
def test_facho_xml_placeholder_with_fragment():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.placeholder_for('./A')
|
xml.placeholder_for('./A')
|
||||||
@@ -355,10 +305,8 @@ def test_facho_xml_placeholder_with_fragment():
|
|||||||
AA.find_or_create_element('./B', append=True)
|
AA.find_or_create_element('./B', append=True)
|
||||||
|
|
||||||
AA = xml.fragment('./AA/Child', append=True)
|
AA = xml.fragment('./AA/Child', append=True)
|
||||||
|
|
||||||
assert xml.tostring() == (
|
assert xml.tostring() == '<root><A/><AA><Child><B/><B/></Child><Child/></AA><AAA/></root>'
|
||||||
'<root><A/><AA><Child><B/><B/></Child><Child/></AA><AAA/></root>')
|
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_create_on_first_append():
|
def test_facho_xml_create_on_first_append():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
@@ -366,7 +314,6 @@ def test_facho_xml_create_on_first_append():
|
|||||||
xml.find_or_create_element('./A', append=True)
|
xml.find_or_create_element('./A', append=True)
|
||||||
assert xml.tostring() == '<root><A/></root>'
|
assert xml.tostring() == '<root><A/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_create_on_first_append_multiple_appends():
|
def test_facho_xml_create_on_first_append_multiple_appends():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
@@ -377,7 +324,6 @@ def test_facho_xml_create_on_first_append_multiple_appends():
|
|||||||
xml.find_or_create_element('./C', append=True)
|
xml.find_or_create_element('./C', append=True)
|
||||||
assert xml.tostring() == '<root><B/><A/><A/><A/><C/></root>'
|
assert xml.tostring() == '<root><B/><A/><A/><A/><C/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_fragment_create_on_first_append():
|
def test_facho_xml_fragment_create_on_first_append():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
@@ -387,7 +333,6 @@ def test_facho_xml_fragment_create_on_first_append():
|
|||||||
A.find_or_create_element('./C')
|
A.find_or_create_element('./C')
|
||||||
assert xml.tostring() == '<root><A><B/></A><A><C/></A></root>'
|
assert xml.tostring() == '<root><A><B/></A><A><C/></A></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_placeholder_optional_and_fragment():
|
def test_facho_xml_placeholder_optional_and_fragment():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
@@ -401,7 +346,6 @@ def test_facho_xml_placeholder_optional_and_fragment():
|
|||||||
|
|
||||||
assert xml.tostring() == '<root><A><AA><B/><C/></AA></A></root>'
|
assert xml.tostring() == '<root><A><AA><B/><C/></AA></A></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_placeholder_optional_and_set_attributes():
|
def test_facho_xml_placeholder_optional_and_set_attributes():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
xml.placeholder_for('./A')
|
xml.placeholder_for('./A')
|
||||||
@@ -410,7 +354,6 @@ def test_facho_xml_placeholder_optional_and_set_attributes():
|
|||||||
assert xml.get_element_attribute('/root/A', 'prueba') == 'OK'
|
assert xml.get_element_attribute('/root/A', 'prueba') == 'OK'
|
||||||
assert xml.tostring() == '<root><A prueba="OK"/></root>'
|
assert xml.tostring() == '<root><A prueba="OK"/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_placeholder_optional_and_fragment_with_set_element():
|
def test_facho_xml_placeholder_optional_and_fragment_with_set_element():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
@@ -422,19 +365,17 @@ def test_facho_xml_placeholder_optional_and_fragment_with_set_element():
|
|||||||
assert xml.tostring() == '<root><A><AA prueba="OK"/></A></root>'
|
assert xml.tostring() == '<root><A><AA prueba="OK"/></A></root>'
|
||||||
assert xml.get_element_attribute('/root/A/AA', 'prueba') == 'OK'
|
assert xml.get_element_attribute('/root/A/AA', 'prueba') == 'OK'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_exist_element():
|
def test_facho_xml_exist_element():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
xml.placeholder_for('./A')
|
xml.placeholder_for('./A')
|
||||||
assert xml.exist_element('/root/A') is False
|
assert xml.exist_element('/root/A') == False
|
||||||
assert xml.tostring() == '<root><A/></root>'
|
assert xml.tostring() == '<root><A/></root>'
|
||||||
|
|
||||||
xml.find_or_create_element('./A')
|
xml.find_or_create_element('./A')
|
||||||
assert xml.exist_element('/root/A')
|
assert xml.exist_element('/root/A') == True
|
||||||
assert xml.tostring() == '<root><A/></root>'
|
assert xml.tostring() == '<root><A/></root>'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_query_element_text_or_attribute():
|
def test_facho_xml_query_element_text_or_attribute():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
@@ -443,7 +384,6 @@ def test_facho_xml_query_element_text_or_attribute():
|
|||||||
assert xml.get_element_text_or_attribute('/root/A') == 'contenido'
|
assert xml.get_element_text_or_attribute('/root/A') == 'contenido'
|
||||||
assert xml.get_element_text_or_attribute('/root/A/@clave') == 'valor'
|
assert xml.get_element_text_or_attribute('/root/A/@clave') == 'valor'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_query_element_text_or_attribute_from_fragment():
|
def test_facho_xml_query_element_text_or_attribute_from_fragment():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
@@ -452,7 +392,6 @@ def test_facho_xml_query_element_text_or_attribute_from_fragment():
|
|||||||
|
|
||||||
assert invoice.get_element_text_or_attribute('/Invoice/A') == 'contenido'
|
assert invoice.get_element_text_or_attribute('/Invoice/A') == 'contenido'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_build_xml_absolute():
|
def test_facho_xml_build_xml_absolute():
|
||||||
xml = facho.FachoXML('root')
|
xml = facho.FachoXML('root')
|
||||||
|
|
||||||
@@ -461,23 +400,18 @@ def test_facho_xml_build_xml_absolute():
|
|||||||
|
|
||||||
|
|
||||||
def test_facho_xml_build_xml_absolute_namespace():
|
def test_facho_xml_build_xml_absolute_namespace():
|
||||||
xml = facho.FachoXML(
|
xml = facho.FachoXML('{%s}root' % ('http://www.dian.gov.co/contratos/facturaelectronica/v1'),
|
||||||
'{%s}root' %
|
nsmap={'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1'})
|
||||||
('http://www.dian.gov.co/contratos/facturaelectronica/v1'),
|
|
||||||
nsmap={
|
|
||||||
'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1'})
|
|
||||||
|
|
||||||
xpath = xml.xpath_from_root('/A')
|
xpath = xml.xpath_from_root('/A')
|
||||||
assert xpath == '/fe:root/A'
|
assert xpath == '/fe:root/A'
|
||||||
|
|
||||||
|
|
||||||
def test_facho_xml_build_xml_absolute_namespace_from_fragment():
|
def test_facho_xml_build_xml_absolute_namespace_from_fragment():
|
||||||
xml = facho.FachoXML(
|
xml = facho.FachoXML('{%s}root' % ('http://www.dian.gov.co/contratos/facturaelectronica/v1'),
|
||||||
'{%s}root' %
|
nsmap={'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1'})
|
||||||
('http://www.dian.gov.co/contratos/facturaelectronica/v1'),
|
|
||||||
nsmap={
|
|
||||||
'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1'})
|
|
||||||
invoice = xml.fragment('/root/Invoice')
|
invoice = xml.fragment('/root/Invoice')
|
||||||
|
|
||||||
xpath = invoice.xpath_from_root('/A')
|
xpath = invoice.xpath_from_root('/A')
|
||||||
assert xpath == '/fe:root/Invoice/A'
|
assert xpath == '/fe:root/Invoice/A'
|
||||||
|
|
||||||
|
|||||||
109
tests/test_fe.py
109
tests/test_fe.py
@@ -4,14 +4,16 @@
|
|||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
import pytest
|
||||||
from facho import fe
|
from facho import fe
|
||||||
|
|
||||||
|
|
||||||
|
import helpers
|
||||||
|
|
||||||
|
|
||||||
def test_xmlsigned_build(monkeypatch):
|
def test_xmlsigned_build(monkeypatch):
|
||||||
# openssl req -x509 -sha256 -nodes -subj "/CN=test" -days 1
|
#openssl req -x509 -sha256 -nodes -subj "/CN=test" -days 1 -newkey rsa:2048 -keyout example.key -out example.pem
|
||||||
# -newkey rsa:2048 -keyout example.key -out example.pem
|
#openssl pkcs12 -export -out example.p12 -inkey example.key -in example.pem
|
||||||
# openssl pkcs12 -export -out example.p12 -inkey example.key -in
|
|
||||||
# example.pem
|
|
||||||
signer = fe.DianXMLExtensionSigner('./tests/example.p12')
|
signer = fe.DianXMLExtensionSigner('./tests/example.p12')
|
||||||
|
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
@@ -19,90 +21,68 @@ def test_xmlsigned_build(monkeypatch):
|
|||||||
|
|
||||||
signer.sign_xml_element(xml.root)
|
signer.sign_xml_element(xml.root)
|
||||||
|
|
||||||
elem = xml.find_or_create_element(
|
elem = xml.find_or_create_element('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/ds:Signature')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent'
|
|
||||||
'/ds:Signature')
|
|
||||||
|
|
||||||
assert elem is not None
|
assert elem is not None
|
||||||
# assert elem.findall('ds:SignedInfo', fe.NAMESPACES) is not None
|
#assert elem.findall('ds:SignedInfo', fe.NAMESPACES) is not None
|
||||||
|
|
||||||
|
|
||||||
def test_xmlsigned_with_passphrase_build(monkeypatch):
|
def test_xmlsigned_with_passphrase_build(monkeypatch):
|
||||||
# openssl req -x509 -sha256 -nodes -subj "/CN=test" -days 1
|
#openssl req -x509 -sha256 -nodes -subj "/CN=test" -days 1 -newkey rsa:2048 -keyout example.key -out example.pem
|
||||||
# -newkey rsa:2048 -keyout example.key -out example.pem
|
#openssl pkcs12 -export -out example.p12 -inkey example.key -in example.pem
|
||||||
# openssl pkcs12 -export -out example.p12 -inkey example.key -in
|
signer = fe.DianXMLExtensionSigner('./tests/example-with-passphrase.p12', 'test')
|
||||||
# example.pem
|
|
||||||
signer = fe.DianXMLExtensionSigner(
|
|
||||||
'./tests/example-with-passphrase.p12', 'test')
|
|
||||||
|
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
|
|
||||||
signer.sign_xml_element(xml.root)
|
signer.sign_xml_element(xml.root)
|
||||||
|
|
||||||
elem = xml.find_or_create_element(
|
elem = xml.find_or_create_element('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/ds:Signature')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent'
|
|
||||||
'/ds:Signature')
|
|
||||||
|
|
||||||
assert elem is not None
|
assert elem is not None
|
||||||
# assert elem.findall('ds:SignedInfo', fe.NAMESPACES) is not None
|
#assert elem.findall('ds:SignedInfo', fe.NAMESPACES) is not None
|
||||||
|
|
||||||
|
|
||||||
def test_dian_extension_software_security_code():
|
def test_dian_extension_software_security_code():
|
||||||
security_code = fe.DianXMLExtensionSoftwareSecurityCode(
|
security_code = fe.DianXMLExtensionSoftwareSecurityCode('idsoftware', '1234', '1')
|
||||||
'idsoftware', '1234', '1')
|
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
xml.add_extension(security_code)
|
xml.add_extension(security_code)
|
||||||
content = xml.get_element_text(
|
content = xml.get_element_text('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareSecurityCode')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent'
|
|
||||||
'/sts:DianExtensions/sts:SoftwareSecurityCode')
|
|
||||||
assert content is not None
|
assert content is not None
|
||||||
|
|
||||||
|
|
||||||
def test_dian_extension_invoice_authorization():
|
def test_dian_extension_invoice_authorization():
|
||||||
invoice_authorization = '18762002346472'
|
invoice_authorization = '18762002346472'
|
||||||
inv_auth_ext = fe.DianXMLExtensionInvoiceAuthorization(
|
inv_auth_ext = fe.DianXMLExtensionInvoiceAuthorization(invoice_authorization,
|
||||||
invoice_authorization, datetime(
|
datetime(2017, 2, 23),
|
||||||
2017, 2, 23), datetime(
|
datetime(2019, 8, 23),
|
||||||
2019, 8, 23), 'MD', 100001, 174999)
|
'MD', 100001, 174999)
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
xml.add_extension(inv_auth_ext)
|
xml.add_extension(inv_auth_ext)
|
||||||
auth = xml.get_element_text(
|
auth = xml.get_element_text('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceControl/sts:InvoiceAuthorization')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent'
|
|
||||||
'/sts:DianExtensions/sts:InvoiceControl/sts:InvoiceAuthorization')
|
|
||||||
assert auth == invoice_authorization
|
assert auth == invoice_authorization
|
||||||
|
|
||||||
|
|
||||||
def test_dian_extension_software_provider():
|
def test_dian_extension_software_provider():
|
||||||
nit = '123456789'
|
nit = '123456789'
|
||||||
id_software = 'ABCDASDF123'
|
id_software = 'ABCDASDF123'
|
||||||
software_provider_extension = fe.DianXMLExtensionSoftwareProvider(
|
software_provider_extension = fe.DianXMLExtensionSoftwareProvider(nit, '', id_software)
|
||||||
nit, '', id_software)
|
|
||||||
|
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
xml.add_extension(software_provider_extension)
|
xml.add_extension(software_provider_extension)
|
||||||
|
|
||||||
give_nit = xml.get_element_text(
|
give_nit = xml.get_element_text('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider/sts:ProviderID')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent'
|
|
||||||
'/sts:DianExtensions/sts:SoftwareProvider/sts:ProviderID')
|
|
||||||
assert nit == give_nit
|
assert nit == give_nit
|
||||||
|
|
||||||
|
|
||||||
def test_dian_extension_authorization_provider():
|
def test_dian_extension_authorization_provider():
|
||||||
auth_provider_extension = fe.DianXMLExtensionAuthorizationProvider()
|
auth_provider_extension = fe.DianXMLExtensionAuthorizationProvider()
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
xml.add_extension(auth_provider_extension)
|
xml.add_extension(auth_provider_extension)
|
||||||
dian_nit = xml.get_element_text(
|
dian_nit = xml.get_element_text('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider/sts:AuthorizationProviderID')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/'
|
|
||||||
'ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider/'
|
|
||||||
'sts:AuthorizationProviderID')
|
|
||||||
assert dian_nit == '800197268'
|
assert dian_nit == '800197268'
|
||||||
|
|
||||||
|
|
||||||
def test_dian_invoice_without_namespace_in_root():
|
def test_dian_invoice_without_namespace_in_root():
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
@@ -112,14 +92,10 @@ def test_dian_invoice_without_namespace_in_root():
|
|||||||
|
|
||||||
def test_xml_sign_dian(monkeypatch):
|
def test_xml_sign_dian(monkeypatch):
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
xml.find_or_create_element(
|
xml.find_or_create_element('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
ublextension = xml.fragment('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension', append=True)
|
||||||
ublextension = xml.fragment(
|
extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension',
|
|
||||||
append=True)
|
|
||||||
ublextension.find_or_create_element(
|
|
||||||
'/ext:UBLExtension/ext:ExtensionContent')
|
|
||||||
|
|
||||||
xmlstring = xml.tostring()
|
xmlstring = xml.tostring()
|
||||||
print(xmlstring)
|
print(xmlstring)
|
||||||
@@ -127,17 +103,12 @@ def test_xml_sign_dian(monkeypatch):
|
|||||||
xmlsigned = signer.sign_xml_string(xmlstring)
|
xmlsigned = signer.sign_xml_string(xmlstring)
|
||||||
assert "Signature" in xmlsigned
|
assert "Signature" in xmlsigned
|
||||||
|
|
||||||
|
|
||||||
def test_xml_sign_dian_using_bytes(monkeypatch):
|
def test_xml_sign_dian_using_bytes(monkeypatch):
|
||||||
xml = fe.FeXML('Invoice',
|
xml = fe.FeXML('Invoice',
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
xml.find_or_create_element(
|
xml.find_or_create_element('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
ublextension = xml.fragment('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension', append=True)
|
||||||
ublextension = xml.fragment(
|
extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension',
|
|
||||||
append=True)
|
|
||||||
ublextension.find_or_create_element(
|
|
||||||
'/ext:UBLExtension/ext:ExtensionContent')
|
|
||||||
|
|
||||||
xmlstring = xml.tostring()
|
xmlstring = xml.tostring()
|
||||||
p12_data = open('./tests/example.p12', 'rb').read()
|
p12_data = open('./tests/example.p12', 'rb').read()
|
||||||
@@ -145,21 +116,3 @@ def test_xml_sign_dian_using_bytes(monkeypatch):
|
|||||||
|
|
||||||
xmlsigned = signer.sign_xml_string(xmlstring)
|
xmlsigned = signer.sign_xml_string(xmlstring)
|
||||||
assert "Signature" in xmlsigned
|
assert "Signature" in xmlsigned
|
||||||
|
|
||||||
|
|
||||||
def test_xml_signature_timestamp(monkeypatch):
|
|
||||||
xml = fe.FeXML(
|
|
||||||
'Invoice',
|
|
||||||
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
|
||||||
xml.find_or_create_element(
|
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
|
||||||
ublextension = xml.fragment(
|
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension', append=True)
|
|
||||||
ublextension.find_or_create_element(
|
|
||||||
'/ext:UBLExtension/ext:ExtensionContent')
|
|
||||||
xmlstring = xml.tostring()
|
|
||||||
signer = fe.DianXMLExtensionSigner('./tests/example.p12')
|
|
||||||
xmlsigned = signer.sign_xml_string(xmlstring)
|
|
||||||
|
|
||||||
with open('invoice.xml', 'w') as file_:
|
|
||||||
file_.write(xmlsigned)
|
|
||||||
|
|||||||
@@ -5,49 +5,24 @@
|
|||||||
|
|
||||||
"""Tests for `facho` package."""
|
"""Tests for `facho` package."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import io
|
import io
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
import facho.fe.form as form
|
import facho.fe.form as form
|
||||||
from facho import fe
|
from facho import fe
|
||||||
from facho.fe.form_xml import (
|
from facho.fe.form_xml import DIANInvoiceXML, DIANCreditNoteXML, DIANDebitNoteXML
|
||||||
DIANInvoiceXML, DIANCreditNoteXML, DIANDebitNoteXML)
|
|
||||||
|
|
||||||
from fixtures import (
|
|
||||||
simple_invoice,
|
|
||||||
simple_invoice_without_lines,
|
|
||||||
simple_credit_note_without_lines,
|
|
||||||
simple_debit_note_without_lines)
|
|
||||||
|
|
||||||
try:
|
|
||||||
CUDE_ = open("./tests/cude.txt", 'r').read().strip()
|
|
||||||
except FileNotFoundError:
|
|
||||||
raise Exception("Archivo Cude No encontrado")
|
|
||||||
|
|
||||||
CUFE_ = (
|
|
||||||
'8bb918b19ba22a694f1da'
|
|
||||||
'11c643b5e9de39adf60311c'
|
|
||||||
'f179179e9b33381030bcd4c3c'
|
|
||||||
'3f156c506ed5908f9276f5bd9b4')
|
|
||||||
|
|
||||||
simple_invoice = simple_invoice
|
|
||||||
simple_invoice_without_lines = simple_invoice_without_lines
|
|
||||||
simple_credit_note_without_lines = simple_credit_note_without_lines
|
|
||||||
simple_debit_note_without_lines = simple_debit_note_without_lines
|
|
||||||
|
|
||||||
|
from fixtures import *
|
||||||
|
|
||||||
def test_invoicesimple_build(simple_invoice):
|
def test_invoicesimple_build(simple_invoice):
|
||||||
xml = DIANInvoiceXML(simple_invoice)
|
xml = DIANInvoiceXML(simple_invoice)
|
||||||
|
|
||||||
supplier_name = xml.get_element_text(
|
supplier_name = xml.get_element_text('/fe:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name')
|
||||||
'/fe:Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc'
|
|
||||||
':Name')
|
|
||||||
assert supplier_name == simple_invoice.invoice_supplier.name
|
assert supplier_name == simple_invoice.invoice_supplier.name
|
||||||
|
|
||||||
customer_name = xml.get_element_text(
|
customer_name = xml.get_element_text('/fe:Invoice/cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name')
|
||||||
'/fe:Invoice/cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc'
|
|
||||||
':Name')
|
|
||||||
assert customer_name == simple_invoice.invoice_customer.name
|
assert customer_name == simple_invoice.invoice_customer.name
|
||||||
|
|
||||||
|
|
||||||
@@ -67,27 +42,22 @@ def test_invoicesimple_xml_signed(monkeypatch, simple_invoice):
|
|||||||
print(xml.tostring())
|
print(xml.tostring())
|
||||||
xml.add_extension(signer)
|
xml.add_extension(signer)
|
||||||
|
|
||||||
elem = xml.get_element(
|
elem = xml.get_element('/fe:Invoice/ext:UBLExtensions/ext:UBLExtension[2]/ext:ExtensionContent/ds:Signature')
|
||||||
'/fe:Invoice/ext:UBLExtensions/ext:UBLExtension[2]/ext'
|
|
||||||
':ExtensionContent/ds:Signature')
|
|
||||||
assert elem.text is not None
|
assert elem.text is not None
|
||||||
|
|
||||||
|
|
||||||
def test_invoicesimple_zip(simple_invoice):
|
def test_invoicesimple_zip(simple_invoice):
|
||||||
xml_invoice = DIANInvoiceXML(simple_invoice)
|
xml_invoice = DIANInvoiceXML(simple_invoice)
|
||||||
|
|
||||||
zipdata = io.BytesIO()
|
zipdata = io.BytesIO()
|
||||||
with fe.DianZIP(zipdata) as dianzip:
|
with fe.DianZIP(zipdata) as dianzip:
|
||||||
name_invoice = dianzip.add_invoice_xml(
|
name_invoice = dianzip.add_invoice_xml(simple_invoice.invoice_ident, str(xml_invoice))
|
||||||
simple_invoice.invoice_ident, str(xml_invoice))
|
|
||||||
|
|
||||||
# el zip ademas de archivar debe comprimir los archivos
|
# el zip ademas de archivar debe comprimir los archivos
|
||||||
# de lo contrario la DIAN lo rechaza
|
# de lo contrario la DIAN lo rechaza
|
||||||
with zipfile.ZipFile(zipdata) as dianzip:
|
with zipfile.ZipFile(zipdata) as dianzip:
|
||||||
dianzip.testzip()
|
dianzip.testzip()
|
||||||
for zipinfo in dianzip.infolist():
|
for zipinfo in dianzip.infolist():
|
||||||
assert zipinfo.compress_type == zipfile.ZIP_DEFLATED, (
|
assert zipinfo.compress_type == zipfile.ZIP_DEFLATED, "se espera el zip comprimido"
|
||||||
"se espera el zip comprimido")
|
|
||||||
|
|
||||||
with zipfile.ZipFile(zipdata) as dianzip:
|
with zipfile.ZipFile(zipdata) as dianzip:
|
||||||
xml_data = dianzip.open(name_invoice).read().decode('utf-8')
|
xml_data = dianzip.open(name_invoice).read().decode('utf-8')
|
||||||
@@ -96,86 +66,66 @@ def test_invoicesimple_zip(simple_invoice):
|
|||||||
|
|
||||||
def test_bug_cbcid_empty_on_invoice_line(simple_invoice):
|
def test_bug_cbcid_empty_on_invoice_line(simple_invoice):
|
||||||
xml_invoice = DIANInvoiceXML(simple_invoice)
|
xml_invoice = DIANInvoiceXML(simple_invoice)
|
||||||
cbc_id = xml_invoice.get_element_text(
|
cbc_id = xml_invoice.get_element_text('/fe:Invoice/cac:InvoiceLine[1]/cbc:ID', format_=int)
|
||||||
'/fe:Invoice/cac:InvoiceLine[1]/cbc:ID', format_=int)
|
|
||||||
assert cbc_id == 1
|
assert cbc_id == 1
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_line_count_numeric(simple_invoice):
|
def test_invoice_line_count_numeric(simple_invoice):
|
||||||
xml_invoice = DIANInvoiceXML(simple_invoice)
|
xml_invoice = DIANInvoiceXML(simple_invoice)
|
||||||
count = xml_invoice.get_element_text(
|
count = xml_invoice.get_element_text('/fe:Invoice/cbc:LineCountNumeric', format_=int)
|
||||||
'/fe:Invoice/cbc:LineCountNumeric', format_=int)
|
|
||||||
assert count == len(simple_invoice.invoice_lines)
|
assert count == len(simple_invoice.invoice_lines)
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_profileexecutionid(simple_invoice):
|
def test_invoice_profileexecutionid(simple_invoice):
|
||||||
xml_invoice = DIANInvoiceXML(simple_invoice)
|
xml_invoice = DIANInvoiceXML(simple_invoice)
|
||||||
cufe_extension = fe.DianXMLExtensionCUFE(simple_invoice)
|
cufe_extension = fe.DianXMLExtensionCUFE(simple_invoice)
|
||||||
xml_invoice.add_extension(cufe_extension)
|
xml_invoice.add_extension(cufe_extension)
|
||||||
id_ = xml_invoice.get_element_text(
|
id_ = xml_invoice.get_element_text('/fe:Invoice/cbc:ProfileExecutionID', format_=int)
|
||||||
'/fe:Invoice/cbc:ProfileExecutionID', format_=int)
|
|
||||||
assert id_ == 2
|
assert id_ == 2
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_invoice_type_code(simple_invoice):
|
def test_invoice_invoice_type_code(simple_invoice):
|
||||||
xml_invoice = DIANInvoiceXML(simple_invoice)
|
xml_invoice = DIANInvoiceXML(simple_invoice)
|
||||||
id_ = xml_invoice.get_element_text(
|
id_ = xml_invoice.get_element_text('/fe:Invoice/cbc:InvoiceTypeCode', format_=int)
|
||||||
'/fe:Invoice/cbc:InvoiceTypeCode', format_=int)
|
|
||||||
assert id_ == 1
|
assert id_ == 1
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_totals(simple_invoice_without_lines):
|
def test_invoice_totals(simple_invoice_without_lines):
|
||||||
simple_invoice = simple_invoice_without_lines
|
simple_invoice = simple_invoice_without_lines
|
||||||
simple_invoice.invoice_ident = '323200000129'
|
simple_invoice.invoice_ident = '323200000129'
|
||||||
simple_invoice.invoice_issue = datetime.strptime(
|
simple_invoice.invoice_issue = datetime.strptime('2019-01-16 10:53:10-05:00', '%Y-%m-%d %H:%M:%S%z')
|
||||||
'2019-01-16 10:53:10-05:00', '%Y-%m-%d %H:%M:%S%z')
|
|
||||||
simple_invoice.invoice_supplier.ident = '700085371'
|
simple_invoice.invoice_supplier.ident = '700085371'
|
||||||
simple_invoice.invoice_customer.ident = '800199436'
|
simple_invoice.invoice_customer.ident = '800199436'
|
||||||
simple_invoice.add_invoice_line(form.InvoiceLine(
|
simple_invoice.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
description='producto',
|
description = 'producto',
|
||||||
item=form.StandardItem(9999),
|
item = form.StandardItem(9999),
|
||||||
price=form.Price(form.Amount(1_500_000), '01', ''),
|
price = form.Price(form.Amount(1_500_000), '01', ''),
|
||||||
tax=form.TaxTotal(
|
tax = form.TaxTotal(
|
||||||
subtotals=[
|
subtotals = [
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
scheme=form.TaxScheme('01'),
|
scheme = form.TaxScheme('01'),
|
||||||
percent=19.0
|
percent = 19.0
|
||||||
)]),
|
)])
|
||||||
withholding=form.WithholdingTaxTotal(
|
|
||||||
subtotals=[])
|
|
||||||
))
|
))
|
||||||
simple_invoice.calculate()
|
simple_invoice.calculate()
|
||||||
assert 1 == len(simple_invoice.invoice_lines)
|
assert 1 == len(simple_invoice.invoice_lines)
|
||||||
assert form.Amount(1_500_000) == (
|
assert form.Amount(1_500_000) == simple_invoice.invoice_legal_monetary_total.line_extension_amount
|
||||||
simple_invoice.invoice_legal_monetary_total.line_extension_amount)
|
assert form.Amount(1_785_000) == simple_invoice.invoice_legal_monetary_total.payable_amount
|
||||||
assert form.Amount(1_785_000) == (
|
|
||||||
simple_invoice.invoice_legal_monetary_total.payable_amount)
|
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_cufe(simple_invoice_without_lines):
|
def test_invoice_cufe(simple_invoice_without_lines):
|
||||||
simple_invoice = simple_invoice_without_lines
|
simple_invoice = simple_invoice_without_lines
|
||||||
simple_invoice.invoice_ident = '323200000129'
|
simple_invoice.invoice_ident = '323200000129'
|
||||||
simple_invoice.invoice_issue = datetime.strptime(
|
simple_invoice.invoice_issue = datetime.strptime('2019-01-16 10:53:10-05:00', '%Y-%m-%d %H:%M:%S%z')
|
||||||
'2019-01-16 10:53:10-05:00', '%Y-%m-%d %H:%M:%S%z')
|
simple_invoice.invoice_supplier.ident = form.PartyIdentification('700085371', '5', '31')
|
||||||
simple_invoice.invoice_supplier.ident = form.PartyIdentification(
|
simple_invoice.invoice_customer.ident = form.PartyIdentification('800199436', '5', '31')
|
||||||
'700085371', '5', '31')
|
|
||||||
simple_invoice.invoice_customer.ident = form.PartyIdentification(
|
|
||||||
'800199436', '5', '31')
|
|
||||||
simple_invoice.add_invoice_line(form.InvoiceLine(
|
simple_invoice.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(
|
quantity = form.Quantity(1.00, '94'),
|
||||||
1.00, '94'),
|
description = 'producto',
|
||||||
description='producto',
|
item = form.StandardItem(111),
|
||||||
item=form.StandardItem(111),
|
price = form.Price(form.Amount(1_500_000), '01', ''),
|
||||||
price=form.Price(form.Amount(1_500_000), '01', ''),
|
tax = form.TaxTotal(
|
||||||
tax=form.TaxTotal(
|
subtotals = [
|
||||||
subtotals=[
|
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
scheme=form.TaxScheme('01'),
|
scheme = form.TaxScheme('01'),
|
||||||
percent=19.0
|
percent = 19.0
|
||||||
)]),
|
)])
|
||||||
withholding=form.WithholdingTaxTotal(
|
|
||||||
subtotals=[])
|
|
||||||
))
|
))
|
||||||
|
|
||||||
simple_invoice.calculate()
|
simple_invoice.calculate()
|
||||||
@@ -183,87 +133,65 @@ def test_invoice_cufe(simple_invoice_without_lines):
|
|||||||
|
|
||||||
cufe_extension = fe.DianXMLExtensionCUFE(
|
cufe_extension = fe.DianXMLExtensionCUFE(
|
||||||
simple_invoice,
|
simple_invoice,
|
||||||
tipo_ambiente=fe.AMBIENTE_PRODUCCION,
|
tipo_ambiente = fe.AMBIENTE_PRODUCCION,
|
||||||
clave_tecnica='693ff6f2a553c3646a063436fd4dd9ded0311471'
|
clave_tecnica = '693ff6f2a553c3646a063436fd4dd9ded0311471'
|
||||||
)
|
)
|
||||||
formatVars = cufe_extension.formatVars()
|
formatVars = cufe_extension.formatVars()
|
||||||
|
#NumFac
|
||||||
# NumFac
|
|
||||||
assert formatVars[0] == '323200000129', "NumFac"
|
assert formatVars[0] == '323200000129', "NumFac"
|
||||||
|
#FecFac
|
||||||
# FecFac
|
|
||||||
assert formatVars[1] == '2019-01-16', "FecFac"
|
assert formatVars[1] == '2019-01-16', "FecFac"
|
||||||
|
#HoraFac
|
||||||
# HoraFac
|
|
||||||
assert formatVars[2] == '10:53:10-05:00', "HoraFac"
|
assert formatVars[2] == '10:53:10-05:00', "HoraFac"
|
||||||
|
#ValorBruto
|
||||||
# ValorBruto
|
|
||||||
assert formatVars[3] == '1500000.00', "ValorBruto"
|
assert formatVars[3] == '1500000.00', "ValorBruto"
|
||||||
|
#CodImpuesto1
|
||||||
# CodImpuesto1
|
|
||||||
assert formatVars[4] == '01', "CodImpuesto1"
|
assert formatVars[4] == '01', "CodImpuesto1"
|
||||||
|
#ValorImpuesto1
|
||||||
# ValorImpuesto1
|
|
||||||
assert formatVars[5] == '285000.00', "ValorImpuesto1"
|
assert formatVars[5] == '285000.00', "ValorImpuesto1"
|
||||||
|
#CodImpuesto2
|
||||||
# CodImpuesto2
|
|
||||||
assert formatVars[6] == '04', "CodImpuesto2"
|
assert formatVars[6] == '04', "CodImpuesto2"
|
||||||
|
#ValorImpuesto2
|
||||||
# ValorImpuesto2
|
|
||||||
assert formatVars[7] == '0.00', "ValorImpuesto2"
|
assert formatVars[7] == '0.00', "ValorImpuesto2"
|
||||||
|
#CodImpuesto3
|
||||||
# CodImpuesto3
|
|
||||||
assert formatVars[8] == '03', "CodImpuesto3"
|
assert formatVars[8] == '03', "CodImpuesto3"
|
||||||
|
#ValorImpuesto3
|
||||||
# ValorImpuesto3
|
|
||||||
assert formatVars[9] == '0.00', "ValorImpuesto3"
|
assert formatVars[9] == '0.00', "ValorImpuesto3"
|
||||||
|
#ValTotFac
|
||||||
# ValTotFac
|
|
||||||
assert formatVars[10] == '1785000.00', "ValTotFac"
|
assert formatVars[10] == '1785000.00', "ValTotFac"
|
||||||
|
#NitOFE
|
||||||
# NitOFE
|
|
||||||
assert formatVars[11] == '700085371', "NitOFE"
|
assert formatVars[11] == '700085371', "NitOFE"
|
||||||
|
#NumAdq
|
||||||
# NumAdq
|
|
||||||
assert formatVars[12] == '800199436', "NumAdq"
|
assert formatVars[12] == '800199436', "NumAdq"
|
||||||
|
#ClTec
|
||||||
# ClTec
|
assert formatVars[13] == '693ff6f2a553c3646a063436fd4dd9ded0311471', "ClTec"
|
||||||
assert formatVars[13] == (
|
#TipoAmbiente
|
||||||
'693ff6f2a553c3646a063436fd4dd9ded0311471'), "ClTec"
|
|
||||||
|
|
||||||
# TipoAmbiente
|
|
||||||
assert formatVars[14] == '1', "TipoAmbiente"
|
assert formatVars[14] == '1', "TipoAmbiente"
|
||||||
|
|
||||||
xml_invoice.add_extension(cufe_extension)
|
xml_invoice.add_extension(cufe_extension)
|
||||||
cufe = xml_invoice.get_element_text('/fe:Invoice/cbc:UUID')
|
cufe = xml_invoice.get_element_text('/fe:Invoice/cbc:UUID')
|
||||||
# RESOLUCION 004: pagina 689
|
# RESOLUCION 004: pagina 689
|
||||||
assert cufe == CUFE_
|
assert cufe == '8bb918b19ba22a694f1da11c643b5e9de39adf60311cf179179e9b33381030bcd4c3c3f156c506ed5908f9276f5bd9b4'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_credit_note_cude(simple_credit_note_without_lines):
|
def test_credit_note_cude(simple_credit_note_without_lines):
|
||||||
simple_invoice = simple_credit_note_without_lines
|
simple_invoice = simple_credit_note_without_lines
|
||||||
simple_invoice.invoice_ident = '8110007871'
|
simple_invoice.invoice_ident = '8110007871'
|
||||||
simple_invoice.invoice_issue = datetime.strptime(
|
simple_invoice.invoice_issue = datetime.strptime('2019-01-12 07:00:00-05:00', '%Y-%m-%d %H:%M:%S%z')
|
||||||
'2019-01-12 07:00:00-05:00', '%Y-%m-%d %H:%M:%S%z')
|
simple_invoice.invoice_supplier.ident = form.PartyIdentification('900373076', '5', '31')
|
||||||
simple_invoice.invoice_supplier.ident = form.PartyIdentification(
|
simple_invoice.invoice_customer.ident = form.PartyIdentification('8355990', '5', '31')
|
||||||
'900373076', '5', '31')
|
|
||||||
simple_invoice.invoice_customer.ident = form.PartyIdentification(
|
|
||||||
'8355990', '5', '31')
|
|
||||||
simple_invoice.add_invoice_line(form.InvoiceLine(
|
simple_invoice.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(
|
quantity = form.Quantity(1, '94'),
|
||||||
1, '94'),
|
description = 'producto',
|
||||||
description='producto',
|
item = form.StandardItem(111),
|
||||||
item=form.StandardItem(111),
|
price = form.Price(form.Amount(5_000), '01', ''),
|
||||||
price=form.Price(
|
tax = form.TaxTotal(
|
||||||
form.Amount(5_000), '01', ''),
|
subtotals = [
|
||||||
tax=form.TaxTotal(
|
|
||||||
subtotals=[
|
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
scheme=form.TaxScheme('01'),
|
scheme = form.TaxScheme('01'),
|
||||||
percent=19.0
|
percent = 19.0
|
||||||
)]),
|
)])
|
||||||
withholding=form.WithholdingTaxTotal(
|
|
||||||
subtotals=[])
|
|
||||||
))
|
))
|
||||||
|
|
||||||
simple_invoice.calculate()
|
simple_invoice.calculate()
|
||||||
@@ -272,39 +200,33 @@ def test_credit_note_cude(simple_credit_note_without_lines):
|
|||||||
cude_extension = fe.DianXMLExtensionCUDE(
|
cude_extension = fe.DianXMLExtensionCUDE(
|
||||||
simple_invoice,
|
simple_invoice,
|
||||||
'12301',
|
'12301',
|
||||||
tipo_ambiente=fe.AMBIENTE_PRODUCCION,
|
tipo_ambiente = fe.AMBIENTE_PRODUCCION,
|
||||||
)
|
)
|
||||||
|
|
||||||
xml_invoice.add_extension(cude_extension)
|
xml_invoice.add_extension(cude_extension)
|
||||||
cude = xml_invoice.get_element_text('/fe:CreditNote/cbc:UUID')
|
cude = xml_invoice.get_element_text('/fe:CreditNote/cbc:UUID')
|
||||||
# pag 612
|
# pag 612
|
||||||
|
assert cude == '907e4444decc9e59c160a2fb3b6659b33dc5b632a5008922b9a62f83f757b1c448e47f5867f2b50dbdb96f48c7681168'
|
||||||
assert cude == CUDE_
|
|
||||||
|
|
||||||
|
|
||||||
# pag 614
|
# pag 614
|
||||||
def test_debit_note_cude(simple_debit_note_without_lines):
|
def test_debit_note_cude(simple_debit_note_without_lines):
|
||||||
simple_invoice = simple_debit_note_without_lines
|
simple_invoice = simple_debit_note_without_lines
|
||||||
simple_invoice.invoice_ident = 'ND1001'
|
simple_invoice.invoice_ident = 'ND1001'
|
||||||
simple_invoice.invoice_issue = datetime.strptime(
|
simple_invoice.invoice_issue = datetime.strptime('2019-01-18 10:58:00-05:00', '%Y-%m-%d %H:%M:%S%z')
|
||||||
'2019-01-18 10:58:00-05:00', '%Y-%m-%d %H:%M:%S%z')
|
simple_invoice.invoice_supplier.ident = form.PartyIdentification('900197264', '5', '31')
|
||||||
simple_invoice.invoice_supplier.ident = form.PartyIdentification(
|
simple_invoice.invoice_customer.ident = form.PartyIdentification('10254102', '5', '31')
|
||||||
'900197264', '5', '31')
|
|
||||||
simple_invoice.invoice_customer.ident = form.PartyIdentification(
|
|
||||||
'10254102', '5', '31')
|
|
||||||
simple_invoice.add_invoice_line(form.InvoiceLine(
|
simple_invoice.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
description='producto',
|
description = 'producto',
|
||||||
item=form.StandardItem(111),
|
item = form.StandardItem(111),
|
||||||
price=form.Price(form.Amount(30_000), '01', ''),
|
price = form.Price(form.Amount(30_000), '01', ''),
|
||||||
tax=form.TaxTotal(
|
tax = form.TaxTotal(
|
||||||
subtotals=[
|
subtotals = [
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
scheme=form.TaxScheme('04'),
|
scheme = form.TaxScheme('04'),
|
||||||
percent=8.0
|
percent = 8.0
|
||||||
)]),
|
)])
|
||||||
withholding=form.WithholdingTaxTotal(
|
|
||||||
subtotals=[])
|
|
||||||
))
|
))
|
||||||
|
|
||||||
simple_invoice.calculate()
|
simple_invoice.calculate()
|
||||||
@@ -313,7 +235,7 @@ def test_debit_note_cude(simple_debit_note_without_lines):
|
|||||||
cude_extension = fe.DianXMLExtensionCUDE(
|
cude_extension = fe.DianXMLExtensionCUDE(
|
||||||
simple_invoice,
|
simple_invoice,
|
||||||
'10201',
|
'10201',
|
||||||
tipo_ambiente=fe.AMBIENTE_PRUEBAS,
|
tipo_ambiente = fe.AMBIENTE_PRUEBAS,
|
||||||
)
|
)
|
||||||
build_vars = cude_extension.buildVars()
|
build_vars = cude_extension.buildVars()
|
||||||
assert build_vars['NumFac'] == 'ND1001'
|
assert build_vars['NumFac'] == 'ND1001'
|
||||||
@@ -329,14 +251,10 @@ def test_debit_note_cude(simple_debit_note_without_lines):
|
|||||||
assert build_vars['Software-PIN'] == '10201'
|
assert build_vars['Software-PIN'] == '10201'
|
||||||
assert build_vars['TipoAmb'] == 2
|
assert build_vars['TipoAmb'] == 2
|
||||||
|
|
||||||
cude_composicion = "".join(cude_extension.formatVars())
|
|
||||||
assert cude_composicion == (
|
cude_composicion = "".join(cude_extension.formatVars())
|
||||||
'ND10012019-01-1810:58:00-05:0030000.00010.00042400.00030.0032400.009'
|
assert cude_composicion == 'ND10012019-01-1810:58:00-05:0030000.00010.00042400.00030.0032400.0090019726410254102102012'
|
||||||
'001'
|
|
||||||
'9726410254102102012')
|
|
||||||
|
|
||||||
xml_invoice.add_extension(cude_extension)
|
xml_invoice.add_extension(cude_extension)
|
||||||
cude = xml_invoice.get_element_text('/fe:DebitNote/cbc:UUID')
|
cude = xml_invoice.get_element_text('/fe:DebitNote/cbc:UUID')
|
||||||
assert cude == (
|
assert cude == '3fa73a86d57d9341c536afde1f85c4efd9d4591c2c22bce4dfb0e6b0d2e83b8f047a8bde7098292e9d2493e60d1c31da'
|
||||||
'3fa73a86d57d9341c536afde1f85c4efd9d4591c2c22bce4dfb0e6b0d2e83b8f047a8'
|
|
||||||
'bde7098292e9d2493e60d1c31da')
|
|
||||||
|
|||||||
@@ -6,164 +6,132 @@
|
|||||||
"""Tests for `facho` package."""
|
"""Tests for `facho` package."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
# from datetime import datetime
|
from datetime import datetime
|
||||||
# import io
|
import io
|
||||||
# import zipfile
|
import zipfile
|
||||||
|
|
||||||
import facho.fe.form as form
|
import facho.fe.form as form
|
||||||
# from facho import fe
|
from facho import fe
|
||||||
|
|
||||||
from fixtures import (
|
|
||||||
simple_invoice,
|
|
||||||
simple_invoice_without_lines,
|
|
||||||
simple_credit_note_without_lines,
|
|
||||||
simple_debit_note_without_lines)
|
|
||||||
|
|
||||||
simple_invoice = simple_invoice
|
|
||||||
simple_invoice_without_lines = simple_invoice_without_lines
|
|
||||||
simple_credit_note_without_lines = simple_credit_note_without_lines
|
|
||||||
simple_debit_note_without_lines = simple_debit_note_without_lines
|
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_legalmonetary():
|
def test_invoice_legalmonetary():
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
inv.add_invoice_line(form.InvoiceLine(
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
description='producto facho',
|
description = 'producto facho',
|
||||||
item=form.StandardItem(9999),
|
item = form.StandardItem(9999),
|
||||||
price=form.Price(
|
price = form.Price(
|
||||||
amount=form.Amount(100.0),
|
amount = form.Amount(100.0),
|
||||||
type_code='01',
|
type_code = '01',
|
||||||
type='x'
|
type = 'x'
|
||||||
),
|
),
|
||||||
tax=form.TaxTotal(
|
tax = form.TaxTotal(
|
||||||
subtotals=[
|
subtotals = [
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
percent=19.0,
|
percent = 19.0,
|
||||||
)]),
|
)
|
||||||
withholding=form.WithholdingTaxTotal(
|
]
|
||||||
subtotals=[])
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
inv.calculate()
|
inv.calculate()
|
||||||
assert inv.invoice_legal_monetary_total.line_extension_amount == (
|
assert inv.invoice_legal_monetary_total.line_extension_amount == form.Amount(100.0)
|
||||||
form.Amount(100.0))
|
assert inv.invoice_legal_monetary_total.tax_exclusive_amount == form.Amount(100.0)
|
||||||
assert inv.invoice_legal_monetary_total.tax_exclusive_amount == (
|
assert inv.invoice_legal_monetary_total.tax_inclusive_amount == form.Amount(119.0)
|
||||||
form.Amount(100.0))
|
assert inv.invoice_legal_monetary_total.charge_total_amount == form.Amount(0.0)
|
||||||
assert inv.invoice_legal_monetary_total.tax_inclusive_amount == (
|
|
||||||
form.Amount(119.0))
|
|
||||||
assert inv.invoice_legal_monetary_total.charge_total_amount == (
|
|
||||||
form.Amount(0.0))
|
|
||||||
|
|
||||||
|
|
||||||
def test_allowancecharge_as_discount():
|
def test_allowancecharge_as_discount():
|
||||||
discount = form.AllowanceChargeAsDiscount(amount=form.Amount(1000.0))
|
discount = form.AllowanceChargeAsDiscount(amount=form.Amount(1000.0))
|
||||||
|
assert discount.isDiscount() == True
|
||||||
assert discount.isDiscount()
|
|
||||||
|
|
||||||
|
|
||||||
def test_FAU10():
|
def test_FAU10():
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
inv.add_invoice_line(form.InvoiceLine(
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
description='productofacho',
|
description = 'producto facho',
|
||||||
item=form.StandardItem(9999),
|
item = form.StandardItem(9999),
|
||||||
price=form.Price(
|
price = form.Price(
|
||||||
amount=form.Amount(100.0),
|
amount = form.Amount(100.0),
|
||||||
type_code='01',
|
type_code = '01',
|
||||||
type='x'
|
type = 'x'
|
||||||
),
|
),
|
||||||
tax=form.TaxTotal(
|
tax = form.TaxTotal(
|
||||||
subtotals=[
|
subtotals = [
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
percent=19.0)]),
|
percent = 19.0,
|
||||||
withholding=form.WithholdingTaxTotal(
|
)
|
||||||
subtotals=[])
|
]
|
||||||
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
inv.add_allowance_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
inv.add_allowance_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
||||||
|
|
||||||
inv.calculate()
|
inv.calculate()
|
||||||
assert inv.invoice_legal_monetary_total.line_extension_amount == (
|
assert inv.invoice_legal_monetary_total.line_extension_amount == form.Amount(100.0)
|
||||||
form.Amount(100.0))
|
assert inv.invoice_legal_monetary_total.tax_exclusive_amount == form.Amount(100.0)
|
||||||
assert inv.invoice_legal_monetary_total.tax_exclusive_amount == (
|
assert inv.invoice_legal_monetary_total.tax_inclusive_amount == form.Amount(119.0)
|
||||||
form.Amount(100.0))
|
assert inv.invoice_legal_monetary_total.charge_total_amount == form.Amount(19.0)
|
||||||
assert inv.invoice_legal_monetary_total.tax_inclusive_amount == (
|
|
||||||
form.Amount(119.0))
|
|
||||||
assert inv.invoice_legal_monetary_total.charge_total_amount == (
|
|
||||||
form.Amount(19.0))
|
|
||||||
|
|
||||||
|
|
||||||
def test_FAU14():
|
def test_FAU14():
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
inv.add_invoice_line(form.InvoiceLine(
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
description='productofacho',
|
description = 'producto facho',
|
||||||
item=form.StandardItem(9999),
|
item = form.StandardItem(9999),
|
||||||
price=form.Price(
|
price = form.Price(
|
||||||
amount=form.Amount(100.0),
|
amount = form.Amount(100.0),
|
||||||
type_code='01',
|
type_code = '01',
|
||||||
type='x'
|
type = 'x'
|
||||||
),
|
),
|
||||||
tax=form.TaxTotal(
|
tax = form.TaxTotal(
|
||||||
subtotals=[
|
subtotals = [
|
||||||
form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
percent=19.0,
|
percent = 19.0,
|
||||||
)]),
|
)
|
||||||
withholding=form.WithholdingTaxTotal(
|
]
|
||||||
subtotals=[])
|
)
|
||||||
))
|
))
|
||||||
inv.add_allowance_charge(form.AllowanceCharge(
|
inv.add_allowance_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
||||||
amount=form.Amount(19.0)))
|
inv.add_prepaid_payment(form.PrePaidPayment(paid_amount = form.Amount(50.0)))
|
||||||
inv.add_prepaid_payment(form.PrePaidPayment(
|
|
||||||
paid_amount=form.Amount(50.0)))
|
|
||||||
inv.calculate()
|
inv.calculate()
|
||||||
|
|
||||||
wants = form.Amount(119.0 + 19.0 - 50.0)
|
wants = form.Amount(119.0 + 19.0 - 50.0)
|
||||||
|
|
||||||
assert inv.invoice_legal_monetary_total.payable_amount == wants, (
|
assert inv.invoice_legal_monetary_total.payable_amount == wants, "got %s want %s" % (inv.invoice_legal_monetary_total.payable_amount, wants)
|
||||||
"got %s want %s" % (
|
|
||||||
inv.invoice_legal_monetary_total.payable_amount, wants))
|
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_tipo_operacion_nota_debito():
|
def test_invalid_tipo_operacion_nota_debito():
|
||||||
reference = form.InvoiceDocumentReference(
|
reference = form.InvoiceDocumentReference(
|
||||||
ident='11111',
|
ident = '11111',
|
||||||
uuid='21312312',
|
uuid = '21312312',
|
||||||
date='2020-05-05'
|
date = '2020-05-05'
|
||||||
)
|
)
|
||||||
inv = form.DebitNote(reference)
|
inv = form.DebitNote(reference)
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
inv.set_operation_type(22)
|
inv.set_operation_type(22)
|
||||||
|
|
||||||
|
|
||||||
def test_valid_tipo_operacion_nota_debito():
|
def test_valid_tipo_operacion_nota_debito():
|
||||||
reference = form.InvoiceDocumentReference(
|
reference = form.InvoiceDocumentReference(
|
||||||
ident='11111',
|
ident = '11111',
|
||||||
uuid='21312312',
|
uuid = '21312312',
|
||||||
date='2020-05-05'
|
date = '2020-05-05'
|
||||||
)
|
)
|
||||||
inv = form.DebitNote(reference)
|
inv = form.DebitNote(reference)
|
||||||
inv.set_operation_type('30')
|
inv.set_operation_type('30')
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_tipo_operacion_nota_credito():
|
def test_invalid_tipo_operacion_nota_credito():
|
||||||
reference = form.InvoiceDocumentReference(
|
reference = form.InvoiceDocumentReference(
|
||||||
ident='11111',
|
ident = '11111',
|
||||||
uuid='21312312',
|
uuid = '21312312',
|
||||||
date='2020-05-05'
|
date = '2020-05-05'
|
||||||
)
|
)
|
||||||
|
|
||||||
inv = form.DebitNote(reference)
|
inv = form.DebitNote(reference)
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
inv.set_operation_type('990')
|
inv.set_operation_type('990')
|
||||||
|
|
||||||
|
|
||||||
def test_valid_tipo_operacion_nota_credito():
|
def test_valid_tipo_operacion_nota_credito():
|
||||||
reference = form.InvoiceDocumentReference(
|
reference = form.InvoiceDocumentReference(
|
||||||
ident='11111',
|
ident = '11111',
|
||||||
uuid='21312312',
|
uuid = '21312312',
|
||||||
date='2020-05-05'
|
date = '2020-05-05'
|
||||||
)
|
)
|
||||||
inv = form.CreditNote(reference)
|
inv = form.CreditNote(reference)
|
||||||
inv.set_operation_type('20')
|
inv.set_operation_type('20')
|
||||||
@@ -173,52 +141,41 @@ def test_quantity():
|
|||||||
quantity1 = form.Quantity(10, '94')
|
quantity1 = form.Quantity(10, '94')
|
||||||
assert quantity1 * form.Amount(3) == form.Amount(30)
|
assert quantity1 * form.Amount(3) == form.Amount(30)
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_line_quantity_without_taxes():
|
def test_invoice_line_quantity_without_taxes():
|
||||||
line = form.InvoiceLine(
|
line = form.InvoiceLine(
|
||||||
quantity=form.Quantity(10, '94'),
|
quantity = form.Quantity(10, '94'),
|
||||||
description='',
|
description = '',
|
||||||
item=form.StandardItem('test', 9999),
|
item = form.StandardItem('test', 9999),
|
||||||
price=form.Price(
|
price = form.Price(
|
||||||
amount=form.Amount(30.00),
|
amount = form.Amount(30.00),
|
||||||
type_code='01',
|
type_code = '01',
|
||||||
type='x'),
|
type = 'x'
|
||||||
tax=form.TaxTotal(subtotals=[]),
|
),
|
||||||
withholding=form.WithholdingTaxTotal(
|
tax = form.TaxTotal(subtotals=[]))
|
||||||
subtotals=[])
|
|
||||||
)
|
|
||||||
line.calculate()
|
line.calculate()
|
||||||
assert line.total_amount == form.Amount(300)
|
assert line.total_amount == form.Amount(300)
|
||||||
assert line.tax_amount == form.Amount(0)
|
assert line.tax_amount == form.Amount(0)
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_legalmonetary_with_taxes():
|
def test_invoice_legalmonetary_with_taxes():
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
inv.add_invoice_line(form.InvoiceLine(
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
description='productofacho',
|
description = 'producto facho',
|
||||||
item=form.StandardItem(9999),
|
item = form.StandardItem(9999),
|
||||||
price=form.Price(
|
price = form.Price(
|
||||||
amount=form.Amount(100.0),
|
amount = form.Amount(100.0),
|
||||||
type_code='01',
|
type_code = '01',
|
||||||
type='x'
|
type = 'x'
|
||||||
),
|
),
|
||||||
tax=form.TaxTotal(subtotals=[]),
|
tax = form.TaxTotal(subtotals=[])
|
||||||
withholding=form.WithholdingTaxTotal(
|
|
||||||
subtotals=[])
|
|
||||||
))
|
))
|
||||||
inv.calculate()
|
inv.calculate()
|
||||||
|
|
||||||
assert inv.invoice_legal_monetary_total.line_extension_amount == (
|
assert inv.invoice_legal_monetary_total.line_extension_amount == form.Amount(100.0)
|
||||||
form.Amount(100.0))
|
assert inv.invoice_legal_monetary_total.tax_exclusive_amount == form.Amount(100.0)
|
||||||
assert inv.invoice_legal_monetary_total.tax_exclusive_amount == (
|
assert inv.invoice_legal_monetary_total.tax_inclusive_amount == form.Amount(100.0)
|
||||||
form.Amount(100.0))
|
assert inv.invoice_legal_monetary_total.charge_total_amount == form.Amount(0.0)
|
||||||
assert inv.invoice_legal_monetary_total.tax_inclusive_amount == (
|
assert inv.invoice_legal_monetary_total.payable_amount == form.Amount(100.0)
|
||||||
form.Amount(100.0))
|
|
||||||
assert inv.invoice_legal_monetary_total.charge_total_amount == (
|
|
||||||
form.Amount(0.0))
|
|
||||||
assert inv.invoice_legal_monetary_total.payable_amount == (
|
|
||||||
form.Amount(100.0))
|
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_ident_prefix_automatic_invalid():
|
def test_invoice_ident_prefix_automatic_invalid():
|
||||||
@@ -226,7 +183,6 @@ def test_invoice_ident_prefix_automatic_invalid():
|
|||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
inv.set_ident('SETPQJQJ1234567')
|
inv.set_ident('SETPQJQJ1234567')
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_ident_prefix_automatic():
|
def test_invoice_ident_prefix_automatic():
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
inv.set_ident('SETP1234567')
|
inv.set_ident('SETP1234567')
|
||||||
@@ -244,15 +200,13 @@ def test_invoice_ident_prefix_automatic():
|
|||||||
inv.set_ident('1234567')
|
inv.set_ident('1234567')
|
||||||
assert inv.invoice_ident_prefix == ''
|
assert inv.invoice_ident_prefix == ''
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_ident_prefix_manual():
|
def test_invoice_ident_prefix_manual():
|
||||||
inv = form.NationalSalesInvoice()
|
inv = form.NationalSalesInvoice()
|
||||||
inv.set_ident('SETP1234567')
|
inv.set_ident('SETP1234567')
|
||||||
inv.set_ident_prefix('SETA')
|
inv.set_ident_prefix('SETA')
|
||||||
assert inv.invoice_ident_prefix == 'SETA'
|
assert inv.invoice_ident_prefix == 'SETA'
|
||||||
|
|
||||||
|
|
||||||
def test_invoice_ident_prefix_automatic_debit():
|
def test_invoice_ident_prefix_automatic_debit():
|
||||||
inv = form.DebitNote(form.BillingReference('', '', ''))
|
inv = form.DebitNote(form.BillingReference('','',''))
|
||||||
inv.set_ident('ABCDEF1234567')
|
inv.set_ident('ABCDEF1234567')
|
||||||
assert inv.invoice_ident_prefix == 'ABCDEF'
|
assert inv.invoice_ident_prefix == 'ABCDEF'
|
||||||
|
|||||||
@@ -6,21 +6,13 @@
|
|||||||
"""Tests for `facho` package."""
|
"""Tests for `facho` package."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from datetime import datetime
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from facho.fe import form
|
||||||
from facho.fe import form_xml
|
from facho.fe import form_xml
|
||||||
# from fixtures import *
|
|
||||||
|
|
||||||
from fixtures import (
|
|
||||||
simple_invoice,
|
|
||||||
simple_invoice_without_lines,
|
|
||||||
simple_credit_note_without_lines,
|
|
||||||
simple_debit_note_without_lines)
|
|
||||||
|
|
||||||
simple_invoice = simple_invoice
|
|
||||||
simple_invoice_without_lines = simple_invoice_without_lines
|
|
||||||
simple_credit_note_without_lines = simple_credit_note_without_lines
|
|
||||||
simple_debit_note_without_lines = simple_debit_note_without_lines
|
|
||||||
|
|
||||||
|
from fixtures import *
|
||||||
|
|
||||||
def test_import_DIANInvoiceXML():
|
def test_import_DIANInvoiceXML():
|
||||||
try:
|
try:
|
||||||
@@ -35,82 +27,70 @@ def test_import_DIANDebitNoteXML():
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pytest.fail("unexpected not found")
|
pytest.fail("unexpected not found")
|
||||||
|
|
||||||
|
|
||||||
def test_import_DIANCreditNoteXML():
|
def test_import_DIANCreditNoteXML():
|
||||||
try:
|
try:
|
||||||
form_xml.DIANCreditNoteXML
|
form_xml.DIANCreditNoteXML
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pytest.fail("unexpected not found")
|
pytest.fail("unexpected not found")
|
||||||
|
|
||||||
|
def test_allowance_charge_in_invoice(simple_invoice_without_lines):
|
||||||
|
inv = copy.copy(simple_invoice_without_lines)
|
||||||
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
|
quantity = form.Quantity(1, '94'),
|
||||||
|
description = 'producto facho',
|
||||||
|
item = form.StandardItem(9999),
|
||||||
|
price = form.Price(
|
||||||
|
amount = form.Amount(100.0),
|
||||||
|
type_code = '01',
|
||||||
|
type = 'x'
|
||||||
|
),
|
||||||
|
tax = form.TaxTotal(
|
||||||
|
subtotals = [
|
||||||
|
form.TaxSubTotal(
|
||||||
|
percent = 19.0,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
))
|
||||||
|
inv.add_allowance_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
||||||
|
inv.calculate()
|
||||||
|
|
||||||
|
xml = form_xml.DIANInvoiceXML(inv)
|
||||||
|
assert xml.get_element_text('./cac:AllowanceCharge/cbc:ID') == '1'
|
||||||
|
assert xml.get_element_text('./cac:AllowanceCharge/cbc:ChargeIndicator') == 'true'
|
||||||
|
assert xml.get_element_text('./cac:AllowanceCharge/cbc:Amount') == '19.0'
|
||||||
|
assert xml.get_element_text('./cac:AllowanceCharge/cbc:BaseAmount') == '100.0'
|
||||||
|
|
||||||
# def test_allowance_charge_in_invoice(simple_invoice_without_lines):
|
def test_allowance_charge_in_invoice_line(simple_invoice_without_lines):
|
||||||
# inv = copy.copy(simple_invoice_without_lines)
|
inv = copy.copy(simple_invoice_without_lines)
|
||||||
# inv.add_invoice_line(form.InvoiceLine(
|
inv.add_invoice_line(form.InvoiceLine(
|
||||||
# quantity=form.Quantity(1, '94'),
|
quantity = form.Quantity(1, '94'),
|
||||||
# description='productofacho',
|
description = 'producto facho',
|
||||||
# item=form.StandardItem(9999),
|
item = form.StandardItem(9999),
|
||||||
# price=form.Price(
|
price = form.Price(
|
||||||
# amount=form.Amount(100.0),
|
amount = form.Amount(100.0),
|
||||||
# type_code='01',
|
type_code = '01',
|
||||||
# type='x'
|
type = 'x'
|
||||||
# ),
|
),
|
||||||
# tax=form.TaxTotal(
|
tax = form.TaxTotal(
|
||||||
# subtotals=[
|
subtotals = [
|
||||||
# form.TaxSubTotal(
|
form.TaxSubTotal(
|
||||||
# percent=19.0,
|
percent = 19.0,
|
||||||
# )]),
|
)
|
||||||
# withholding=form.WithholdingTaxTotal(
|
]
|
||||||
# subtotals=[])
|
),
|
||||||
# ))
|
allowance_charge = [
|
||||||
|
form.AllowanceChargeAsDiscount(amount=form.Amount(10.0))
|
||||||
|
]
|
||||||
|
))
|
||||||
|
inv.calculate()
|
||||||
|
|
||||||
# inv.add_allowance_charge(form.AllowanceCharge(amount=form.Amount(19.0)))
|
# se aplico descuento
|
||||||
# inv.calculate()
|
assert inv.invoice_legal_monetary_total.line_extension_amount == form.Amount(90.0)
|
||||||
|
|
||||||
|
xml = form_xml.DIANInvoiceXML(inv)
|
||||||
|
|
||||||
# xml = form_xml.DIANInvoiceXML(inv)
|
with pytest.raises(AttributeError):
|
||||||
# assert xml.get_element_text('./cac:AllowanceCharge/cbc:ID') == '1'
|
assert xml.get_element_text('/fe:Invoice/cac:AllowanceCharge/cbc:ID') == '1'
|
||||||
# assert xml.get_element_text(
|
xml.get_element_text('/fe:Invoice/cac:InvoiceLine/cac:AllowanceCharge/cbc:ID') == '1'
|
||||||
# './cac:AllowanceCharge/cbc:ChargeIndicator') == 'true'
|
xml.get_element_text('/fe:Invoice/cac:InvoiceLine/cac:AllowanceCharge/cbc:BaseAmount') == '100.0'
|
||||||
# assert xml.get_element_text(
|
|
||||||
# './cac:AllowanceCharge/cbc:Amount') == '19.0'
|
|
||||||
# assert xml.get_element_text(
|
|
||||||
# './cac:AllowanceCharge/cbc:BaseAmount') == '100.0'
|
|
||||||
|
|
||||||
|
|
||||||
# def test_allowance_charge_in_invoice_line(simple_invoice_without_lines):
|
|
||||||
# inv = copy.copy(simple_invoice_without_lines)
|
|
||||||
# inv.add_invoice_line(form.InvoiceLine(
|
|
||||||
# quantity=form.Quantity(1, '94'),
|
|
||||||
# description='producto facho',
|
|
||||||
# item=form.StandardItem(9999),
|
|
||||||
# price=form.Price(
|
|
||||||
# amount=form.Amount(100.0),
|
|
||||||
# type_code='01',
|
|
||||||
# type='x'
|
|
||||||
# ),
|
|
||||||
# tax=form.TaxTotal(
|
|
||||||
# subtotals=[
|
|
||||||
# form.TaxSubTotal(
|
|
||||||
# percent=19.0,
|
|
||||||
# )]),
|
|
||||||
# withholding=form.WithholdingTaxTotal(
|
|
||||||
# subtotals=[]),
|
|
||||||
# allowance_charge=[
|
|
||||||
# form.AllowanceChargeAsDiscount(amount=form.Amount(10.0))
|
|
||||||
# ]
|
|
||||||
# ))
|
|
||||||
# inv.calculate()
|
|
||||||
|
|
||||||
# # se aplico descuento
|
|
||||||
# assert inv.invoice_legal_monetary_total.line_extension_amount == (
|
|
||||||
# form.Amount(90.0))
|
|
||||||
|
|
||||||
# xml = form_xml.DIANInvoiceXML(inv)
|
|
||||||
|
|
||||||
# with pytest.raises(AttributeError):
|
|
||||||
# assert xml.get_element_text(
|
|
||||||
# '/fe:Invoice/cac:AllowanceCharge/cbc:ID') == '1'
|
|
||||||
# xml.get_element_text(
|
|
||||||
# '/fe:Invoice/cac:InvoiceLine/cac:AllowanceCharge/cbc:ID') == '1'
|
|
||||||
# xml.get_element_text(
|
|
||||||
# '/fe:Invoice/cac:InvoiceLine/cac:AllowanceCharge/cbc:BaseAmount'
|
|
||||||
# ) == '100.0'
|
|
||||||
|
|||||||
1098
tests/test_nomina.py
1098
tests/test_nomina.py
File diff suppressed because it is too large
Load Diff
@@ -1,270 +0,0 @@
|
|||||||
#!/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/Comp
|
|
||||||
# robanteTotal') == '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/Re
|
|
||||||
# emplazar/ReemplazandoPredecesor/@NumeroPred') == '123456'
|
|
||||||
# assert
|
|
||||||
# xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/Re
|
|
||||||
# emplazar/ReemplazandoPredecesor/@CUNEPred') == 'ABC123456'
|
|
||||||
# assert
|
|
||||||
# xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/Re
|
|
||||||
# emplazar/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/Reemplaza
|
|
||||||
# ndoPredecesor') is not None
|
|
||||||
# assert
|
|
||||||
# xml.get_element('/nominaajuste:NominaIndividualDeAjuste/Eliminar/EliminandoP
|
|
||||||
# redecesor') is None
|
|
||||||
|
|
||||||
# def test_adicionar_eliminar_reemplazar_predecesor_opcional():
|
|
||||||
# nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
|
|
||||||
|
|
||||||
#
|
|
||||||
# nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Eliminar.Pr
|
|
||||||
# edecesor(
|
|
||||||
# numero = '123456',
|
|
||||||
# cune = 'ABC123456',
|
|
||||||
# fecha_generacion = '2021-11-16'
|
|
||||||
# ))
|
|
||||||
|
|
||||||
# xml = nomina.toFachoXML()
|
|
||||||
# print(xml.tostring())
|
|
||||||
# assert
|
|
||||||
# xml.get_element('/nominaajuste:NominaIndividualDeAjuste/Eliminar/EliminandoP
|
|
||||||
# redecesor') is not None
|
|
||||||
# assert
|
|
||||||
# xml.get_element('/nominaajuste:NominaIndividualDeAjuste/Reemplazar/Reemplaza
|
|
||||||
# ndoPredecesor') 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/Compro
|
|
||||||
# banteTotal') == '1000000.00'
|
|
||||||
|
|
||||||
# def test_adicionar_eliminar_asignar_predecesor():
|
|
||||||
# nomina = fe.nomina.DIANNominaIndividualDeAjuste.Eliminar()
|
|
||||||
|
|
||||||
#
|
|
||||||
# nomina.asignar_predecesor(fe.nomina.DIANNominaIndividualDeAjuste.Eliminar.Pr
|
|
||||||
# edecesor(
|
|
||||||
# numero = '123456',
|
|
||||||
# cune = 'ABC123456',
|
|
||||||
# fecha_generacion = '2021-11-16'
|
|
||||||
# ))
|
|
||||||
|
|
||||||
# xml = nomina.toFachoXML()
|
|
||||||
# print(xml.tostring())
|
|
||||||
# assert
|
|
||||||
# xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/El
|
|
||||||
# iminar/EliminandoPredecesor/@NumeroPred') == '123456'
|
|
||||||
# assert
|
|
||||||
# xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/El
|
|
||||||
# iminar/EliminandoPredecesor/@CUNEPred') == 'ABC123456'
|
|
||||||
# assert
|
|
||||||
# xml.get_element_text_or_attribute('/nominaajuste:NominaIndividualDeAjuste/El
|
|
||||||
# iminar/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'
|
|
||||||
@@ -3,28 +3,22 @@
|
|||||||
# This file is part of facho. The COPYRIGHT file at the top level of
|
# This file is part of facho. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
|
||||||
# import pytest
|
import pytest
|
||||||
|
|
||||||
import facho.fe.form as form
|
import facho.fe.form as form
|
||||||
from facho import fe
|
from facho import fe
|
||||||
|
from facho.fe.form_xml import DIANInvoiceXML, DIANCreditNoteXML, DIANDebitNoteXML
|
||||||
|
|
||||||
from facho.fe.form_xml import DIANInvoiceXML
|
from fixtures import *
|
||||||
# from facho.fe.form_xml import (
|
|
||||||
# DIANInvoiceXML, DIANCreditNoteXML, DIANDebitNoteXML)
|
|
||||||
|
|
||||||
from fixtures import simple_invoice
|
|
||||||
|
|
||||||
from facho.fe.form import query
|
from facho.fe.form import query
|
||||||
|
|
||||||
simple_invoice = simple_invoice
|
|
||||||
|
|
||||||
|
|
||||||
def test_query_billing_reference(simple_invoice):
|
def test_query_billing_reference(simple_invoice):
|
||||||
xml = DIANInvoiceXML(simple_invoice)
|
xml = DIANInvoiceXML(simple_invoice)
|
||||||
cufe_extension = fe.DianXMLExtensionCUFE(simple_invoice)
|
cufe_extension = fe.DianXMLExtensionCUFE(simple_invoice)
|
||||||
xml.add_extension(cufe_extension)
|
xml.add_extension(cufe_extension)
|
||||||
out = xml.tostring()
|
out = xml.tostring()
|
||||||
|
|
||||||
reference = query.billing_reference(out, form.BillingReference)
|
reference = query.billing_reference(out, form.BillingReference)
|
||||||
assert isinstance(reference, form.BillingReference)
|
assert isinstance(reference, form.BillingReference)
|
||||||
assert reference.ident != ''
|
assert reference.ident != ''
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user