Fix: Formateo PEP8 (79 cols) y limpieza flake8 en paquete facho
- Líneas >79 cols reajustadas en todo el paquete - Fix F821: etree.cleanup_namespaces(security) en signature.py (era 'header', NameError) - Fix bug cune_xpath -> xpath en nomina/informacion_general() (NameError) - Elimina clase TaxScheme duplicada en form/__init__.py - Imports explícitos (F403/F405) y __all__ en form_xml/invoice.py, nomina - Elimina imports y variables muertas (F401/F841), E712 (== None -> is None)
This commit is contained in:
428
facho/cli.py
428
facho/cli.py
@@ -1,39 +1,37 @@
|
|||||||
# -*- 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,
|
{
|
||||||
'formatters': {
|
"version": 1,
|
||||||
'verbose': {
|
"formatters": {"verbose": {"format": "%(name)s: %(message)s"}},
|
||||||
'format': '%(name)s: %(message)s'
|
"handlers": {
|
||||||
}
|
"console": {
|
||||||
},
|
"level": "DEBUG",
|
||||||
'handlers': {
|
"class": "logging.StreamHandler",
|
||||||
'console': {
|
"formatter": "verbose",
|
||||||
'level': 'DEBUG',
|
|
||||||
'class': 'logging.StreamHandler',
|
|
||||||
'formatter': 'verbose',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'loggers': {
|
"loggers": {
|
||||||
'zeep.transports': {
|
"zeep.transports": {
|
||||||
'level': 'DEBUG',
|
"level": "DEBUG",
|
||||||
'propagate': True,
|
"propagate": True,
|
||||||
'handlers': ['console'],
|
"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:
|
||||||
@@ -41,99 +39,122 @@ 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(nit, nit_proveedor, id_software, username, password):
|
def consultaResolucionesFacturacion(
|
||||||
|
nit, nit_proveedor, id_software, username, password
|
||||||
|
):
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
client_dian = dian.DianClient(username,
|
|
||||||
password)
|
client_dian = dian.DianClient(username, password)
|
||||||
resp = client_dian.request(dian.ConsultaResolucionesFacturacionPeticion(
|
resp = client_dian.request(
|
||||||
|
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(private_key, public_key, habilitacion, password, test_setid, filename, zipfile):
|
def soap_send_test_set_async(
|
||||||
|
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(private_key, public_key, password=password)
|
client = dian.DianSignatureClient(
|
||||||
|
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(req(
|
resp = client.request(
|
||||||
|
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(private_key, public_key, habilitacion, password, filename, zipfile):
|
def soap_send_bill_async(
|
||||||
|
private_key, public_key, habilitacion, password, filename, zipfile
|
||||||
|
):
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
client = dian.DianSignatureClient(
|
||||||
|
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(
|
resp = client.request(req(filename, open(zipfile, "rb").read()))
|
||||||
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(private_key, public_key, habilitacion, password, filename, zipfile):
|
def soap_send_bill_sync(
|
||||||
|
private_key, public_key, habilitacion, password, filename, zipfile
|
||||||
|
):
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
client = dian.DianSignatureClient(
|
||||||
|
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(
|
resp = client.request(req(filename, open(zipfile, "rb").read()))
|
||||||
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(private_key, public_key, habilitacion, password, track_id):
|
def soap_get_status_zip(
|
||||||
|
private_key, public_key, habilitacion, password, track_id
|
||||||
|
):
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
client = dian.DianSignatureClient(
|
||||||
|
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(
|
resp = client.request(req(trackId=track_id))
|
||||||
trackId = track_id
|
|
||||||
))
|
|
||||||
|
|
||||||
print("StatusCode:", resp.StatusCode)
|
print("StatusCode:", resp.StatusCode)
|
||||||
print("StatusDescription:", resp.StatusDescription)
|
print("StatusDescription:", resp.StatusDescription)
|
||||||
@@ -143,68 +164,78 @@ def soap_get_status_zip(private_key, public_key, habilitacion, password, track_i
|
|||||||
|
|
||||||
|
|
||||||
@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(private_key, public_key, habilitacion, password, track_id):
|
def soap_get_status(
|
||||||
|
private_key, public_key, habilitacion, password, track_id
|
||||||
|
):
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
client = dian.DianSignatureClient(
|
||||||
|
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(
|
resp = client.request(req(trackId=track_id))
|
||||||
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(private_key,
|
def soap_get_numbering_range(
|
||||||
|
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(private_key, public_key, password=password)
|
client = dian.DianSignatureClient(
|
||||||
|
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(
|
resp = client.request(req(nit, nit_proveedor, id_software))
|
||||||
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"',
|
||||||
@@ -213,35 +244,55 @@ 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(private_key, passphrase, xmlfile, ssl=True, use_cache_policy=False, output=None):
|
def sign_xml(
|
||||||
|
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(private_key, passphrase=passphrase, localpolicy=use_cache_policy)
|
signer = fe.DianXMLExtensionSigner(
|
||||||
document = open(xmlfile, 'r').read().encode('utf-8')
|
private_key, passphrase=passphrase, localpolicy=use_cache_policy
|
||||||
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(private_key, passphrase, scriptname, generate=False, ssl=True, sign=False, use_cache_policy=False, output=None):
|
def generate_invoice(
|
||||||
|
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
|
||||||
@@ -254,13 +305,15 @@ def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=Tr
|
|||||||
|
|
||||||
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)
|
||||||
|
|
||||||
import facho.fe.form as form
|
from facho.fe.form_xml import (
|
||||||
from facho.fe.form_xml import DIANInvoiceXML, DIANWriteSigned, DIANWrite, DIANSupportDocumentXML
|
DIANWriteSigned,
|
||||||
from facho import fe
|
DIANWrite,
|
||||||
|
DIANSupportDocumentXML,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
invoice_xml = module.document_xml()
|
invoice_xml = module.document_xml()
|
||||||
@@ -279,24 +332,39 @@ def generate_invoice(private_key, passphrase, scriptname, generate=False, ssl=Tr
|
|||||||
xml.add_extension(extension)
|
xml.add_extension(extension)
|
||||||
|
|
||||||
if sign:
|
if sign:
|
||||||
DIANWriteSigned(xml, output, private_key, passphrase, use_cache_policy)
|
DIANWriteSigned(
|
||||||
|
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(private_key, passphrase, scriptname, ssl=True, sign=False, use_cache_policy=False, output=None):
|
def generate_nomina(
|
||||||
|
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() -> fe.nomina.NominaIndividual
|
def nomina() -> (
|
||||||
def extensions(fe.nomina.NominaIndividual): -> List[facho.FachoXMLExtension]
|
fe.nomina.NominaIndividual
|
||||||
|
)
|
||||||
|
def extensions(
|
||||||
|
fe.nomina.NominaIndividual
|
||||||
|
): -> List[facho.FachoXMLExtension]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not ssl:
|
if not ssl:
|
||||||
@@ -304,7 +372,7 @@ def generate_nomina(private_key, passphrase, scriptname, ssl=True, sign=False, u
|
|||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@@ -320,59 +388,83 @@ def generate_nomina(private_key, passphrase, scriptname, ssl=True, sign=False, u
|
|||||||
xml.add_extension(extension)
|
xml.add_extension(extension)
|
||||||
|
|
||||||
if sign:
|
if sign:
|
||||||
DIANWriteSigned(xml, output, private_key, passphrase, use_cache_policy, dian_signer=facho.fe.nomina.DianXMLExtensionSigner)
|
DIANWriteSigned(
|
||||||
|
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(private_key, public_key, habilitacion, password, filename, zipfile):
|
def soap_send_nomina_sync(
|
||||||
|
private_key, public_key, habilitacion, password, filename, zipfile
|
||||||
|
):
|
||||||
from facho.fe.client import dian
|
from facho.fe.client import dian
|
||||||
|
|
||||||
client = dian.DianSignatureClient(private_key, public_key, password=password)
|
client = dian.DianSignatureClient(
|
||||||
|
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(
|
resp = client.request(req(open(zipfile, "rb").read()))
|
||||||
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(private_key, passphrase, xmlfile, ssl=True, use_cache_policy=False, output=None):
|
def sign_verify_xml(
|
||||||
|
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(private_key, passphrase=passphrase, localpolicy=use_cache_policy)
|
signer = fe.DianXMLExtensionSignerVerifier(
|
||||||
document = open(xmlfile, 'r').read().encode('utf-8')
|
private_key, passphrase=passphrase, localpolicy=use_cache_policy
|
||||||
|
)
|
||||||
|
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(software_id, software_pin, nit, dv, output_zippath):
|
def generate_nomina_habilitacion(
|
||||||
|
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(
|
||||||
@@ -380,15 +472,17 @@ def generate_nomina_habilitacion(software_id, software_pin, nit, dv, output_zipp
|
|||||||
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)
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ 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='',
|
def __init__(self, root, builder=None, nsmap=None, fragment_prefix='',
|
||||||
fragment_root_element=None):
|
fragment_root_element=None):
|
||||||
if builder is None:
|
if builder is None:
|
||||||
|
|||||||
@@ -14,3 +14,22 @@ 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,23 +1,13 @@
|
|||||||
from facho import facho
|
|
||||||
|
|
||||||
import zeep
|
import zeep
|
||||||
from zeep.wsse.username import UsernameToken
|
from zeep.wsse.username import UsernameToken
|
||||||
from .wsse.signature import Signature, BinarySignature
|
from .wsse.signature import BinarySignature
|
||||||
from zeep.wsa import WsAddressingPlugin
|
|
||||||
import xmlsec
|
import xmlsec
|
||||||
import urllib.request
|
from dataclasses import dataclass, asdict
|
||||||
from datetime import datetime
|
|
||||||
from dataclasses import dataclass, asdict, field
|
|
||||||
|
|
||||||
import http.client
|
|
||||||
import hashlib
|
|
||||||
import secrets
|
|
||||||
import base64
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['DianClient',
|
__all__ = ['DianClient']
|
||||||
'ConsultaResolucionesFacturacionPeticion',
|
|
||||||
'ConsultaResolucionesFacturacionRespuesta']
|
|
||||||
|
|
||||||
class SOAPService:
|
class SOAPService:
|
||||||
|
|
||||||
@@ -33,6 +23,7 @@ class SOAPService:
|
|||||||
def todict(self):
|
def todict(self):
|
||||||
return asdict(self)
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GetNumberingRangeResponse:
|
class GetNumberingRangeResponse:
|
||||||
|
|
||||||
@@ -49,7 +40,6 @@ class GetNumberingRangeResponse:
|
|||||||
|
|
||||||
NumberRangeResponse: list[NumberRangeResponse]
|
NumberRangeResponse: list[NumberRangeResponse]
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fromdict(cls, data):
|
def fromdict(cls, data):
|
||||||
return cls(
|
return cls(
|
||||||
@@ -100,6 +90,7 @@ class SendTestSetAsyncResponse:
|
|||||||
data['ErrorMessageList'] or []
|
data['ErrorMessageList'] or []
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SendTestSetAsync(SOAPService):
|
class SendTestSetAsync(SOAPService):
|
||||||
fileName: str
|
fileName: str
|
||||||
@@ -115,6 +106,7 @@ 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
|
||||||
@@ -129,6 +121,7 @@ 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
|
||||||
@@ -162,6 +155,7 @@ 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
|
||||||
@@ -175,6 +169,7 @@ 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
|
||||||
@@ -220,6 +215,7 @@ 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):
|
||||||
@@ -250,7 +246,11 @@ class DianClient(DianGateway):
|
|||||||
self._password = password
|
self._password = password
|
||||||
|
|
||||||
def _open(self, service):
|
def _open(self, service):
|
||||||
return zeep.Client(service.get_wsdl(), wsse=UsernameToken(self._username, self._password))
|
return zeep.Client(
|
||||||
|
service.get_wsdl(),
|
||||||
|
wsse=UsernameToken(
|
||||||
|
self._username,
|
||||||
|
self._password))
|
||||||
|
|
||||||
|
|
||||||
class DianSignatureClient(DianGateway):
|
class DianSignatureClient(DianGateway):
|
||||||
@@ -262,13 +262,10 @@ 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=
|
client = zeep.Client(service.get_wsdl(), wsse=BinarySignature(
|
||||||
BinarySignature(
|
|
||||||
self.private_key_path, self.public_key_path, self.password,
|
self.private_key_path, self.public_key_path, self.password,
|
||||||
signature_method=xmlsec.Transform.RSA_SHA256,
|
signature_method=xmlsec.Transform.RSA_SHA256,
|
||||||
digest_method=xmlsec.Transform.SHA256)
|
digest_method=xmlsec.Transform.SHA256),
|
||||||
,
|
|
||||||
)
|
)
|
||||||
return client
|
return client
|
||||||
|
|||||||
@@ -70,8 +70,11 @@ 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, key, self.signature_method, self.digest_method, expires_dt=self.expires_dt
|
envelope,
|
||||||
)
|
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):
|
||||||
@@ -81,7 +84,7 @@ class MemorySignature(object):
|
|||||||
|
|
||||||
|
|
||||||
class Signature(MemorySignature):
|
class Signature(MemorySignature):
|
||||||
"""Sign given SOAP envelope with WSSE sig using given key file and cert file."""
|
"""Sign given SOAP envelope with WSSE sig using given key and cert file."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -101,15 +104,18 @@ class Signature(MemorySignature):
|
|||||||
|
|
||||||
|
|
||||||
class BinarySignature(Signature):
|
class BinarySignature(Signature):
|
||||||
"""Sign given SOAP envelope with WSSE sig using given key file and cert file.
|
"""Sign given SOAP envelope with WSSE sig using given key 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, key, self.signature_method, self.digest_method, expires_dt = self.expires_dt
|
envelope,
|
||||||
)
|
key,
|
||||||
|
self.signature_method,
|
||||||
|
self.digest_method,
|
||||||
|
expires_dt=self.expires_dt)
|
||||||
return envelope, headers
|
return envelope, headers
|
||||||
|
|
||||||
|
|
||||||
@@ -219,7 +225,9 @@ 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(envelope, key, signature_method, digest_method)
|
return _sign_envelope_with_key(
|
||||||
|
envelope, key, signature_method, digest_method)
|
||||||
|
|
||||||
|
|
||||||
def get_timestamp(timestamp=None, delta=None):
|
def get_timestamp(timestamp=None, delta=None):
|
||||||
timestamp = timestamp or datetime.now(timezone.utc)
|
timestamp = timestamp or datetime.now(timezone.utc)
|
||||||
@@ -230,11 +238,15 @@ 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({'{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id': utils.get_unique_id()})
|
etimestamp = utils.WSU.Timestamp({
|
||||||
|
'{http://docs.oasis-open.org/wss/2004/01/'
|
||||||
|
'oasis-200401-wss-wssecurity-utility-1.0.xsd}Id':
|
||||||
|
utils.get_unique_id()})
|
||||||
etimestamp.append(utils.WSU.Created(get_timestamp()))
|
etimestamp.append(utils.WSU.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)
|
||||||
@@ -243,11 +255,16 @@ def _append_timestamp(security, expires_dt=None):
|
|||||||
keep_ns_prefixes=security.nsmap,
|
keep_ns_prefixes=security.nsmap,
|
||||||
top_nsmap=utils.NSMAP)
|
top_nsmap=utils.NSMAP)
|
||||||
else:
|
else:
|
||||||
etree.cleanup_namespaces(header)
|
etree.cleanup_namespaces(security)
|
||||||
|
|
||||||
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(
|
||||||
@@ -278,7 +295,7 @@ def _signature_prepare(envelope, key, signature_method, digest_method, expires_d
|
|||||||
_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 != None:
|
if timestamp is not None:
|
||||||
_sign_node(ctx, signature, timestamp, digest_method)
|
_sign_node(ctx, signature, timestamp, digest_method)
|
||||||
ctx.sign(signature)
|
ctx.sign(signature)
|
||||||
|
|
||||||
@@ -286,18 +303,30 @@ def _signature_prepare(envelope, key, signature_method, digest_method, expires_d
|
|||||||
# 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(key_info, QName(ns.WSSE, "SecurityTokenReference"))
|
sec_token_ref = etree.SubElement(
|
||||||
|
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(envelope, key, signature_method, digest_method, expires_dt=None):
|
def _sign_envelope_with_key(
|
||||||
|
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(envelope, key, signature_method, digest_method, expires_dt=None):
|
def _sign_envelope_with_key_binary(
|
||||||
|
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
|
||||||
)
|
)
|
||||||
@@ -353,7 +382,10 @@ 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("ds:SignedInfo/ds:Reference", namespaces={"ds": ns.DS})
|
refs = signature.xpath(
|
||||||
|
"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,10 +7,17 @@ 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'))
|
|
||||||
|
|
||||||
NominaIndividual = xmlschema.XMLSchema(path_for_xsd('nomina', 'NominaIndividualElectronicaXSDV1.0.6.xsd'))
|
UBLInvoice = xmlschema.XMLSchema(
|
||||||
NominaIndividualDeAjuste = xmlschema.XMLSchema(path_for_xsd('nomina', 'NominaIndividualDeAjusteElectronicaXSDV1.0.6.xsd'))
|
path_for_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)
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ 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',
|
||||||
@@ -72,38 +73,88 @@ __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')
|
|
||||||
TipoResponsabilidad = CodeList(path_for_codelist('TipoResponsabilidad-2.1.gc'), 'code', 'name')\
|
TipoOrganizacion = CodeList(path_for_codelist(
|
||||||
.update(CodeList(path_for_codelist('TipoResponsabilidad-2.1.custom.gc'), 'code', 'name'))
|
'TipoOrganizacion-2.1.gc'), 'code', 'name')
|
||||||
TipoAmbiente = CodeList(path_for_codelist('TipoAmbiente-2.1.gc'), 'code', 'name')
|
TipoResponsabilidad = CodeList(
|
||||||
TipoDocumento = CodeList(path_for_codelist('TipoDocumento-2.1.gc'), 'code', 'name')
|
path_for_codelist('TipoResponsabilidad-2.1.gc'),
|
||||||
TipoImpuesto = CodeList(path_for_codelist('TipoImpuesto-2.1.gc'), 'code', 'name')\
|
'code',
|
||||||
.update(CodeList(path_for_codelist('TipoImpuesto-2.1.custom.gc'), 'code', 'name'))
|
'name') .update(
|
||||||
TarifaImpuesto = CodeList(path_for_codelist('TarifaImpuestoINC-2.1.gc'), 'code', 'name')\
|
CodeList(
|
||||||
.update(CodeList(path_for_codelist('TarifaImpuestoIVA-2.1.gc'), 'code', 'name'))\
|
path_for_codelist('TipoResponsabilidad-2.1.custom.gc'),
|
||||||
.update(CodeList(path_for_codelist('TarifaImpuestoReteIVA-2.1.gc'), 'code', 'name'))\
|
'code',
|
||||||
.update(CodeList(path_for_codelist('TarifaImpuestoReteRenta-2.1.gc'), 'code', 'name'))
|
'name'))
|
||||||
CodigoPrecioReferencia = CodeList(path_for_codelist('CodigoPrecioReferencia-2.1.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-2.1.custom.gc'), 'code', 'name')
|
RegimenFiscal = CodeList(path_for_codelist(
|
||||||
TipoOperacionNC = CodeList(path_for_codelist('TipoOperacionNC-2.1.gc'), 'code', 'name')
|
'RegimenFiscal-2.1.custom.gc'), 'code', 'name')
|
||||||
TipoOperacionNCDS = CodeList(path_for_codelist('TipoOperacionNCDS-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('Departamentos-2.1.gc'), 'code', 'name')
|
Departamento = CodeList(path_for_codelist(
|
||||||
|
'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-2.1.gc'), 'code', 'name')
|
TipoIdFiscal = CodeList(path_for_codelist(
|
||||||
CodigoDescuento = CodeList(path_for_codelist('CodigoDescuento-2.1.gc'), 'code', 'name')
|
'TipoIdFiscal-2.1.gc'), 'code', 'name')
|
||||||
UnidadesMedida = CodeList(path_for_codelist('UnidadesMedida-2.1.gc'), 'code', 'name')
|
CodigoDescuento = CodeList(path_for_codelist(
|
||||||
TipoTrabajador = CodeList(path_for_codelist('TipoTrabajador-2.1.gc'), 'code', 'name')
|
'CodigoDescuento-2.1.gc'), 'code', 'name')
|
||||||
SubTipoTrabajador = CodeList(path_for_codelist('SubTipoTrabajador-2.1.gc'), 'code', 'name')
|
UnidadesMedida = CodeList(path_for_codelist(
|
||||||
TipoContrato = CodeList(path_for_codelist('TipoContrato-2.1.gc'), 'code', 'name')
|
'UnidadesMedida-2.1.gc'), 'code', 'name')
|
||||||
PeriodoNomina = CodeList(path_for_codelist('PeriodoNomina-2.1.gc'), 'code', 'name')
|
TipoTrabajador = CodeList(path_for_codelist(
|
||||||
|
'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('Idioma-2.1.gc'), 'iso-639-1', 'name')
|
IdiomaISO6391 = CodeList(path_for_codelist(
|
||||||
|
'Idioma-2.1.gc'), 'iso-639-1', 'name')
|
||||||
|
|||||||
296
facho/fe/fe.py
296
facho/fe/fe.py
@@ -37,31 +37,45 @@ AMBIENTE_PRODUCCION = codelist.TipoAmbiente.by_name('Producción')['code']
|
|||||||
|
|
||||||
|
|
||||||
SCHEME_AGENCY_ATTRS = {
|
SCHEME_AGENCY_ATTRS = {
|
||||||
'schemeAgencyName': 'CO, DIAN (Dirección de Impuestos y Aduanas Nacionales)',
|
'schemeAgencyName': 'CO, DIAN (Dirección de Impuestos y Aduanas'
|
||||||
'schemeAgencyID': '195'
|
' Nacionales)',
|
||||||
}
|
'schemeAgencyID': '195'}
|
||||||
|
|
||||||
|
|
||||||
# RESOLUCION 0001: pagina 516
|
# RESOLUCION 0001: pagina 516
|
||||||
POLICY_ID = 'https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf'
|
POLICY_ID = (
|
||||||
POLICY_NAME = u'Política de firma para facturas electrónicas de la República de Colombia.'
|
'https://facturaelectronica.dian.gov.co/politicadefirma/v2'
|
||||||
|
'/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')
|
Bogota = tz.gettz('America/Bogota')
|
||||||
# NAMESPACES = {
|
# NAMESPACES = {
|
||||||
# 'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2',
|
# 'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2',
|
||||||
# 'nomina': 'dian:gov:co:facturaelectronica:NominaIndividual',
|
# 'nomina': 'dian:gov:co:facturaelectronica:NominaIndividual',
|
||||||
# 'nominaajuste': 'dian:gov:co:facturaelectronica:NominaIndividualDeAjuste',
|
# 'nominaajuste': 'dian:gov:co:facturaelectronica:'
|
||||||
|
# 'NominaIndividualDeAjuste',
|
||||||
# 'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
|
# 'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
|
||||||
# 'xs': 'http://www.w3.org/2001/XMLSchema-instance',
|
# 'xs': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
# 'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
|
# 'cac': 'urn:oasis:names:specification:ubl:schema:xsd:'
|
||||||
# 'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
|
# 'CommonAggregateComponents-2',
|
||||||
# 'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1',
|
# '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',
|
# 'clm54217': 'urn:un:unece:uncefact:codelist:specification:54217:2001',
|
||||||
# 'clmIANAMIMEMediaType': 'urn:un:unece:uncefact:codelist:specification:IANAMIMEMediaType:2003',
|
# 'clmIANAMIMEMediaType': 'urn:un:unece:uncefact:codelist:specification:'
|
||||||
# 'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2',
|
# 'IANAMIMEMediaType:2003',
|
||||||
# 'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2',
|
# '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',
|
# 'sts': 'dian:gov:co:facturaelectronica:Structures-2-1',
|
||||||
# 'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2',
|
# 'udt': 'urn:un:unece:uncefact:data:specification:'
|
||||||
|
# 'UnqualifiedDataTypesSchemaModule:2',
|
||||||
# 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
# 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
# '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#',
|
# 'xades141': 'http://uri.etsi.org/01903/v1.4.1#',
|
||||||
@@ -72,12 +86,19 @@ Bogota = tz.gettz('America/Bogota')
|
|||||||
|
|
||||||
NAMESPACES = {
|
NAMESPACES = {
|
||||||
'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
|
'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1',
|
||||||
'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
|
'cac': (
|
||||||
'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
|
'urn:oasis:names:specification:ubl:schema:xsd'
|
||||||
'ext': 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2',
|
':CommonAggregateComponents-2'),
|
||||||
|
'cbc': 'urn:oasis:names:specification:ubl:schema:xsd'
|
||||||
|
':CommonBasicComponents-2',
|
||||||
|
'ext': (
|
||||||
|
'urn:oasis:names:specification:ubl:schema:xsd'
|
||||||
|
':CommonExtensionComponents-2'),
|
||||||
'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2',
|
'qdt': 'urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2',
|
||||||
'sts': 'dian:gov:co:facturaelectronica:Structures-2-1',
|
'sts': 'dian:gov:co:facturaelectronica:Structures-2-1',
|
||||||
'udt': 'urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2',
|
'udt': (
|
||||||
|
'urn:un:unece:uncefact:data:specification'
|
||||||
|
':UnqualifiedDataTypesSchemaModule:2'),
|
||||||
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
'ds': 'http://www.w3.org/2000/09/xmldsig#',
|
'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#',
|
||||||
@@ -119,14 +140,17 @@ class FeXML(FachoXML):
|
|||||||
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 namespace
|
# MACHETE(bit4bit) la DIAN espera que la etiqueta raiz no este en un
|
||||||
|
# namespace
|
||||||
root_namespace = self.root_namespace()
|
root_namespace = self.root_namespace()
|
||||||
root_localname = self.root_localname()
|
root_localname = self.root_localname()
|
||||||
xmlns_name = {v: k for k, v in NAMESPACES.items()}[root_namespace]
|
xmlns_name = {v: k for k, v in NAMESPACES.items()}[root_namespace]
|
||||||
if root_localname == 'Invoice':
|
if root_localname == 'Invoice':
|
||||||
urn_oasis = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'
|
urn_oasis = (
|
||||||
|
'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2')
|
||||||
if root_localname == 'CreditNote':
|
if root_localname == 'CreditNote':
|
||||||
urn_oasis = 'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2'
|
urn_oasis = (
|
||||||
|
'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2')
|
||||||
return super().tostring(**kw)\
|
return super().tostring(**kw)\
|
||||||
.replace(xmlns_name + ':', '')\
|
.replace(xmlns_name + ':', '')\
|
||||||
.replace('xmlns:' + xmlns_name, 'xmlns')\
|
.replace('xmlns:' + xmlns_name, 'xmlns')\
|
||||||
@@ -149,9 +173,12 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
|
|
||||||
def _get_qrcode(self, cufe):
|
def _get_qrcode(self, cufe):
|
||||||
url_for = {
|
url_for = {
|
||||||
AMBIENTE_PRUEBAS: 'https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey=',
|
AMBIENTE_PRUEBAS: (
|
||||||
AMBIENTE_PRODUCCION: 'https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey='
|
'https://catalogo-vpfe-hab.dian.gov.co/document/'
|
||||||
}
|
'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):
|
||||||
@@ -162,21 +189,29 @@ class DianXMLExtensionCUDFE(FachoXMLExtension):
|
|||||||
|
|
||||||
if self.schemeName() == "CUDS-SHA384":
|
if self.schemeName() == "CUDS-SHA384":
|
||||||
if fachoxml.tag_document() == 'Invoice':
|
if fachoxml.tag_document() == 'Invoice':
|
||||||
fachoxml.set_element('./cbc:ProfileID',
|
fachoxml.set_element(
|
||||||
'DIAN 2.1: documento soporte en adquisiciones efectuadas a no obligados a facturar.')
|
'./cbc:ProfileID',
|
||||||
|
'DIAN 2.1: documento soporte en adquisiciones '
|
||||||
|
'efectuadas a no obligados a facturar.')
|
||||||
else:
|
else:
|
||||||
fachoxml.set_element('./cbc:ProfileID',
|
fachoxml.set_element(
|
||||||
'DIAN 2.1: Nota de ajuste al documento soporte en adquisiciones efectuadas a sujetos no obligados a expedir factura o documento equivalente')
|
'./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:
|
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')
|
||||||
|
|
||||||
# #DIAN 1.8.-2021: FAD03
|
# fachoxml.set_element('./cbc:ProfileID',
|
||||||
# fachoxml.set_element('./cbc:ProfileID', 'DIAN 2.1: Factura Electrónica de Venta')
|
# 'DIAN 2.1: Factura Electrónica de Venta')
|
||||||
fachoxml.set_element(
|
fachoxml.set_element(
|
||||||
'./cbc:ProfileExecutionID', self._tipo_ambiente_int())
|
'./cbc:ProfileExecutionID', self._tipo_ambiente_int())
|
||||||
# DIAN 1.7.-2020: FAB36
|
# DIAN 1.7.-2020: FAB36
|
||||||
fachoxml.set_element(
|
fachoxml.set_element(
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:QRCode',
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:QRCode',
|
||||||
self._get_qrcode(cufe))
|
self._get_qrcode(cufe))
|
||||||
|
|
||||||
def issue_time(self, datetime_):
|
def issue_time(self, datetime_):
|
||||||
@@ -192,7 +227,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'] = invoice.invoice_legal_monetary_total.line_extension_amount
|
build_vars['ValorBruto'] = (
|
||||||
|
invoice.invoice_legal_monetary_total.line_extension_amount)
|
||||||
build_vars['ValorTotalPagar'
|
build_vars['ValorTotalPagar'
|
||||||
] = invoice.invoice_legal_monetary_total.payable_amount
|
] = invoice.invoice_legal_monetary_total.payable_amount
|
||||||
ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0))
|
ValorImpuestoPara = defaultdict(lambda: form.Amount(0.0))
|
||||||
@@ -204,7 +240,8 @@ 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(codigo_impuesto, form.Amount(0.0))
|
ValorImpuestoPara.setdefault(
|
||||||
|
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
|
||||||
@@ -244,21 +281,35 @@ class DianXMLExtensionCUFE(DianXMLExtensionCUDFE):
|
|||||||
CodImpuesto2 = build_vars['CodImpuesto2']
|
CodImpuesto2 = build_vars['CodImpuesto2']
|
||||||
CodImpuesto3 = build_vars['CodImpuesto3']
|
CodImpuesto3 = build_vars['CodImpuesto3']
|
||||||
return [
|
return [
|
||||||
'%s' % build_vars['NumFac'],
|
'%s' %
|
||||||
'%s' % build_vars['FecFac'],
|
build_vars['NumFac'],
|
||||||
'%s' % build_vars['HoraFac'],
|
'%s' %
|
||||||
form.Amount(build_vars['ValorBruto']).truncate_as_string(2),
|
build_vars['FecFac'],
|
||||||
|
'%s' %
|
||||||
|
build_vars['HoraFac'],
|
||||||
|
form.Amount(
|
||||||
|
build_vars['ValorBruto']).truncate_as_string(2),
|
||||||
CodImpuesto1,
|
CodImpuesto1,
|
||||||
build_vars['ValorImpuestoPara'].get(CodImpuesto1, form.Amount(0.0)).truncate_as_string(2),
|
build_vars['ValorImpuestoPara'].get(
|
||||||
|
CodImpuesto1,
|
||||||
|
form.Amount(0.0)).truncate_as_string(2),
|
||||||
CodImpuesto2,
|
CodImpuesto2,
|
||||||
build_vars['ValorImpuestoPara'].get(CodImpuesto2, form.Amount(0.0)).truncate_as_string(2),
|
build_vars['ValorImpuestoPara'].get(
|
||||||
|
CodImpuesto2,
|
||||||
|
form.Amount(0.0)).truncate_as_string(2),
|
||||||
CodImpuesto3,
|
CodImpuesto3,
|
||||||
build_vars['ValorImpuestoPara'].get(CodImpuesto3, form.Amount(0.0)).truncate_as_string(2),
|
build_vars['ValorImpuestoPara'].get(
|
||||||
|
CodImpuesto3,
|
||||||
|
form.Amount(0.0)).truncate_as_string(2),
|
||||||
build_vars['ValorTotalPagar'].truncate_as_string(2),
|
build_vars['ValorTotalPagar'].truncate_as_string(2),
|
||||||
'%s' % build_vars['NitOFE'],
|
'%s' %
|
||||||
'%s' % build_vars['NumAdq'],
|
build_vars['NitOFE'],
|
||||||
'%s' % build_vars['ClTec'],
|
'%s' %
|
||||||
'%d' % build_vars['TipoAmb'],
|
build_vars['NumAdq'],
|
||||||
|
'%s' %
|
||||||
|
build_vars['ClTec'],
|
||||||
|
'%d' %
|
||||||
|
build_vars['TipoAmb'],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -282,21 +333,39 @@ class DianXMLExtensionCUDE(DianXMLExtensionCUDFE):
|
|||||||
CodImpuesto2 = build_vars['CodImpuesto2']
|
CodImpuesto2 = build_vars['CodImpuesto2']
|
||||||
CodImpuesto3 = build_vars['CodImpuesto3']
|
CodImpuesto3 = build_vars['CodImpuesto3']
|
||||||
return [
|
return [
|
||||||
'%s' % build_vars['NumFac'],
|
'%s' %
|
||||||
'%s' % build_vars['FecFac'],
|
build_vars['NumFac'],
|
||||||
'%s' % build_vars['HoraFac'],
|
'%s' %
|
||||||
form.Amount(build_vars['ValorBruto']).truncate_as_string(2),
|
build_vars['FecFac'],
|
||||||
|
'%s' %
|
||||||
|
build_vars['HoraFac'],
|
||||||
|
form.Amount(
|
||||||
|
build_vars['ValorBruto']).truncate_as_string(2),
|
||||||
CodImpuesto1,
|
CodImpuesto1,
|
||||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0)).truncate_as_string(2),
|
form.Amount(
|
||||||
|
build_vars['ValorImpuestoPara'].get(
|
||||||
|
CodImpuesto1,
|
||||||
|
0.0)).truncate_as_string(2),
|
||||||
CodImpuesto2,
|
CodImpuesto2,
|
||||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto2, 0.0)).truncate_as_string(2),
|
form.Amount(
|
||||||
|
build_vars['ValorImpuestoPara'].get(
|
||||||
|
CodImpuesto2,
|
||||||
|
0.0)).truncate_as_string(2),
|
||||||
CodImpuesto3,
|
CodImpuesto3,
|
||||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto3, 0.0)).truncate_as_string(2),
|
form.Amount(
|
||||||
form.Amount(build_vars['ValorTotalPagar']).truncate_as_string(2),
|
build_vars['ValorImpuestoPara'].get(
|
||||||
'%s' % build_vars['NitOFE'],
|
CodImpuesto3,
|
||||||
'%s' % build_vars['NumAdq'],
|
0.0)).truncate_as_string(2),
|
||||||
'%s' % build_vars['Software-PIN'],
|
form.Amount(
|
||||||
'%d' % build_vars['TipoAmb'],
|
build_vars['ValorTotalPagar']).truncate_as_string(2),
|
||||||
|
'%s' %
|
||||||
|
build_vars['NitOFE'],
|
||||||
|
'%s' %
|
||||||
|
build_vars['NumAdq'],
|
||||||
|
'%s' %
|
||||||
|
build_vars['Software-PIN'],
|
||||||
|
'%d' %
|
||||||
|
build_vars['TipoAmb'],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -317,20 +386,30 @@ class DianXMLExtensionCUDS(DianXMLExtensionCUDFE):
|
|||||||
def formatVars(self):
|
def formatVars(self):
|
||||||
build_vars = self.buildVars()
|
build_vars = self.buildVars()
|
||||||
CodImpuesto1 = build_vars['CodImpuesto1']
|
CodImpuesto1 = build_vars['CodImpuesto1']
|
||||||
CodImpuesto2 = build_vars['CodImpuesto2']
|
|
||||||
CodImpuesto3 = build_vars['CodImpuesto3']
|
|
||||||
return [
|
return [
|
||||||
'%s' % build_vars['NumFac'],
|
'%s' %
|
||||||
'%s' % build_vars['FecFac'],
|
build_vars['NumFac'],
|
||||||
'%s' % build_vars['HoraFac'],
|
'%s' %
|
||||||
form.Amount(build_vars['ValorBruto']).truncate_as_string(2),
|
build_vars['FecFac'],
|
||||||
|
'%s' %
|
||||||
|
build_vars['HoraFac'],
|
||||||
|
form.Amount(
|
||||||
|
build_vars['ValorBruto']).truncate_as_string(2),
|
||||||
CodImpuesto1,
|
CodImpuesto1,
|
||||||
form.Amount(build_vars['ValorImpuestoPara'].get(CodImpuesto1, 0.0)).truncate_as_string(2),
|
form.Amount(
|
||||||
form.Amount(build_vars['ValorTotalPagar']).truncate_as_string(2),
|
build_vars['ValorImpuestoPara'].get(
|
||||||
'%s' % build_vars['NitOFE'],
|
CodImpuesto1,
|
||||||
'%s' % build_vars['NumAdq'],
|
0.0)).truncate_as_string(2),
|
||||||
'%s' % build_vars['Software-PIN'],
|
form.Amount(
|
||||||
'%d' % build_vars['TipoAmb'],
|
build_vars['ValorTotalPagar']).truncate_as_string(2),
|
||||||
|
'%s' %
|
||||||
|
build_vars['NitOFE'],
|
||||||
|
'%s' %
|
||||||
|
build_vars['NumAdq'],
|
||||||
|
'%s' %
|
||||||
|
build_vars['Software-PIN'],
|
||||||
|
'%d' %
|
||||||
|
build_vars['TipoAmb'],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -344,14 +423,19 @@ class DianXMLExtensionSoftwareProvider(FachoXMLExtension):
|
|||||||
|
|
||||||
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('/sts:SoftwareProvider/sts:ProviderID', self.nit,
|
software_provider.set_element(
|
||||||
|
'/sts:SoftwareProvider/sts:ProviderID',
|
||||||
|
self.nit,
|
||||||
**provider_id_attrs)
|
**provider_id_attrs)
|
||||||
software_provider.set_element('/sts:SoftwareProvider/sts:SoftwareID', self.id_software,
|
software_provider.set_element(
|
||||||
|
'/sts:SoftwareProvider/sts:SoftwareID',
|
||||||
|
self.id_software,
|
||||||
**SCHEME_AGENCY_ATTRS)
|
**SCHEME_AGENCY_ATTRS)
|
||||||
|
|
||||||
|
|
||||||
@@ -364,7 +448,10 @@ class DianXMLExtensionSoftwareSecurityCode(FachoXMLExtension):
|
|||||||
self.invoice_ident = invoice_ident
|
self.invoice_ident = invoice_ident
|
||||||
|
|
||||||
def build(self, fexml):
|
def build(self, fexml):
|
||||||
dian_path = './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareSecurityCode'
|
dian_path = (
|
||||||
|
'./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'))
|
||||||
@@ -418,8 +505,11 @@ class DianXMLExtensionSigner:
|
|||||||
xml.append(signature)
|
xml.append(signature)
|
||||||
|
|
||||||
ref = xmlsig.template.add_reference(
|
ref = xmlsig.template.add_reference(
|
||||||
signature, xmlsig.constants.TransformSha256, uri="", name="xmldsig-%s-ref0" % (id_uuid)
|
signature,
|
||||||
)
|
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)
|
||||||
@@ -438,9 +528,8 @@ class DianXMLExtensionSigner:
|
|||||||
|
|
||||||
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" % (id_props),
|
signature, xmlsig.constants.TransformSha256, uri="#%s" %
|
||||||
uri_type="http://uri.etsi.org/01903#SignedProperties"
|
(id_props), uri_type="http://uri.etsi.org/01903#SignedProperties")
|
||||||
)
|
|
||||||
xmlsig.template.add_transform(
|
xmlsig.template.add_transform(
|
||||||
props_ref, xmlsig.constants.TransformInclC14N)
|
props_ref, xmlsig.constants.TransformInclC14N)
|
||||||
|
|
||||||
@@ -481,7 +570,9 @@ class DianXMLExtensionAuthorizationProvider(FachoXMLExtension):
|
|||||||
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:DianExtensions/sts:AuthorizationProvider')
|
authorization_provider = fexml.fragment(
|
||||||
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:AuthorizationProvider')
|
||||||
authorization_provider.set_element('./sts:AuthorizationProviderID',
|
authorization_provider.set_element('./sts:AuthorizationProviderID',
|
||||||
'800197268',
|
'800197268',
|
||||||
**attrs)
|
**attrs)
|
||||||
@@ -490,12 +581,17 @@ class DianXMLExtensionAuthorizationProvider(FachoXMLExtension):
|
|||||||
class DianXMLExtensionInvoiceSource(FachoXMLExtension):
|
class DianXMLExtensionInvoiceSource(FachoXMLExtension):
|
||||||
# CAB13
|
# CAB13
|
||||||
def build(self, fexml):
|
def build(self, fexml):
|
||||||
dian_path = '/fe:CreditNote/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode'
|
dian_path = (
|
||||||
|
'/fe:CreditNote/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionCo'
|
||||||
|
'ntent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode'
|
||||||
|
)
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
dian_path, 'CO',
|
dian_path, 'CO',
|
||||||
listAgencyID="6",
|
listAgencyID="6",
|
||||||
listAgencyName="United Nations Economic Commission for Europe",
|
listAgencyName="United Nations Economic Commission for Europe",
|
||||||
listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1")
|
listSchemeURI=(
|
||||||
|
"urn:oasis:names:specification:ubl:codelist:gc:"
|
||||||
|
"CountryIdentificationCode-2.1"))
|
||||||
|
|
||||||
|
|
||||||
class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension):
|
class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension):
|
||||||
@@ -512,28 +608,38 @@ class DianXMLExtensionInvoiceAuthorization(FachoXMLExtension):
|
|||||||
self.to = to
|
self.to = to
|
||||||
|
|
||||||
def build(self, fexml):
|
def build(self, fexml):
|
||||||
invoice_control = fexml.fragment('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceControl')
|
invoice_control = fexml.fragment(
|
||||||
invoice_control.set_element('/sts:InvoiceControl/sts:InvoiceAuthorization', self.authorization)
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizationPeriod/cbc:StartDate',
|
':DianExtensions/sts:InvoiceControl')
|
||||||
|
invoice_control.set_element(
|
||||||
|
'/sts:InvoiceControl/sts:InvoiceAuthorization',
|
||||||
|
self.authorization)
|
||||||
|
invoice_control.set_element(
|
||||||
|
'/sts:InvoiceControl/sts:AuthorizationPeriod/cbc:StartDate',
|
||||||
self.period_startdate.strftime('%Y-%m-%d'))
|
self.period_startdate.strftime('%Y-%m-%d'))
|
||||||
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizationPeriod/cbc:EndDate',
|
invoice_control.set_element(
|
||||||
|
'/sts:InvoiceControl/sts:AuthorizationPeriod/cbc:EndDate',
|
||||||
self.period_enddate.strftime('%Y-%m-%d'))
|
self.period_enddate.strftime('%Y-%m-%d'))
|
||||||
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:Prefix',
|
invoice_control.set_element(
|
||||||
|
'/sts:InvoiceControl/sts:AuthorizedInvoices/sts:Prefix',
|
||||||
self.prefix)
|
self.prefix)
|
||||||
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:From',
|
invoice_control.set_element(
|
||||||
self.from_)
|
'/sts:InvoiceControl/sts:AuthorizedInvoices/sts:From', self.from_)
|
||||||
invoice_control.set_element('/sts:InvoiceControl/sts:AuthorizedInvoices/sts:To',
|
invoice_control.set_element(
|
||||||
self.to)
|
'/sts:InvoiceControl/sts:AuthorizedInvoices/sts:To', self.to)
|
||||||
|
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource/cbc:IdentificationCode',
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:InvoiceSource/cbc:IdentificationCode',
|
||||||
'CO',
|
'CO',
|
||||||
# DIAN 1.7.-2020: FAB15
|
# DIAN 1.7.-2020: FAB15
|
||||||
listAgencyID="6",
|
listAgencyID="6",
|
||||||
# DIAN 1.7.-2020: FAB16
|
# DIAN 1.7.-2020: FAB16
|
||||||
listAgencyName="United Nations Economic Commission for Europe",
|
listAgencyName="United Nations Economic Commission for Europe",
|
||||||
# DIAN 1.7.-2020: FAB17
|
# DIAN 1.7.-2020: FAB17
|
||||||
listSchemeURI="urn:oasis:names:specification:ubl:codelist:gc:CountryIdentificationCode-2.1")
|
listSchemeURI=(
|
||||||
|
"urn:oasis:names:specification:ubl:codelist:gc:"
|
||||||
|
"CountryIdentificationCode-2.1"))
|
||||||
|
|
||||||
|
|
||||||
class DianZIP:
|
class DianZIP:
|
||||||
@@ -576,7 +682,11 @@ class DianZIP:
|
|||||||
|
|
||||||
class DianXMLExtensionSignerVerifier:
|
class DianXMLExtensionSignerVerifier:
|
||||||
|
|
||||||
def __init__(self, pkcs12_path_or_bytes, passphrase=None, localpolicy=True):
|
def __init__(
|
||||||
|
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
|
||||||
@@ -610,5 +720,5 @@ class DianXMLExtensionSignerVerifier:
|
|||||||
else:
|
else:
|
||||||
ctx.verify(signature)
|
ctx.verify(signature)
|
||||||
return True
|
return True
|
||||||
except:
|
except BaseException:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
# 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, field
|
||||||
from datetime import datetime, date
|
from datetime import datetime
|
||||||
# from collections import defaultdict
|
# from collections import defaultdict
|
||||||
import decimal
|
import decimal
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
@@ -278,17 +280,6 @@ 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
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ 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.
|
||||||
|
|||||||
@@ -1,7 +1,18 @@
|
|||||||
from .invoice import *
|
from .invoice import DIANInvoiceXML
|
||||||
from .credit_note import *
|
from .credit_note import DIANCreditNoteXML
|
||||||
from .debit_note import *
|
from .debit_note import DIANDebitNoteXML
|
||||||
from .utils import *
|
from .utils import DIANWrite, DIANWriteSigned
|
||||||
from .attached_document import *
|
from .attached_document import AttachedDocument
|
||||||
from .support_document import *
|
from .support_document import DIANSupportDocumentXML
|
||||||
from .support_document_credit_note import *
|
from .support_document_credit_note import DIANSupportDocumentCreditNoteXML
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'DIANInvoiceXML',
|
||||||
|
'DIANCreditNoteXML',
|
||||||
|
'DIANDebitNoteXML',
|
||||||
|
'DIANWrite',
|
||||||
|
'DIANWriteSigned',
|
||||||
|
'AttachedDocument',
|
||||||
|
'DIANSupportDocumentXML',
|
||||||
|
'DIANSupportDocumentCreditNoteXML',
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
from .. import fe
|
|
||||||
from ..form import *
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from .. import fe
|
||||||
|
from ..form import (
|
||||||
|
Amount,
|
||||||
|
CreditNoteDocumentReference,
|
||||||
|
DebitNoteDocumentReference,
|
||||||
|
InvoiceDocumentReference,
|
||||||
|
TaxTotalOmit,
|
||||||
|
WithholdingTaxTotalOmit,
|
||||||
|
)
|
||||||
|
|
||||||
__all__ = ['DIANInvoiceXML']
|
__all__ = ['DIANInvoiceXML']
|
||||||
|
|
||||||
|
|
||||||
class DIANInvoiceXML(fe.FeXML):
|
class DIANInvoiceXML(fe.FeXML):
|
||||||
"""
|
"""
|
||||||
DianInvoiceXML mapea objeto form.Invoice a XML segun
|
DianInvoiceXML mapea objeto form.Invoice a XML segun
|
||||||
@@ -11,16 +20,31 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, invoice, tag_document='Invoice'):
|
def __init__(self, invoice, tag_document='Invoice'):
|
||||||
super().__init__(tag_document, 'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
super().__init__(
|
||||||
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceControl')
|
tag_document,
|
||||||
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource')
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider')
|
self.placeholder_for(
|
||||||
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareSecurityCode')
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
self.placeholder_for('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider/sts:AuthorizationProviderID')
|
':DianExtensions/sts:InvoiceControl')
|
||||||
|
self.placeholder_for(
|
||||||
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:InvoiceSource')
|
||||||
|
self.placeholder_for(
|
||||||
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:SoftwareProvider')
|
||||||
|
self.placeholder_for(
|
||||||
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:SoftwareSecurityCode')
|
||||||
|
self.placeholder_for(
|
||||||
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/'
|
||||||
|
'sts:DianExtensions/sts:AuthorizationProvider/'
|
||||||
|
'sts:AuthorizationProviderID')
|
||||||
|
|
||||||
# ZE02 se requiere existencia para firmar
|
# ZE02 se requiere existencia para firmar
|
||||||
ublextension = self.fragment('./ext:UBLExtensions/ext:UBLExtension', append=True)
|
ublextension = self.fragment(
|
||||||
extcontent = ublextension.find_or_create_element('/ext:UBLExtension/ext:ExtensionContent')
|
'./ext:UBLExtensions/ext:UBLExtension', append=True)
|
||||||
|
ublextension.find_or_create_element(
|
||||||
|
'/ext:UBLExtension/ext:ExtensionContent')
|
||||||
self.attach_invoice(invoice)
|
self.attach_invoice(invoice)
|
||||||
|
|
||||||
def set_supplier(fexml, invoice):
|
def set_supplier(fexml, invoice):
|
||||||
@@ -28,72 +52,99 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
|
|
||||||
# DIAN 1.7.-2020: CAJ02
|
# DIAN 1.7.-2020: CAJ02
|
||||||
# DIAN 1.7.-2020: FAJ02
|
# DIAN 1.7.-2020: FAJ02
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cbc:AdditionalAccountID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cbc:AdditionalAccountID',
|
||||||
invoice.invoice_supplier.organization_code)
|
invoice.invoice_supplier.organization_code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAJ06
|
# DIAN 1.7.-2020: CAJ06
|
||||||
# DIAN 1.7.-2020: FAJ06
|
# DIAN 1.7.-2020: FAJ06
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name',
|
||||||
invoice.invoice_supplier.name)
|
invoice.invoice_supplier.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAJ07, CAJ08
|
# DIAN 1.7.-2020: CAJ07, CAJ08
|
||||||
# DIAN 1.7.-2020: FAJ07
|
# DIAN 1.7.-2020: FAJ07
|
||||||
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ08
|
# DIAN 1.7.-2020: FAJ08
|
||||||
# DIAN 1.7.-2020: CAJ09
|
# DIAN 1.7.-2020: CAJ09
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:ID',
|
||||||
invoice.invoice_supplier.address.city.code)
|
invoice.invoice_supplier.address.city.code)
|
||||||
# DIAN 1.7.-2020: FAJ09
|
# DIAN 1.7.-2020: FAJ09
|
||||||
# DIAN 1.7.-2020: CAJ10
|
# DIAN 1.7.-2020: CAJ10
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CityName',
|
||||||
invoice.invoice_supplier.address.city.name)
|
invoice.invoice_supplier.address.city.name)
|
||||||
# DIAN 1.7.-2020: FAJ11
|
# DIAN 1.7.-2020: FAJ11
|
||||||
# DIAN 1.7.-2020: CAJ11
|
# DIAN 1.7.-2020: CAJ11
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CountrySubentity',
|
||||||
invoice.invoice_supplier.address.countrysubentity.name)
|
invoice.invoice_supplier.address.countrysubentity.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ12
|
# DIAN 1.7.-2020: FAJ12
|
||||||
# DIAN 1.7.-2020: CAJ12
|
# DIAN 1.7.-2020: CAJ12
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CountrySubentityCode',
|
||||||
invoice.invoice_supplier.address.countrysubentity.code)
|
invoice.invoice_supplier.address.countrysubentity.code)
|
||||||
# DIAN 1.7.-2020: FAJ14
|
# DIAN 1.7.-2020: FAJ14
|
||||||
# DIAN 1.7.-2020: CAJ13, CAJ14
|
# DIAN 1.7.-2020: CAJ13, CAJ14
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:AddressLine/cbc:Line',
|
||||||
invoice.invoice_supplier.address.street)
|
invoice.invoice_supplier.address.street)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ16
|
# DIAN 1.7.-2020: FAJ16
|
||||||
# DIAN 1.7.-2020: CAJ16, CAJ16
|
# DIAN 1.7.-2020: CAJ16, CAJ16
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:Country/cbc:IdentificationCode',
|
||||||
invoice.invoice_supplier.address.country.code)
|
invoice.invoice_supplier.address.country.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ17
|
# DIAN 1.7.-2020: FAJ17
|
||||||
# DIAN 1.7.-2020: CAJ17
|
# DIAN 1.7.-2020: CAJ17
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:Country/cbc:Name',
|
||||||
invoice.invoice_supplier.address.country.name,
|
invoice.invoice_supplier.address.country.name,
|
||||||
# DIAN 1.7.-2020: FAJ18
|
# DIAN 1.7.-2020: FAJ18
|
||||||
languageID='es')
|
languageID='es')
|
||||||
|
|
||||||
supplier_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy()
|
supplier_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy()
|
||||||
supplier_company_id_attrs.update({'schemeID': invoice.invoice_supplier.ident.dv,
|
supplier_company_id_attrs.update(
|
||||||
|
{
|
||||||
|
'schemeID': invoice.invoice_supplier.ident.dv,
|
||||||
'schemeName': invoice.invoice_supplier.ident.type_fiscal})
|
'schemeName': invoice.invoice_supplier.ident.type_fiscal})
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ19
|
# DIAN 1.7.-2020: FAJ19
|
||||||
# DIAN 1.7.-2020: CAJ19
|
# DIAN 1.7.-2020: CAJ19
|
||||||
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ20
|
# DIAN 1.7.-2020: FAJ20
|
||||||
# DIAN 1.7.-2020: CAJ20
|
# DIAN 1.7.-2020: CAJ20
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':RegistrationName',
|
||||||
invoice.invoice_supplier.legal_name)
|
invoice.invoice_supplier.legal_name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ21
|
# DIAN 1.7.-2020: FAJ21
|
||||||
# DIAN 1.7.-2020: CAJ21
|
# DIAN 1.7.-2020: CAJ21
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':CompanyID',
|
||||||
invoice.invoice_supplier.ident,
|
invoice.invoice_supplier.ident,
|
||||||
# DIAN 1.7.-2020: FAJ22,FAJ23,FAJ24,FAJ25
|
# DIAN 1.7.-2020: FAJ22,FAJ23,FAJ24,FAJ25
|
||||||
**supplier_company_id_attrs)
|
**supplier_company_id_attrs)
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':TaxLevelCode',
|
||||||
# DIAN 1.7.-2020: FAJ26
|
# DIAN 1.7.-2020: FAJ26
|
||||||
# DIAN 1.7.-2020: CAJ26
|
# DIAN 1.7.-2020: CAJ26
|
||||||
invoice.invoice_supplier.responsability_code,
|
invoice.invoice_supplier.responsability_code,
|
||||||
@@ -102,139 +153,197 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
listName=invoice.invoice_supplier.responsability_regime_code)
|
listName=invoice.invoice_supplier.responsability_regime_code)
|
||||||
# DIAN 1.7.-2020: FAJ28
|
# DIAN 1.7.-2020: FAJ28
|
||||||
# DIAN 1.7.-2020: CAJ28
|
# DIAN 1.7.-2020: CAJ28
|
||||||
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ29
|
# DIAN 1.7.-2020: FAJ29
|
||||||
# DIAN 1.7.-2020: CAJ29
|
# DIAN 1.7.-2020: CAJ29
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:ID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cbc:ID',
|
||||||
invoice.invoice_supplier.address.city.code)
|
invoice.invoice_supplier.address.city.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ30
|
# DIAN 1.7.-2020: FAJ30
|
||||||
# DIAN 1.7.-2020: CAJ30
|
# DIAN 1.7.-2020: CAJ30
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CityName', invoice.invoice_supplier.address.city.name)
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cbc:CityName',
|
||||||
|
invoice.invoice_supplier.address.city.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ31
|
# DIAN 1.7.-2020: FAJ31
|
||||||
# DIAN 1.7.-2020: CAJ31
|
# DIAN 1.7.-2020: CAJ31
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentity',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cbc:CountrySubentity',
|
||||||
invoice.invoice_supplier.address.countrysubentity.name)
|
invoice.invoice_supplier.address.countrysubentity.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ32
|
# DIAN 1.7.-2020: FAJ32
|
||||||
# DIAN 1.7.-2020: CAJ32
|
# DIAN 1.7.-2020: CAJ32
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentityCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cbc:CountrySubentityCode',
|
||||||
invoice.invoice_supplier.address.countrysubentity.code)
|
invoice.invoice_supplier.address.countrysubentity.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ33,FAJ34
|
# DIAN 1.7.-2020: FAJ33,FAJ34
|
||||||
# DIAN 1.7.-2020: CAJ33,CAJ34
|
# DIAN 1.7.-2020: CAJ33,CAJ34
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine/cbc:Line',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:AddressLine/cbc:Line',
|
||||||
invoice.invoice_supplier.address.street)
|
invoice.invoice_supplier.address.street)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ35,FAJ36
|
# DIAN 1.7.-2020: FAJ35,FAJ36
|
||||||
# DIAN 1.7.-2020: CAJ35,CAJ36
|
# DIAN 1.7.-2020: CAJ35,CAJ36
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:IdentificationCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:Country/cbc:IdentificationCode',
|
||||||
invoice.invoice_supplier.address.country.code)
|
invoice.invoice_supplier.address.country.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ37,FAJ38
|
# DIAN 1.7.-2020: FAJ37,FAJ38
|
||||||
# DIAN 1.7.-2020: CAJ37,CAJ38
|
# DIAN 1.7.-2020: CAJ37,CAJ38
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:Name',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:Country/cbc:Name',
|
||||||
invoice.invoice_supplier.address.country.name,
|
invoice.invoice_supplier.address.country.name,
|
||||||
languageID='es')
|
languageID='es')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ39
|
# DIAN 1.7.-2020: FAJ39
|
||||||
# DIAN 1.7.-2020: CAJ39
|
# DIAN 1.7.-2020: CAJ39
|
||||||
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAJ40
|
# DIAN 1.7.-2020: CAJ40
|
||||||
# DIAN 1.7.-2020: FAJ40
|
# DIAN 1.7.-2020: FAJ40
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme/cbc:ID',
|
||||||
invoice.invoice_customer.tax_scheme.code)
|
invoice.invoice_customer.tax_scheme.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAJ41
|
# DIAN 1.7.-2020: CAJ41
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme/cbc:Name',
|
||||||
invoice.invoice_customer.tax_scheme.name)
|
invoice.invoice_customer.tax_scheme.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ42
|
# DIAN 1.7.-2020: FAJ42
|
||||||
# DIAN 1.7.-2020: CAJ42
|
# DIAN 1.7.-2020: CAJ42
|
||||||
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ43
|
# DIAN 1.7.-2020: FAJ43
|
||||||
# DIAN 1.7.-2020: CAJ43
|
# DIAN 1.7.-2020: CAJ43
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc'
|
||||||
|
':RegistrationName',
|
||||||
invoice.invoice_supplier.legal_name)
|
invoice.invoice_supplier.legal_name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ44,FAJ45,FAJ46,FAJ47,FAJ48
|
# DIAN 1.7.-2020: FAJ44,FAJ45,FAJ46,FAJ47,FAJ48
|
||||||
# DIAN 1.7.-2020: CAJ44,CAJ45,CAJ46,CAJ47,CAJ48
|
# DIAN 1.7.-2020: CAJ44,CAJ45,CAJ46,CAJ47,CAJ48
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc'
|
||||||
|
':CompanyID',
|
||||||
invoice.invoice_supplier.ident,
|
invoice.invoice_supplier.ident,
|
||||||
**supplier_company_id_attrs)
|
**supplier_company_id_attrs)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ49
|
# DIAN 1.7.-2020: FAJ49
|
||||||
# DIAN 1.7.-2020: CAJ49
|
# DIAN 1.7.-2020: CAJ49
|
||||||
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cac:CorporateRegistrationScheme')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cac'
|
||||||
|
':CorporateRegistrationScheme')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ50
|
# DIAN 1.7.-2020: FAJ50
|
||||||
# DIAN 1.7.-2020: CAJ50
|
# DIAN 1.7.-2020: CAJ50
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cac:CorporateRegistrationScheme/cbc:ID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cac'
|
||||||
|
':CorporateRegistrationScheme/cbc:ID',
|
||||||
invoice.invoice_ident_prefix)
|
invoice.invoice_ident_prefix)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAJ67
|
# DIAN 1.7.-2020: CAJ67
|
||||||
fexml.placeholder_for('./cac:AccountingSupplierParty/cac:Party/cac:Contact')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:Contact')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAJ71
|
# DIAN 1.7.-2020: FAJ71
|
||||||
# DIAN 1.7.-2020: CAJ71
|
# DIAN 1.7.-2020: CAJ71
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:ElectronicMail',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc'
|
||||||
|
':ElectronicMail',
|
||||||
invoice.invoice_supplier.email)
|
invoice.invoice_supplier.email)
|
||||||
|
|
||||||
|
|
||||||
def set_customer(fexml, invoice):
|
def set_customer(fexml, invoice):
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty')
|
fexml.placeholder_for('./cac:AccountingCustomerParty')
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cbc:AdditionalAccountID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cbc:AdditionalAccountID',
|
||||||
invoice.invoice_customer.organization_code)
|
invoice.invoice_customer.organization_code)
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyIdentification/cbc:ID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyIdentification'
|
||||||
|
'/cbc:ID',
|
||||||
invoice.invoice_customer.ident)
|
invoice.invoice_customer.ident)
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name',
|
||||||
invoice.invoice_customer.name)
|
invoice.invoice_customer.name)
|
||||||
|
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation')
|
||||||
customer_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy()
|
customer_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy()
|
||||||
# DIAN 1.7.-2020: FAK25
|
# DIAN 1.7.-2020: FAK25
|
||||||
# DIAN 1.7.-2020: CAK25
|
# DIAN 1.7.-2020: CAK25
|
||||||
customer_company_id_attrs.update({'schemeID': invoice.invoice_customer.ident.dv,
|
customer_company_id_attrs.update(
|
||||||
|
{
|
||||||
|
'schemeID': invoice.invoice_customer.ident.dv,
|
||||||
'schemeName': invoice.invoice_customer.ident.type_fiscal})
|
'schemeName': invoice.invoice_customer.ident.type_fiscal})
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK07
|
# DIAN 1.7.-2020: FAK07
|
||||||
# DIAN 1.7.-2020: CAK07
|
# DIAN 1.7.-2020: CAK07
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK08
|
# DIAN 1.7.-2020: FAK08
|
||||||
# DIAN 1.7.-2020: CAK08
|
# DIAN 1.7.-2020: CAK08
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:ID',
|
||||||
invoice.invoice_customer.address.city.code)
|
invoice.invoice_customer.address.city.code)
|
||||||
# DIAN 1.7.-2020: FAK09
|
# DIAN 1.7.-2020: FAK09
|
||||||
# DIAN 1.7.-2020: CAK09
|
# DIAN 1.7.-2020: CAK09
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName', invoice.invoice_customer.address.city.name)
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CityName',
|
||||||
|
invoice.invoice_customer.address.city.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK11
|
# DIAN 1.7.-2020: FAK11
|
||||||
# DIAN 1.7.-2020: CAK11
|
# DIAN 1.7.-2020: CAK11
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CountrySubentity',
|
||||||
invoice.invoice_customer.address.countrysubentity.name)
|
invoice.invoice_customer.address.countrysubentity.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK12
|
# DIAN 1.7.-2020: FAK12
|
||||||
# DIAN 1.7.-2020: CAK12
|
# DIAN 1.7.-2020: CAK12
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CountrySubentityCode',
|
||||||
invoice.invoice_customer.address.countrysubentity.code)
|
invoice.invoice_customer.address.countrysubentity.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK13, CAK14
|
# DIAN 1.7.-2020: CAK13, CAK14
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:AddressLine/cbc:Line',
|
||||||
invoice.invoice_customer.address.street)
|
invoice.invoice_customer.address.street)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK16
|
# DIAN 1.7.-2020: CAK16
|
||||||
# DIAN 1.7.-2020: FAK16
|
# DIAN 1.7.-2020: FAK16
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:Country/cbc:IdentificationCode',
|
||||||
invoice.invoice_customer.address.country.code)
|
invoice.invoice_customer.address.country.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK17
|
# DIAN 1.7.-2020: FAK17
|
||||||
# DIAN 1.7.-2020: CAK17
|
# DIAN 1.7.-2020: CAK17
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:Country/cbc:Name',
|
||||||
invoice.invoice_customer.address.country.name,
|
invoice.invoice_customer.address.country.name,
|
||||||
# DIAN 1.7.-2020: FAK18
|
# DIAN 1.7.-2020: FAK18
|
||||||
# DIAN 1.7.-2020: CAK18
|
# DIAN 1.7.-2020: CAK18
|
||||||
@@ -242,22 +351,29 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
|
|
||||||
# DIAN 1.7.-2020: FAK17,FAK19
|
# DIAN 1.7.-2020: FAK17,FAK19
|
||||||
# DIAN 1.7.-2020: CAK19
|
# DIAN 1.7.-2020: CAK19
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK17,FAK20
|
# DIAN 1.7.-2020: FAK17,FAK20
|
||||||
# DIAN 1.7.-2020: CAK20
|
# DIAN 1.7.-2020: CAK20
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':RegistrationName',
|
||||||
invoice.invoice_customer.legal_name)
|
invoice.invoice_customer.legal_name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK21
|
# DIAN 1.7.-2020: CAK21
|
||||||
# DIAN 1.7.-2020: FAK21
|
# DIAN 1.7.-2020: FAK21
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':CompanyID',
|
||||||
invoice.invoice_customer.ident,
|
invoice.invoice_customer.ident,
|
||||||
# DIAN 1.7.-2020: CAK22, CAK23, CAK24, CAK25
|
# DIAN 1.7.-2020: CAK22, CAK23, CAK24, CAK25
|
||||||
**customer_company_id_attrs)
|
**customer_company_id_attrs)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK26
|
# DIAN 1.7.-2020: CAK26
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':TaxLevelCode',
|
||||||
# DIAN 1.7.-2020: FAK26
|
# DIAN 1.7.-2020: FAK26
|
||||||
invoice.invoice_customer.responsability_code,
|
invoice.invoice_customer.responsability_code,
|
||||||
# DIAN 1.7.-2020: FAK27
|
# DIAN 1.7.-2020: FAK27
|
||||||
@@ -266,98 +382,140 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
|
|
||||||
# DIAN 1.7.-2020: FAK28
|
# DIAN 1.7.-2020: FAK28
|
||||||
# DIAN 1.7.-2020: CAK28
|
# DIAN 1.7.-2020: CAK28
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK29
|
# DIAN 1.7.-2020: FAK29
|
||||||
# DIAN 1.7.-2020: CAK29
|
# DIAN 1.7.-2020: CAK29
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:ID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cbc:ID',
|
||||||
invoice.invoice_customer.address.city.code)
|
invoice.invoice_customer.address.city.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK30
|
# DIAN 1.7.-2020: FAK30
|
||||||
# DIAN 1.7.-2020: CAK30
|
# DIAN 1.7.-2020: CAK30
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CityName',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cbc:CityName',
|
||||||
invoice.invoice_customer.address.city.name)
|
invoice.invoice_customer.address.city.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK31
|
# DIAN 1.7.-2020: FAK31
|
||||||
# DIAN 1.7.-2020: CAK31
|
# DIAN 1.7.-2020: CAK31
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentity',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cbc:CountrySubentity',
|
||||||
invoice.invoice_customer.address.countrysubentity.name)
|
invoice.invoice_customer.address.countrysubentity.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK32
|
# DIAN 1.7.-2020: FAK32
|
||||||
# DIAN 1.7.-2020: CAK32
|
# DIAN 1.7.-2020: CAK32
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cbc:CountrySubentityCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cbc:CountrySubentityCode',
|
||||||
invoice.invoice_customer.address.countrysubentity.code)
|
invoice.invoice_customer.address.countrysubentity.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK33
|
# DIAN 1.7.-2020: FAK33
|
||||||
# DIAN 1.7.-2020: CAK33
|
# DIAN 1.7.-2020: CAK33
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:AddressLine')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK34
|
# DIAN 1.7.-2020: FAK34
|
||||||
# DIAN 1.7.-2020: CAK34
|
# DIAN 1.7.-2020: CAK34
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:AddressLine/cbc:Line',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:AddressLine/cbc:Line',
|
||||||
invoice.invoice_customer.address.street)
|
invoice.invoice_customer.address.street)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK35
|
# DIAN 1.7.-2020: CAK35
|
||||||
# DIAN 1.7.-2020: FAK35
|
# DIAN 1.7.-2020: FAK35
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:Country')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK36
|
# DIAN 1.7.-2020: CAK36
|
||||||
# DIAN 1.7.-2020: FAK36
|
# DIAN 1.7.-2020: FAK36
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:IdentificationCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:Country/cbc:IdentificationCode',
|
||||||
invoice.invoice_customer.address.country.code)
|
invoice.invoice_customer.address.country.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK37
|
# DIAN 1.7.-2020: CAK37
|
||||||
# DIAN 1.7.-2020: FAK37
|
# DIAN 1.7.-2020: FAK37
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:Name', invoice.invoice_customer.address.country.name)
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:Country/cbc:Name',
|
||||||
|
invoice.invoice_customer.address.country.name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK38
|
# DIAN 1.7.-2020: FAK38
|
||||||
# DIAN 1.7.-2020: CAK38
|
# DIAN 1.7.-2020: CAK38
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:RegistrationAddress/cac:Country/cbc:IdentificationCode',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':RegistrationAddress/cac:Country/cbc:IdentificationCode',
|
||||||
invoice.invoice_customer.address.country.code,
|
invoice.invoice_customer.address.country.code,
|
||||||
languageID='es')
|
languageID='es')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK39
|
# DIAN 1.7.-2020: CAK39
|
||||||
# DIAN 1.7.-2020: FAK39
|
# DIAN 1.7.-2020: FAK39
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK40 Machete Construir Validación
|
# DIAN 1.7.-2020: CAK40 Machete Construir Validación
|
||||||
# DIAN 1.7.-2020: FAK40
|
# DIAN 1.7.-2020: FAK40
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme/cbc:ID',
|
||||||
invoice.invoice_customer.tax_scheme.code)
|
invoice.invoice_customer.tax_scheme.code)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK41
|
# DIAN 1.7.-2020: FAK41
|
||||||
# DIAN 1.7.-2020: CAK41 Machete Construir Validación
|
# DIAN 1.7.-2020: CAK41 Machete Construir Validación
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme/cbc:Name',
|
||||||
invoice.invoice_customer.tax_scheme.name)
|
invoice.invoice_customer.tax_scheme.name)
|
||||||
# DIAN 1.7.-2020: FAK42
|
# DIAN 1.7.-2020: FAK42
|
||||||
# DIAN 1.7.-2020: CAK42
|
# DIAN 1.7.-2020: CAK42
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK43
|
# DIAN 1.7.-2020: FAK43
|
||||||
# DIAN 1.7.-2020: CAK43
|
# DIAN 1.7.-2020: CAK43
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc'
|
||||||
|
':RegistrationName',
|
||||||
invoice.invoice_customer.legal_name)
|
invoice.invoice_customer.legal_name)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: CAK44
|
# DIAN 1.7.-2020: CAK44
|
||||||
# DIAN 1.7.-2020: FAK44,FAK45,FAK46,FAK47,FAK48
|
# DIAN 1.7.-2020: FAK44,FAK45,FAK46,FAK47,FAK48
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc'
|
||||||
|
':CompanyID',
|
||||||
invoice.invoice_customer.ident,
|
invoice.invoice_customer.ident,
|
||||||
**customer_company_id_attrs)
|
**customer_company_id_attrs)
|
||||||
|
|
||||||
fexml.placeholder_for('./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity')
|
fexml.placeholder_for(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity')
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAK55
|
# DIAN 1.7.-2020: FAK55
|
||||||
# DIAN 1.7.-2020: CAK51, CAK55
|
# DIAN 1.7.-2020: CAK51, CAK55
|
||||||
fexml.set_element('./cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:ElectronicMail',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc'
|
||||||
|
':ElectronicMail',
|
||||||
invoice.invoice_customer.email)
|
invoice.invoice_customer.email)
|
||||||
|
|
||||||
|
|
||||||
def set_payment_mean(fexml, invoice):
|
def set_payment_mean(fexml, invoice):
|
||||||
payment_mean = invoice.invoice_payment_mean
|
payment_mean = invoice.invoice_payment_mean
|
||||||
fexml.set_element('./cac:PaymentMeans/cbc:ID', payment_mean.id)
|
fexml.set_element('./cac:PaymentMeans/cbc:ID', payment_mean.id)
|
||||||
fexml.set_element('./cac:PaymentMeans/cbc:PaymentMeansCode', payment_mean.code)
|
fexml.set_element(
|
||||||
fexml.set_element('./cac:PaymentMeans/cbc:PaymentDueDate', payment_mean.due_at.strftime('%Y-%m-%d'))
|
'./cac:PaymentMeans/cbc:PaymentMeansCode',
|
||||||
fexml.set_element('./cac:PaymentMeans/cbc:PaymentID', payment_mean.payment_id)
|
payment_mean.code)
|
||||||
|
fexml.set_element(
|
||||||
|
'./cac:PaymentMeans/cbc:PaymentDueDate',
|
||||||
|
payment_mean.due_at.strftime('%Y-%m-%d'))
|
||||||
|
fexml.set_element(
|
||||||
|
'./cac:PaymentMeans/cbc:PaymentID',
|
||||||
|
payment_mean.payment_id)
|
||||||
|
|
||||||
def set_element_amount_for(fexml, xml, xpath, amount):
|
def set_element_amount_for(fexml, xml, xpath, amount):
|
||||||
if not isinstance(amount, Amount):
|
if not isinstance(amount, Amount):
|
||||||
@@ -372,38 +530,48 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
fexml.set_element(xpath, amount, currencyID=amount.currency.code)
|
fexml.set_element(xpath, amount, currencyID=amount.currency.code)
|
||||||
|
|
||||||
def set_legal_monetary(fexml, invoice):
|
def set_legal_monetary(fexml, invoice):
|
||||||
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:LineExtensionAmount',
|
fexml.set_element_amount(
|
||||||
|
'./cac:LegalMonetaryTotal/cbc:LineExtensionAmount',
|
||||||
invoice.invoice_legal_monetary_total.line_extension_amount)
|
invoice.invoice_legal_monetary_total.line_extension_amount)
|
||||||
|
|
||||||
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount',
|
fexml.set_element_amount(
|
||||||
|
'./cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount',
|
||||||
invoice.invoice_legal_monetary_total.tax_exclusive_amount)
|
invoice.invoice_legal_monetary_total.tax_exclusive_amount)
|
||||||
|
|
||||||
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount',
|
fexml.set_element_amount(
|
||||||
|
'./cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount',
|
||||||
invoice.invoice_legal_monetary_total.tax_inclusive_amount)
|
invoice.invoice_legal_monetary_total.tax_inclusive_amount)
|
||||||
|
|
||||||
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:ChargeTotalAmount',
|
fexml.set_element_amount(
|
||||||
|
'./cac:LegalMonetaryTotal/cbc:ChargeTotalAmount',
|
||||||
invoice.invoice_legal_monetary_total.charge_total_amount)
|
invoice.invoice_legal_monetary_total.charge_total_amount)
|
||||||
|
|
||||||
fexml.set_element_amount('./cac:LegalMonetaryTotal/cbc:PayableAmount',
|
fexml.set_element_amount(
|
||||||
|
'./cac:LegalMonetaryTotal/cbc:PayableAmount',
|
||||||
invoice.invoice_legal_monetary_total.payable_amount)
|
invoice.invoice_legal_monetary_total.payable_amount)
|
||||||
|
|
||||||
|
|
||||||
def _set_invoice_document_reference(fexml, reference):
|
def _set_invoice_document_reference(fexml, reference):
|
||||||
fexml._do_set_billing_reference(reference, 'cac:InvoiceDocumentReference')
|
fexml._do_set_billing_reference(
|
||||||
|
reference, 'cac:InvoiceDocumentReference')
|
||||||
|
|
||||||
def _set_credit_note_document_reference(fexml, reference):
|
def _set_credit_note_document_reference(fexml, reference):
|
||||||
fexml._do_set_billing_reference(reference, 'cac:CreditNoteDocumentReference')
|
fexml._do_set_billing_reference(
|
||||||
|
reference, 'cac:CreditNoteDocumentReference')
|
||||||
|
|
||||||
def _set_debit_note_document_reference(fexml, reference):
|
def _set_debit_note_document_reference(fexml, reference):
|
||||||
fexml._do_set_billing_reference(reference, 'cac:DebitNoteDocumentReference')
|
fexml._do_set_billing_reference(
|
||||||
|
reference, 'cac:DebitNoteDocumentReference')
|
||||||
|
|
||||||
def _do_set_billing_reference(fexml, reference, tag_document):
|
def _do_set_billing_reference(fexml, reference, tag_document):
|
||||||
fexml.set_element('./cac:BillingReference/%s/cbc:ID' % (tag_document),
|
fexml.set_element('./cac:BillingReference/%s/cbc:ID' % (tag_document),
|
||||||
reference.ident)
|
reference.ident)
|
||||||
fexml.set_element('./cac:BillingReference/cac:InvoiceDocumentReference/cbc:UUID',
|
fexml.set_element(
|
||||||
|
'./cac:BillingReference/cac:InvoiceDocumentReference/cbc:UUID',
|
||||||
reference.uuid,
|
reference.uuid,
|
||||||
schemeName='CUFE-SHA384')
|
schemeName='CUFE-SHA384')
|
||||||
fexml.set_element('./cac:BillingReference/cac:InvoiceDocumentReference/cbc:IssueDate',
|
fexml.set_element(
|
||||||
|
'./cac:BillingReference/cac:InvoiceDocumentReference/'
|
||||||
|
'cbc:IssueDate',
|
||||||
reference.date.strftime("%Y-%m-%d"))
|
reference.date.strftime("%Y-%m-%d"))
|
||||||
|
|
||||||
def set_billing_reference(fexml, invoice):
|
def set_billing_reference(fexml, invoice):
|
||||||
@@ -421,7 +589,8 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
|
|
||||||
def set_invoice_totals(fexml, invoice):
|
def set_invoice_totals(fexml, invoice):
|
||||||
tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0)))
|
tax_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0)))
|
||||||
withholding_amount_for = defaultdict(lambda: defaultdict(lambda: Amount(0.0)))
|
withholding_amount_for = defaultdict(
|
||||||
|
lambda: defaultdict(lambda: Amount(0.0)))
|
||||||
percent_for = defaultdict(lambda: None)
|
percent_for = defaultdict(lambda: None)
|
||||||
|
|
||||||
# requeridos para CUFE
|
# requeridos para CUFE
|
||||||
@@ -439,9 +608,12 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
for invoice_line in invoice.invoice_lines:
|
for invoice_line in invoice.invoice_lines:
|
||||||
for subtotal in invoice_line.tax.subtotals:
|
for subtotal in invoice_line.tax.subtotals:
|
||||||
if subtotal.scheme is not None:
|
if subtotal.scheme is not None:
|
||||||
tax_amount_for[subtotal.scheme.code]['tax_amount'] += subtotal.tax_amount
|
scheme = subtotal.scheme.code
|
||||||
tax_amount_for[subtotal.scheme.code]['taxable_amount'] += invoice_line.taxable_amount
|
tax_amount_for[scheme][
|
||||||
tax_amount_for[subtotal.scheme.code]['name'] = subtotal.scheme.name
|
'tax_amount'] += subtotal.tax_amount
|
||||||
|
tax_amount_for[scheme][
|
||||||
|
'taxable_amount'] += invoice_line.taxable_amount
|
||||||
|
tax_amount_for[scheme]['name'] = subtotal.scheme.name
|
||||||
|
|
||||||
# MACHETE ojo InvoiceLine.tax pasar a Invoice
|
# MACHETE ojo InvoiceLine.tax pasar a Invoice
|
||||||
percent_for[subtotal.scheme.code] = subtotal.percent
|
percent_for[subtotal.scheme.code] = subtotal.percent
|
||||||
@@ -450,12 +622,16 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
|
|
||||||
for subtotal_withholding in invoice_line.withholding.subtotals:
|
for subtotal_withholding in invoice_line.withholding.subtotals:
|
||||||
if subtotal_withholding.scheme is not None:
|
if subtotal_withholding.scheme is not None:
|
||||||
withholding_amount_for[subtotal_withholding.scheme.code]['tax_amount'] += subtotal_withholding.tax_amount
|
scheme = subtotal_withholding.scheme.code
|
||||||
withholding_amount_for[subtotal_withholding.scheme.code]['taxable_amount'] += invoice_line.withholding_taxable_amount
|
withholding_amount_for[scheme][
|
||||||
|
'tax_amount'] += subtotal_withholding.tax_amount
|
||||||
|
withholding_amount_for[scheme][
|
||||||
|
'taxable_amount'] += (
|
||||||
|
invoice_line.withholding_taxable_amount)
|
||||||
|
|
||||||
# MACHETE ojo InvoiceLine.tax pasar a Invoice
|
# MACHETE ojo InvoiceLine.tax pasar a Invoice
|
||||||
|
|
||||||
percent_for[subtotal_withholding.scheme.code] = subtotal_withholding.percent
|
percent_for[scheme] = subtotal_withholding.percent
|
||||||
|
|
||||||
total_withholding_amount += subtotal_withholding.tax_amount
|
total_withholding_amount += subtotal_withholding.tax_amount
|
||||||
|
|
||||||
@@ -477,12 +653,14 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
tax_amount)
|
tax_amount)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAS05
|
# DIAN 1.7.-2020: FAS05
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(
|
||||||
|
line,
|
||||||
'/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
'/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
||||||
amount_of['taxable_amount'])
|
amount_of['taxable_amount'])
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAU06
|
# DIAN 1.7.-2020: FAU06
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(
|
||||||
|
line,
|
||||||
'/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount',
|
'/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount',
|
||||||
amount_of['tax_amount'])
|
amount_of['tax_amount'])
|
||||||
|
|
||||||
@@ -491,14 +669,19 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cbc:Percent',
|
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cbc:Percent',
|
||||||
percent_for[cod_impuesto])
|
percent_for[cod_impuesto])
|
||||||
|
|
||||||
|
|
||||||
if percent_for[cod_impuesto]:
|
if percent_for[cod_impuesto]:
|
||||||
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent',
|
line.set_element(
|
||||||
|
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/'
|
||||||
|
'cbc:Percent',
|
||||||
percent_for[cod_impuesto])
|
percent_for[cod_impuesto])
|
||||||
|
|
||||||
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
|
line.set_element(
|
||||||
|
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme'
|
||||||
|
'/cbc:ID',
|
||||||
cod_impuesto)
|
cod_impuesto)
|
||||||
line.set_element('/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name',
|
line.set_element(
|
||||||
|
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme'
|
||||||
|
'/cbc:Name',
|
||||||
amount_of['name'])
|
amount_of['name'])
|
||||||
|
|
||||||
for index, item in enumerate(withholding_amount_for.items()):
|
for index, item in enumerate(withholding_amount_for.items()):
|
||||||
@@ -506,36 +689,45 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
next_append = index > 0
|
next_append = index > 0
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAS01
|
# DIAN 1.7.-2020: FAS01
|
||||||
line = fexml.fragment('./cac:WithholdingTaxTotal', append=next_append)
|
line = fexml.fragment(
|
||||||
|
'./cac:WithholdingTaxTotal',
|
||||||
|
append=next_append)
|
||||||
# DIAN 1.7.-2020: FAU06
|
# DIAN 1.7.-2020: FAU06
|
||||||
tax_amount = amount_of['tax_amount']
|
tax_amount = amount_of['tax_amount']
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(
|
||||||
'/cac:WithholdingTaxTotal/cbc:TaxAmount',
|
line, '/cac:WithholdingTaxTotal/cbc:TaxAmount', tax_amount)
|
||||||
tax_amount)
|
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAS05
|
# DIAN 1.7.-2020: FAS05
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(
|
||||||
|
line,
|
||||||
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
||||||
amount_of['taxable_amount'])
|
amount_of['taxable_amount'])
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAU06
|
# DIAN 1.7.-2020: FAU06
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(
|
||||||
|
line,
|
||||||
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount',
|
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount',
|
||||||
amount_of['tax_amount'])
|
amount_of['tax_amount'])
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAS07
|
# DIAN 1.7.-2020: FAS07
|
||||||
if percent_for[cod_impuesto]:
|
if percent_for[cod_impuesto]:
|
||||||
line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:Percent',
|
line.set_element(
|
||||||
|
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:Percent',
|
||||||
percent_for[cod_impuesto])
|
percent_for[cod_impuesto])
|
||||||
|
|
||||||
|
|
||||||
if percent_for[cod_impuesto]:
|
if percent_for[cod_impuesto]:
|
||||||
line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent',
|
line.set_element(
|
||||||
|
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory'
|
||||||
|
'/cbc:Percent',
|
||||||
percent_for[cod_impuesto])
|
percent_for[cod_impuesto])
|
||||||
|
|
||||||
line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
|
line.set_element(
|
||||||
|
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac'
|
||||||
|
':TaxScheme/cbc:ID',
|
||||||
cod_impuesto)
|
cod_impuesto)
|
||||||
line.set_element('/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name',
|
line.set_element(
|
||||||
|
'/cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac'
|
||||||
|
':TaxScheme/cbc:Name',
|
||||||
'ReteRenta')
|
'ReteRenta')
|
||||||
|
|
||||||
# abstract method
|
# abstract method
|
||||||
@@ -552,50 +744,87 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
invoice_line.tax_amount)
|
invoice_line.tax_amount)
|
||||||
|
|
||||||
# DIAN 1.7.-2020: FAX05
|
# DIAN 1.7.-2020: FAX05
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(
|
||||||
|
line,
|
||||||
'./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
'./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
||||||
invoice_line.taxable_amount)
|
invoice_line.taxable_amount)
|
||||||
for subtotal in invoice_line.tax.subtotals:
|
for subtotal in invoice_line.tax.subtotals:
|
||||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP')
|
line.set_element(
|
||||||
|
'./cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount',
|
||||||
|
subtotal.tax_amount,
|
||||||
|
currencyID='COP')
|
||||||
|
|
||||||
if subtotal.percent is not None:
|
if subtotal.percent is not None:
|
||||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', '%0.2f' % round(subtotal.percent, 2))
|
line.set_element(
|
||||||
|
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc'
|
||||||
|
':Percent',
|
||||||
|
'%0.2f' %
|
||||||
|
round(
|
||||||
|
subtotal.percent,
|
||||||
|
2))
|
||||||
|
|
||||||
if subtotal.scheme is not None:
|
if subtotal.scheme is not None:
|
||||||
# DIAN 1.7.-2020: FAX15
|
# DIAN 1.7.-2020: FAX15
|
||||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code)
|
line.set_element(
|
||||||
line.set_element('./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name)
|
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac'
|
||||||
|
':TaxScheme/cbc:ID',
|
||||||
|
subtotal.scheme.code)
|
||||||
|
line.set_element(
|
||||||
|
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac'
|
||||||
|
':TaxScheme/cbc:Name',
|
||||||
|
subtotal.scheme.name)
|
||||||
|
|
||||||
def set_invoice_line_withholding(fexml, line, invoice_line):
|
def set_invoice_line_withholding(fexml, line, invoice_line):
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(line,
|
||||||
'./cac:WithholdingTaxTotal/cbc:TaxAmount',
|
'./cac:WithholdingTaxTotal/cbc:TaxAmount',
|
||||||
invoice_line.withholding_amount)
|
invoice_line.withholding_amount)
|
||||||
# DIAN 1.7.-2020: FAX05
|
# DIAN 1.7.-2020: FAX05
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(
|
||||||
|
line,
|
||||||
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxableAmount',
|
||||||
invoice_line.withholding_taxable_amount)
|
invoice_line.withholding_taxable_amount)
|
||||||
|
|
||||||
for subtotal in invoice_line.withholding.subtotals:
|
for subtotal in invoice_line.withholding.subtotals:
|
||||||
line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount', subtotal.tax_amount, currencyID='COP')
|
line.set_element(
|
||||||
|
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cbc:TaxAmount',
|
||||||
|
subtotal.tax_amount,
|
||||||
|
currencyID='COP')
|
||||||
|
|
||||||
if subtotal.percent is not None:
|
if subtotal.percent is not None:
|
||||||
line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent', '%0.2f' % round(subtotal.percent, 2))
|
line.set_element(
|
||||||
|
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac'
|
||||||
|
':TaxCategory/cbc:Percent',
|
||||||
|
'%0.2f' %
|
||||||
|
round(
|
||||||
|
subtotal.percent,
|
||||||
|
2))
|
||||||
|
|
||||||
if subtotal.scheme is not None:
|
if subtotal.scheme is not None:
|
||||||
# DIAN 1.7.-2020: FAX15
|
# DIAN 1.7.-2020: FAX15
|
||||||
line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID', subtotal.scheme.code)
|
line.set_element(
|
||||||
line.set_element('./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', subtotal.scheme.name)
|
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac'
|
||||||
|
':TaxCategory/cac:TaxScheme/cbc:ID',
|
||||||
|
subtotal.scheme.code)
|
||||||
|
line.set_element(
|
||||||
|
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac'
|
||||||
|
':TaxCategory/cac:TaxScheme/cbc:Name',
|
||||||
|
subtotal.scheme.name)
|
||||||
|
|
||||||
def set_invoice_lines(fexml, invoice):
|
def set_invoice_lines(fexml, invoice):
|
||||||
next_append = False
|
next_append = False
|
||||||
for index, invoice_line in enumerate(invoice.invoice_lines):
|
for index, invoice_line in enumerate(invoice.invoice_lines):
|
||||||
line = fexml.fragment('./cac:%sLine' % (fexml.tag_document()), append=next_append)
|
line = fexml.fragment(
|
||||||
|
'./cac:%sLine' %
|
||||||
|
(fexml.tag_document()),
|
||||||
|
append=next_append)
|
||||||
next_append = True
|
next_append = True
|
||||||
|
|
||||||
line.set_element('./cbc:ID', index + 1)
|
line.set_element('./cbc:ID', index + 1)
|
||||||
line.set_element('./cbc:%sQuantity' % (fexml.tag_document_concilied()), invoice_line.quantity, unitCode = 'NAR')
|
line.set_element(
|
||||||
|
'./cbc:%sQuantity' %
|
||||||
|
(fexml.tag_document_concilied()),
|
||||||
|
invoice_line.quantity,
|
||||||
|
unitCode='NAR')
|
||||||
fexml.set_element_amount_for(line,
|
fexml.set_element_amount_for(line,
|
||||||
'./cbc:LineExtensionAmount',
|
'./cbc:LineExtensionAmount',
|
||||||
invoice_line.total_amount)
|
invoice_line.total_amount)
|
||||||
@@ -603,18 +832,26 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
if not isinstance(invoice_line.tax, TaxTotalOmit):
|
if not isinstance(invoice_line.tax, TaxTotalOmit):
|
||||||
fexml.set_invoice_line_tax(line, invoice_line)
|
fexml.set_invoice_line_tax(line, invoice_line)
|
||||||
|
|
||||||
if not isinstance(invoice_line.withholding, WithholdingTaxTotalOmit):
|
if not isinstance(
|
||||||
|
invoice_line.withholding,
|
||||||
|
WithholdingTaxTotalOmit):
|
||||||
fexml.set_invoice_line_withholding(line, invoice_line)
|
fexml.set_invoice_line_withholding(line, invoice_line)
|
||||||
|
|
||||||
line.set_element('./cac:Item/cbc:Description', invoice_line.item.description)
|
line.set_element(
|
||||||
|
'./cac:Item/cbc:Description',
|
||||||
|
invoice_line.item.description)
|
||||||
|
|
||||||
line.set_element('./cac:Item/cac:StandardItemIdentification/cbc:ID',
|
line.set_element(
|
||||||
|
'./cac:Item/cac:StandardItemIdentification/cbc:ID',
|
||||||
invoice_line.item.id,
|
invoice_line.item.id,
|
||||||
schemeID=invoice_line.item.scheme_id,
|
schemeID=invoice_line.item.scheme_id,
|
||||||
schemeName=invoice_line.item.scheme_name,
|
schemeName=invoice_line.item.scheme_name,
|
||||||
schemeAgencyID=invoice_line.item.scheme_agency_id)
|
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)
|
line.set_element(
|
||||||
|
'./cac:Price/cbc:PriceAmount',
|
||||||
|
invoice_line.price.amount,
|
||||||
|
currencyID=invoice_line.price.amount.currency.code)
|
||||||
# DIAN 1.7.-2020: FBB04
|
# DIAN 1.7.-2020: FBB04
|
||||||
line.set_element('./cac:Price/cbc:BaseQuantity',
|
line.set_element('./cac:Price/cbc:BaseQuantity',
|
||||||
invoice_line.price.quantity,
|
invoice_line.price.quantity,
|
||||||
@@ -622,7 +859,8 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
|
|
||||||
for idx, charge in enumerate(invoice_line.allowance_charge):
|
for idx, charge in enumerate(invoice_line.allowance_charge):
|
||||||
next_append_charge = idx > 0
|
next_append_charge = idx > 0
|
||||||
fexml.append_allowance_charge(line, index + 1, charge, append=next_append_charge)
|
fexml.append_allowance_charge(
|
||||||
|
line, index + 1, charge, append=next_append_charge)
|
||||||
|
|
||||||
def set_allowance_charge(fexml, invoice):
|
def set_allowance_charge(fexml, invoice):
|
||||||
for idx, charge in enumerate(invoice.invoice_allowance_charge):
|
for idx, charge in enumerate(invoice.invoice_allowance_charge):
|
||||||
@@ -656,18 +894,28 @@ class DIANInvoiceXML(fe.FeXML):
|
|||||||
|
|
||||||
fexml.placeholder_for('./ext:UBLExtensions')
|
fexml.placeholder_for('./ext:UBLExtensions')
|
||||||
fexml.set_element('./cbc:UBLVersionID', 'UBL 2.1')
|
fexml.set_element('./cbc:UBLVersionID', 'UBL 2.1')
|
||||||
fexml.set_element('./cbc:CustomizationID', invoice.invoice_operation_type)
|
fexml.set_element(
|
||||||
|
'./cbc:CustomizationID',
|
||||||
|
invoice.invoice_operation_type)
|
||||||
fexml.placeholder_for('./cbc:ProfileID')
|
fexml.placeholder_for('./cbc:ProfileID')
|
||||||
fexml.placeholder_for('./cbc:ProfileExecutionID')
|
fexml.placeholder_for('./cbc:ProfileExecutionID')
|
||||||
fexml.set_element('./cbc:ID', invoice.invoice_ident)
|
fexml.set_element('./cbc:ID', invoice.invoice_ident)
|
||||||
fexml.placeholder_for('./cbc:UUID')
|
fexml.placeholder_for('./cbc:UUID')
|
||||||
fexml.set_element('./cbc:IssueDate', invoice.invoice_issue.strftime('%Y-%m-%d'))
|
fexml.set_element(
|
||||||
|
'./cbc:IssueDate',
|
||||||
|
invoice.invoice_issue.strftime('%Y-%m-%d'))
|
||||||
# DIAN 1.7.-2020: FAD10
|
# DIAN 1.7.-2020: FAD10
|
||||||
fexml.set_element('./cbc:IssueTime', invoice.invoice_issue.strftime('%H:%M:%S-05:00'))
|
fexml.set_element(
|
||||||
fexml.set_element('./cbc:%sTypeCode' % (fexml.tag_document()),
|
'./cbc:IssueTime',
|
||||||
|
invoice.invoice_issue.strftime('%H:%M:%S-05:00'))
|
||||||
|
fexml.set_element(
|
||||||
|
'./cbc:%sTypeCode' %
|
||||||
|
(fexml.tag_document()),
|
||||||
invoice.invoice_type_code,
|
invoice.invoice_type_code,
|
||||||
listAgencyID='195',
|
listAgencyID='195',
|
||||||
listAgencyName='No matching global declaration available for the validation root',
|
listAgencyName=(
|
||||||
|
'No matching global declaration available for the '
|
||||||
|
'validation root'),
|
||||||
listURI='http://www.dian.gov.co')
|
listURI='http://www.dian.gov.co')
|
||||||
fexml.set_element('./cbc:DocumentCurrencyCode', 'COP')
|
fexml.set_element('./cbc:DocumentCurrencyCode', 'COP')
|
||||||
fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines))
|
fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines))
|
||||||
|
|||||||
@@ -14,36 +14,45 @@ __all__ = ['DIANSupportDocumentXML']
|
|||||||
class DIANSupportDocumentXML(fe.FeXML):
|
class DIANSupportDocumentXML(fe.FeXML):
|
||||||
"""
|
"""
|
||||||
DianSupportDocumentXML mapea objeto form.Invoice a XML segun
|
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.
|
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'):
|
def __init__(self, invoice, tag_document='Invoice'):
|
||||||
super().__init__(tag_document, 'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
super().__init__(
|
||||||
|
tag_document,
|
||||||
|
'http://www.dian.gov.co/contratos/facturaelectronica/v1')
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAB03
|
# DIAN 1.1.-2021: DSAB03
|
||||||
# DIAN 1.1.-2021: NSAB03
|
# DIAN 1.1.-2021: NSAB03
|
||||||
self.placeholder_for(
|
self.placeholder_for(
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceControl')
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:InvoiceControl')
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAB13
|
# DIAN 1.1.-2021: DSAB13
|
||||||
# DIAN 1.1.-2021: NSAB13
|
# DIAN 1.1.-2021: NSAB13
|
||||||
self.placeholder_for(
|
self.placeholder_for(
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:InvoiceSource')
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:InvoiceSource')
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAB18
|
# DIAN 1.1.-2021: DSAB18
|
||||||
# DIAN 1.1.-2021: NSAB18
|
# DIAN 1.1.-2021: NSAB18
|
||||||
self.placeholder_for(
|
self.placeholder_for(
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareProvider')
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:SoftwareProvider')
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAB27
|
# DIAN 1.1.-2021: DSAB27
|
||||||
# DIAN 1.1.-2021: NSAB27
|
# DIAN 1.1.-2021: NSAB27
|
||||||
self.placeholder_for(
|
self.placeholder_for(
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:SoftwareSecurityCode')
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts'
|
||||||
|
':DianExtensions/sts:SoftwareSecurityCode')
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAB30 DSAB31
|
# DIAN 1.1.-2021: DSAB30 DSAB31
|
||||||
# DIAN 1.1.-2021: NSAB30 NSAB31
|
# DIAN 1.1.-2021: NSAB30 NSAB31
|
||||||
self.placeholder_for(
|
self.placeholder_for(
|
||||||
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/sts:DianExtensions/sts:AuthorizationProvider/sts:AuthorizationProviderID')
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent/'
|
||||||
|
'sts:DianExtensions/sts:AuthorizationProvider/'
|
||||||
|
'sts:AuthorizationProviderID')
|
||||||
|
|
||||||
# ZE02 se requiere existencia para firmar
|
# ZE02 se requiere existencia para firmar
|
||||||
# DIAN 1.1.-2021: DSAA02 DSAB01
|
# DIAN 1.1.-2021: DSAA02 DSAB01
|
||||||
@@ -52,7 +61,7 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
'./ext:UBLExtensions/ext:UBLExtension', append=True)
|
'./ext:UBLExtensions/ext:UBLExtension', append=True)
|
||||||
# DIAN 1.1.-2021: DSAB02
|
# DIAN 1.1.-2021: DSAB02
|
||||||
# DIAN 1.1.-2021: NSAB02
|
# DIAN 1.1.-2021: NSAB02
|
||||||
extcontent = ublextension.find_or_create_element(
|
ublextension.find_or_create_element(
|
||||||
'/ext:UBLExtension/ext:ExtensionContent')
|
'/ext:UBLExtension/ext:ExtensionContent')
|
||||||
self.attach_invoice(invoice)
|
self.attach_invoice(invoice)
|
||||||
|
|
||||||
@@ -70,51 +79,61 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
# DIAN 1.1.-2021: DSAJ07 DSAJ08
|
# DIAN 1.1.-2021: DSAJ07 DSAJ08
|
||||||
# DIAN 1.1.-2021: NSAJ07 NSAJ08
|
# DIAN 1.1.-2021: NSAJ07 NSAJ08
|
||||||
fexml.placeholder_for(
|
fexml.placeholder_for(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address')
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address')
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ09
|
# DIAN 1.1.-2021: DSAJ09
|
||||||
# DIAN 1.1.-2021: NSAJ09
|
# DIAN 1.1.-2021: NSAJ09
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:ID',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:ID',
|
||||||
invoice.invoice_supplier.address.city.code)
|
invoice.invoice_supplier.address.city.code)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ10
|
# DIAN 1.1.-2021: DSAJ10
|
||||||
# DIAN 1.1.-2021: NSAJ10
|
# DIAN 1.1.-2021: NSAJ10
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CityName',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CityName',
|
||||||
invoice.invoice_supplier.address.city.name)
|
invoice.invoice_supplier.address.city.name)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ73
|
# DIAN 1.1.-2021: DSAJ73
|
||||||
# DIAN 1.1.-2021: NSAJ73
|
# DIAN 1.1.-2021: NSAJ73
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:PostalZone',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:PostalZone',
|
||||||
invoice.invoice_supplier.address.postalzone.code)
|
invoice.invoice_supplier.address.postalzone.code)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ11
|
# DIAN 1.1.-2021: DSAJ11
|
||||||
# DIAN 1.1.-2021: NSAJ11
|
# DIAN 1.1.-2021: NSAJ11
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentity',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CountrySubentity',
|
||||||
invoice.invoice_supplier.address.countrysubentity.name)
|
invoice.invoice_supplier.address.countrysubentity.name)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ12
|
# DIAN 1.1.-2021: DSAJ12
|
||||||
# DIAN 1.1.-2021: NSAJ12
|
# DIAN 1.1.-2021: NSAJ12
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cbc:CountrySubentityCode',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cbc:CountrySubentityCode',
|
||||||
invoice.invoice_supplier.address.countrysubentity.code)
|
invoice.invoice_supplier.address.countrysubentity.code)
|
||||||
# DIAN 1.1.-2021: NSAJ13 NSAJ14
|
# DIAN 1.1.-2021: NSAJ13 NSAJ14
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:AddressLine/cbc:Line',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:AddressLine/cbc:Line',
|
||||||
invoice.invoice_supplier.address.street)
|
invoice.invoice_supplier.address.street)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ15 DSAJ16
|
# DIAN 1.1.-2021: DSAJ15 DSAJ16
|
||||||
# DIAN 1.1.-2021: NSAJ15 NSAJ16
|
# DIAN 1.1.-2021: NSAJ15 NSAJ16
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:IdentificationCode',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:Country/cbc:IdentificationCode',
|
||||||
invoice.invoice_supplier.address.country.code)
|
invoice.invoice_supplier.address.country.code)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ17
|
# DIAN 1.1.-2021: DSAJ17
|
||||||
# DIAN 1.1.-2021: NSAJ17
|
# DIAN 1.1.-2021: NSAJ17
|
||||||
fexml.set_element('./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac:Address/cac:Country/cbc:Name',
|
fexml.set_element(
|
||||||
|
'./cac:AccountingSupplierParty/cac:Party/cac:PhysicalLocation/cac'
|
||||||
|
':Address/cac:Country/cbc:Name',
|
||||||
invoice.invoice_supplier.address.country.name,
|
invoice.invoice_supplier.address.country.name,
|
||||||
# DIAN 1.1.-2021: DSAJ18
|
# DIAN 1.1.-2021: DSAJ18
|
||||||
# # DIAN 1.1.-2021: NSAJ18
|
# # DIAN 1.1.-2021: NSAJ18
|
||||||
@@ -134,13 +153,15 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
# DIAN 1.1.-2021: DSAJ20
|
# DIAN 1.1.-2021: DSAJ20
|
||||||
# DIAN 1.1.-2021: NSAJ20
|
# DIAN 1.1.-2021: NSAJ20
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':RegistrationName',
|
||||||
invoice.invoice_supplier.legal_name)
|
invoice.invoice_supplier.legal_name)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ21
|
# DIAN 1.1.-2021: DSAJ21
|
||||||
# DIAN 1.1.-2021: NSAJ21
|
# DIAN 1.1.-2021: NSAJ21
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':CompanyID',
|
||||||
invoice.invoice_supplier.ident,
|
invoice.invoice_supplier.ident,
|
||||||
# DIAN 1.1.-2021: DSAJ22 DSAJ23 DSAJ24 DSAJ25
|
# DIAN 1.1.-2021: DSAJ22 DSAJ23 DSAJ24 DSAJ25
|
||||||
# DIAN 1.1.-2021: NSAJ22 NSAJ23 NSAJ24 NSAJ25
|
# DIAN 1.1.-2021: NSAJ22 NSAJ23 NSAJ24 NSAJ25
|
||||||
@@ -149,25 +170,29 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
# DIAN 1.1.-2021: DSAJ26
|
# DIAN 1.1.-2021: DSAJ26
|
||||||
# DIAN 1.1.-2021: NSAJ26
|
# DIAN 1.1.-2021: NSAJ26
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':TaxLevelCode',
|
||||||
invoice.invoice_supplier.responsability_code,
|
invoice.invoice_supplier.responsability_code,
|
||||||
listName=invoice.invoice_supplier.responsability_regime_code)
|
listName=invoice.invoice_supplier.responsability_regime_code)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ39
|
# DIAN 1.1.-2021: DSAJ39
|
||||||
# DIAN 1.1.-2021: NSAJ39
|
# DIAN 1.1.-2021: NSAJ39
|
||||||
fexml.placeholder_for(
|
fexml.placeholder_for(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme')
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme')
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ40
|
# DIAN 1.1.-2021: DSAJ40
|
||||||
# DIAN 1.1.-2021: NSAJ40
|
# DIAN 1.1.-2021: NSAJ40
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme/cbc:ID',
|
||||||
invoice.invoice_customer.tax_scheme.code)
|
invoice.invoice_customer.tax_scheme.code)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAJ41
|
# DIAN 1.1.-2021: DSAJ41
|
||||||
# DIAN 1.1.-2021: NSAJ41
|
# DIAN 1.1.-2021: NSAJ41
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
|
'./cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme/cbc:Name',
|
||||||
invoice.invoice_customer.tax_scheme.name)
|
invoice.invoice_customer.tax_scheme.name)
|
||||||
|
|
||||||
def set_customer(fexml, invoice):
|
def set_customer(fexml, invoice):
|
||||||
@@ -193,7 +218,8 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
# DIAN 1.1.-2021: DSAK20
|
# DIAN 1.1.-2021: DSAK20
|
||||||
# DIAN 1.1.-2021: NSAK20
|
# DIAN 1.1.-2021: NSAK20
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:RegistrationName',
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':RegistrationName',
|
||||||
invoice.invoice_customer.legal_name)
|
invoice.invoice_customer.legal_name)
|
||||||
|
|
||||||
customer_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy()
|
customer_company_id_attrs = fe.SCHEME_AGENCY_ATTRS.copy()
|
||||||
@@ -205,7 +231,8 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
# DIAN 1.1.-2021: DSAK21
|
# DIAN 1.1.-2021: DSAK21
|
||||||
# DIAN 1.1.-2021: NSAK21
|
# DIAN 1.1.-2021: NSAK21
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID',
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':CompanyID',
|
||||||
invoice.invoice_customer.ident,
|
invoice.invoice_customer.ident,
|
||||||
# DIAN 1.1.-2021: DSAK22 DSAK23 DSAK24 DSAK25
|
# DIAN 1.1.-2021: DSAK22 DSAK23 DSAK24 DSAK25
|
||||||
# DIAN 1.1.-2021: NSAK22 NSAK23 NSAK24 NSAK25
|
# DIAN 1.1.-2021: NSAK22 NSAK23 NSAK24 NSAK25
|
||||||
@@ -214,24 +241,28 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
# DIAN 1.1.-2021: DSAK26
|
# DIAN 1.1.-2021: DSAK26
|
||||||
# DIAN 1.1.-2021: NSAK26
|
# DIAN 1.1.-2021: NSAK26
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:TaxLevelCode',
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc'
|
||||||
|
':TaxLevelCode',
|
||||||
invoice.invoice_customer.responsability_code)
|
invoice.invoice_customer.responsability_code)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAK39
|
# DIAN 1.1.-2021: DSAK39
|
||||||
# DIAN 1.1.-2021: NSAK39
|
# DIAN 1.1.-2021: NSAK39
|
||||||
fexml.placeholder_for(
|
fexml.placeholder_for(
|
||||||
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme')
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme')
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAK40
|
# DIAN 1.1.-2021: DSAK40
|
||||||
# DIAN 1.1.-2021: NSAK40
|
# DIAN 1.1.-2021: NSAK40
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme/cbc:ID',
|
||||||
invoice.invoice_customer.tax_scheme.code)
|
invoice.invoice_customer.tax_scheme.code)
|
||||||
|
|
||||||
# DIAN 1.1.-2021: DSAK41
|
# DIAN 1.1.-2021: DSAK41
|
||||||
# DIAN 1.1.-2021: NSAK41
|
# DIAN 1.1.-2021: NSAK41
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:Name',
|
'./cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac'
|
||||||
|
':TaxScheme/cbc:Name',
|
||||||
invoice.invoice_customer.tax_scheme.name)
|
invoice.invoice_customer.tax_scheme.name)
|
||||||
|
|
||||||
def set_payment_mean(fexml, invoice):
|
def set_payment_mean(fexml, invoice):
|
||||||
@@ -328,7 +359,8 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
reference.uuid,
|
reference.uuid,
|
||||||
schemeName=schemeName)
|
schemeName=schemeName)
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
'./cac:BillingReference/cac:InvoiceDocumentReference/cbc:IssueDate',
|
'./cac:BillingReference/cac:InvoiceDocumentReference/'
|
||||||
|
'cbc:IssueDate',
|
||||||
reference.date.strftime("%Y-%m-%d"))
|
reference.date.strftime("%Y-%m-%d"))
|
||||||
|
|
||||||
def set_billing_reference(fexml, invoice):
|
def set_billing_reference(fexml, invoice):
|
||||||
@@ -419,14 +451,17 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
|
|
||||||
if percent_for[cod_impuesto]:
|
if percent_for[cod_impuesto]:
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent',
|
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/'
|
||||||
|
'cbc:Percent',
|
||||||
percent_for[cod_impuesto])
|
percent_for[cod_impuesto])
|
||||||
|
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
|
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme'
|
||||||
|
'/cbc:ID',
|
||||||
cod_impuesto)
|
cod_impuesto)
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name', 'IVA')
|
'/cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme'
|
||||||
|
'/cbc:Name', 'IVA')
|
||||||
|
|
||||||
# abstract method
|
# abstract method
|
||||||
|
|
||||||
@@ -455,7 +490,8 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
|
|
||||||
if subtotal.percent is not None:
|
if subtotal.percent is not None:
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent',
|
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac'
|
||||||
|
':TaxCategory/cbc:Percent',
|
||||||
'%0.2f' %
|
'%0.2f' %
|
||||||
round(
|
round(
|
||||||
subtotal.percent,
|
subtotal.percent,
|
||||||
@@ -464,10 +500,12 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
if subtotal.scheme is not None:
|
if subtotal.scheme is not None:
|
||||||
# DIAN 1.7.-2020: FAX15
|
# DIAN 1.7.-2020: FAX15
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
|
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac'
|
||||||
|
':TaxCategory/cac:TaxScheme/cbc:ID',
|
||||||
subtotal.scheme.code)
|
subtotal.scheme.code)
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name',
|
'./cac:WithholdingTaxTotal/cac:TaxSubtotal/cac'
|
||||||
|
':TaxCategory/cac:TaxScheme/cbc:Name',
|
||||||
subtotal.scheme.name)
|
subtotal.scheme.name)
|
||||||
|
|
||||||
def set_invoice_line_tax(fexml, line, invoice_line):
|
def set_invoice_line_tax(fexml, line, invoice_line):
|
||||||
@@ -488,7 +526,8 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
|
|
||||||
if subtotal.percent is not None:
|
if subtotal.percent is not None:
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent',
|
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc'
|
||||||
|
':Percent',
|
||||||
'%0.2f' %
|
'%0.2f' %
|
||||||
round(
|
round(
|
||||||
subtotal.percent,
|
subtotal.percent,
|
||||||
@@ -497,10 +536,12 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
if subtotal.scheme is not None:
|
if subtotal.scheme is not None:
|
||||||
# DIAN 1.7.-2020: FAX15
|
# DIAN 1.7.-2020: FAX15
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
|
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac'
|
||||||
|
':TaxScheme/cbc:ID',
|
||||||
subtotal.scheme.code)
|
subtotal.scheme.code)
|
||||||
line.set_element(
|
line.set_element(
|
||||||
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:Name',
|
'./cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac'
|
||||||
|
':TaxScheme/cbc:Name',
|
||||||
subtotal.scheme.name)
|
subtotal.scheme.name)
|
||||||
|
|
||||||
def set_invoice_lines(fexml, invoice):
|
def set_invoice_lines(fexml, invoice):
|
||||||
@@ -615,7 +656,9 @@ class DIANSupportDocumentXML(fe.FeXML):
|
|||||||
(fexml.tag_document()),
|
(fexml.tag_document()),
|
||||||
invoice.invoice_type_code,
|
invoice.invoice_type_code,
|
||||||
listAgencyID='195',
|
listAgencyID='195',
|
||||||
listAgencyName='No matching global declaration available for the validation root',
|
listAgencyName=(
|
||||||
|
'No matching global declaration available for the '
|
||||||
|
'validation root'),
|
||||||
listURI='http://www.dian.gov.co')
|
listURI='http://www.dian.gov.co')
|
||||||
fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines))
|
fexml.set_element('./cbc:LineCountNumeric', len(invoice.invoice_lines))
|
||||||
fexml.set_element(
|
fexml.set_element(
|
||||||
|
|||||||
@@ -11,18 +11,88 @@ import hashlib
|
|||||||
|
|
||||||
|
|
||||||
from .. import fe
|
from .. import fe
|
||||||
from .. import form
|
|
||||||
from ..data.dian import codelist
|
from ..data.dian import codelist
|
||||||
|
|
||||||
from .devengado import *
|
|
||||||
from .deduccion import *
|
|
||||||
from .trabajador import *
|
|
||||||
from .empleador import *
|
|
||||||
from .pago import *
|
|
||||||
from .lugar import Lugar
|
|
||||||
|
|
||||||
from .amount import Amount
|
from .amount import Amount
|
||||||
from .exception import *
|
from .deduccion import (
|
||||||
|
Deduccion,
|
||||||
|
DeduccionFondoPension,
|
||||||
|
DeduccionSalud,
|
||||||
|
)
|
||||||
|
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 .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',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class Fecha:
|
class Fecha:
|
||||||
def __init__(self, fecha):
|
def __init__(self, fecha):
|
||||||
@@ -46,6 +116,7 @@ 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)
|
||||||
@@ -84,6 +155,7 @@ class NumeroSecuencia:
|
|||||||
# NIE012
|
# NIE012
|
||||||
Numero=numero)
|
Numero=numero)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Periodo:
|
class Periodo:
|
||||||
fecha_ingreso: str | Fecha
|
fecha_ingreso: str | Fecha
|
||||||
@@ -96,7 +168,8 @@ class Periodo:
|
|||||||
|
|
||||||
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)
|
self.fecha_liquidacion_inicio = Fecha.cast(
|
||||||
|
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)
|
||||||
|
|
||||||
@@ -107,7 +180,8 @@ class Periodo:
|
|||||||
# NIE003
|
# NIE003
|
||||||
FechaRetiro=self.fecha_retiro,
|
FechaRetiro=self.fecha_retiro,
|
||||||
# NIE004
|
# NIE004
|
||||||
FechaLiquidacionInicio=self.fecha_liquidacion_inicio,
|
FechaLiquidacionInicio=(
|
||||||
|
self.fecha_liquidacion_inicio),
|
||||||
# NIE005
|
# NIE005
|
||||||
FechaLiquidacionFin=self.fecha_liquidacion_fin,
|
FechaLiquidacionFin=self.fecha_liquidacion_fin,
|
||||||
# NIE006
|
# NIE006
|
||||||
@@ -115,6 +189,7 @@ class Periodo:
|
|||||||
# NIE008
|
# NIE008
|
||||||
FechaGen=self.fecha_generacion)
|
FechaGen=self.fecha_generacion)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Proveedor:
|
class Proveedor:
|
||||||
razon_social: str
|
razon_social: str
|
||||||
@@ -141,11 +216,16 @@ class Proveedor:
|
|||||||
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')
|
ambiente = fexml.get_element_attribute(
|
||||||
codigo_qr = f"https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey={cune}"
|
scopexml.xpath_from_root('/InformacionGeneral'), 'Ambiente')
|
||||||
|
codigo_qr = (
|
||||||
|
f"https://catalogo-vpfe.dian.gov.co/document/"
|
||||||
|
f"searchqr?documentkey={cune}")
|
||||||
|
|
||||||
if InformacionGeneral.AMBIENTE_PRUEBAS == ambiente:
|
if InformacionGeneral.AMBIENTE_PRUEBAS == ambiente:
|
||||||
codigo_qr = f"https://catalogo-vpfe-hab.dian.gov.co/document/searchqr?documentkey={cune}"
|
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')
|
||||||
|
|
||||||
@@ -153,13 +233,15 @@ class Proveedor:
|
|||||||
|
|
||||||
# NIE020
|
# NIE020
|
||||||
software_code = self._software_security_code(fexml, scopexml)
|
software_code = self._software_security_code(fexml, scopexml)
|
||||||
fexml.set_attributes(scopexml.xpath_from_root('/ProveedorXML'), SoftwareSC=software_code)
|
fexml.set_attributes(
|
||||||
|
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(scopexml.xpath_from_root('/NumeroSecuenciaXML'), 'Numero')
|
numero = fexml.get_element_attribute(
|
||||||
|
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')
|
||||||
|
|
||||||
@@ -173,6 +255,7 @@ class Proveedor:
|
|||||||
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
|
||||||
@@ -181,18 +264,33 @@ class Metadata:
|
|||||||
lugar_generacion: Lugar
|
lugar_generacion: Lugar
|
||||||
proveedor: Proveedor
|
proveedor: Proveedor
|
||||||
|
|
||||||
def apply(self, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml):
|
def apply(
|
||||||
|
self,
|
||||||
|
novedad,
|
||||||
|
numero_secuencia_xml,
|
||||||
|
lugar_generacion_xml,
|
||||||
|
proveedor_xml):
|
||||||
if novedad:
|
if novedad:
|
||||||
self.novedad.apply(novedad)
|
self.novedad.apply(novedad)
|
||||||
self.secuencia.apply(numero_secuencia_xml)
|
self.secuencia.apply(numero_secuencia_xml)
|
||||||
self.lugar_generacion.apply(lugar_generacion_xml, './LugarGeneracionXML')
|
self.lugar_generacion.apply(
|
||||||
|
lugar_generacion_xml,
|
||||||
|
'./LugarGeneracionXML')
|
||||||
self.proveedor.apply(proveedor_xml)
|
self.proveedor.apply(proveedor_xml)
|
||||||
|
|
||||||
def post_apply(self, fexml, scopexml, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml):
|
def post_apply(
|
||||||
|
self,
|
||||||
|
fexml,
|
||||||
|
scopexml,
|
||||||
|
novedad,
|
||||||
|
numero_secuencia_xml,
|
||||||
|
lugar_generacion_xml,
|
||||||
|
proveedor_xml):
|
||||||
self.proveedor.post_apply(fexml, scopexml, proveedor_xml)
|
self.proveedor.post_apply(fexml, scopexml, proveedor_xml)
|
||||||
if novedad:
|
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
|
||||||
@@ -203,6 +301,7 @@ 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
|
||||||
@@ -213,6 +312,7 @@ 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
|
||||||
@@ -328,17 +428,28 @@ class InformacionGeneral:
|
|||||||
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__(pkcs12_path, passphrase=passphrase, localpolicy=localpolicy)
|
super().__init__(
|
||||||
|
pkcs12_path,
|
||||||
|
passphrase=passphrase,
|
||||||
|
localpolicy=localpolicy)
|
||||||
|
|
||||||
def _element_extension_content(self, fachoxml):
|
def _element_extension_content(self, fachoxml):
|
||||||
return fachoxml.builder.xpath(fachoxml.root, './ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
return fachoxml.builder.xpath(
|
||||||
|
fachoxml.root,
|
||||||
|
'./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
||||||
|
|
||||||
|
|
||||||
class DIANNominaXML:
|
class DIANNominaXML:
|
||||||
def __init__(self, tag_document, xpath_ajuste=None, schemaLocation=None, namespace_ajuste=None):
|
def __init__(
|
||||||
|
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
|
||||||
@@ -346,21 +457,26 @@ class DIANNominaXML:
|
|||||||
if namespace_ajuste:
|
if namespace_ajuste:
|
||||||
self.fexml = fe.FeXML(tag_document, namespace_ajuste)
|
self.fexml = fe.FeXML(tag_document, namespace_ajuste)
|
||||||
else:
|
else:
|
||||||
self.fexml = fe.FeXML(tag_document, 'dian:gov:co:facturaelectronica:NominaIndividual')
|
self.fexml = fe.FeXML(
|
||||||
|
tag_document,
|
||||||
|
'dian:gov:co:facturaelectronica:NominaIndividual')
|
||||||
|
|
||||||
self.fexml.root.set("SchemaLocation", "")
|
self.fexml.root.set("SchemaLocation", "")
|
||||||
self.fexml.root.set("schemaLocation", 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('./ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent')
|
self.fexml.placeholder_for(
|
||||||
|
'./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('./ReemplazandoPredecesor', optional=True)
|
self.root_fragment.placeholder_for(
|
||||||
self.root_fragment.placeholder_for('./EliminandoPredecesor', optional=True)
|
'./ReemplazandoPredecesor', optional=True)
|
||||||
|
self.root_fragment.placeholder_for(
|
||||||
|
'./EliminandoPredecesor', optional=True)
|
||||||
if not namespace_ajuste:
|
if not namespace_ajuste:
|
||||||
self.root_fragment.placeholder_for('./Novedad', optional=False)
|
self.root_fragment.placeholder_for('./Novedad', optional=False)
|
||||||
self.root_fragment.placeholder_for('./Periodo')
|
self.root_fragment.placeholder_for('./Periodo')
|
||||||
@@ -374,16 +490,20 @@ 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('./Devengados/Transporte', optional=True)
|
self.root_fragment.placeholder_for(
|
||||||
|
'./Devengados/Transporte', optional=True)
|
||||||
if not namespace_ajuste:
|
if not namespace_ajuste:
|
||||||
self.novedad = self.root_fragment.fragment('./Novedad')
|
self.novedad = self.root_fragment.fragment('./Novedad')
|
||||||
else:
|
else:
|
||||||
self.novedad = None
|
self.novedad = None
|
||||||
self.informacion_general_xml = self.root_fragment.fragment('./InformacionGeneral')
|
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('./NumeroSecuenciaXML')
|
self.numero_secuencia_xml = self.root_fragment.fragment(
|
||||||
self.lugar_generacion_xml = self.root_fragment.fragment('./LugarGeneracionXML')
|
'./NumeroSecuenciaXML')
|
||||||
|
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')
|
||||||
@@ -399,13 +519,19 @@ class DIANNominaXML:
|
|||||||
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_xml, self.informacion_general_version)
|
self.informacion_general.apply(
|
||||||
|
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):
|
||||||
@@ -498,10 +624,13 @@ 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_xpath, 'CUNE'),
|
'cune': self.fexml.get_element_attribute(
|
||||||
'fecha_generacion': self.fexml.get_element_attribute(xpath, 'FechaGen'),
|
xpath, 'CUNE'),
|
||||||
'numero': self.fexml.get_element_attribute(self.root_fragment('/NumeroSecuenciaXML', 'Numero'))
|
'fecha_generacion': self.fexml.get_element_attribute(
|
||||||
}
|
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()
|
||||||
@@ -512,26 +641,38 @@ class DIANNominaXML:
|
|||||||
# 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.fexml, self.root_fragment, self.informacion_general_xml)
|
self.informacion_general.post_apply(
|
||||||
|
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.fexml, self.root_fragment, self.novedad, self.numero_secuencia_xml, self.lugar_generacion_xml, self.proveedor_xml)
|
self.metadata.post_apply(
|
||||||
|
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('./DevengadosTotal', '0.0')
|
devengados_total = self.root_fragment.get_element_text_or_attribute(
|
||||||
deducciones_total = self.root_fragment.get_element_text_or_attribute('./DeduccionesTotal', '0.0')
|
'./DevengadosTotal', '0.0')
|
||||||
|
deducciones_total = self.root_fragment.get_element_text_or_attribute(
|
||||||
|
'./DeduccionesTotal', '0.0')
|
||||||
|
|
||||||
comprobante_total = Amount(devengados_total) - Amount(deducciones_total)
|
comprobante_total = Amount(devengados_total) - \
|
||||||
|
Amount(deducciones_total)
|
||||||
|
|
||||||
self.root_fragment.set_element('./ComprobanteTotal', str(round(comprobante_total, 2)))
|
self.root_fragment.set_element(
|
||||||
|
'./ComprobanteTotal', str(round(comprobante_total, 2)))
|
||||||
|
|
||||||
def _deducciones_total(self):
|
def _deducciones_total(self):
|
||||||
xpaths = [
|
xpaths = [
|
||||||
self.root_fragment.xpath_from_root('/Deducciones/Salud/@Deduccion'),
|
self.root_fragment.xpath_from_root(
|
||||||
self.root_fragment.xpath_from_root('/Deducciones/FondoPension/@Deduccion')
|
'/Deducciones/Salud/@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))
|
||||||
|
|
||||||
@@ -540,15 +681,19 @@ class DIANNominaXML:
|
|||||||
for deduccion in deducciones:
|
for deduccion in deducciones:
|
||||||
deducciones_total += deduccion
|
deducciones_total += deduccion
|
||||||
|
|
||||||
self.root_fragment.set_element('./DeduccionesTotal', str(round(deducciones_total, 2)))
|
self.root_fragment.set_element(
|
||||||
|
'./DeduccionesTotal', str(round(deducciones_total, 2)))
|
||||||
|
|
||||||
def _devengados_total(self):
|
def _devengados_total(self):
|
||||||
xpaths = [
|
xpaths = [
|
||||||
self.root_fragment.xpath_from_root('/Devengados/Basico/@SueldoTrabajado'),
|
self.root_fragment.xpath_from_root(
|
||||||
self.root_fragment.xpath_from_root('/Devengados/Transporte/@AuxilioTransporte'),
|
'/Devengados/Basico/@SueldoTrabajado'),
|
||||||
self.root_fragment.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojS'),
|
self.root_fragment.xpath_from_root(
|
||||||
self.root_fragment.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojNS')
|
'/Devengados/Transporte/@AuxilioTransporte'),
|
||||||
]
|
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))
|
||||||
|
|
||||||
@@ -558,10 +703,13 @@ class DIANNominaXML:
|
|||||||
# TODO(bit4bit) nque valor va redondeado?
|
# TODO(bit4bit) nque valor va redondeado?
|
||||||
# NIE186
|
# NIE186
|
||||||
self.root_fragment.set_element('./Redondeo', str(round(0, 2)))
|
self.root_fragment.set_element('./Redondeo', str(round(0, 2)))
|
||||||
self.root_fragment.set_element('./DevengadosTotal', str(round(devengados_total,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(lambda val: self.fexml.get_element_text_or_attribute(val, multiple=True), xpaths)
|
xpaths_values_of_values = map(
|
||||||
|
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:
|
||||||
@@ -573,15 +721,22 @@ 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"
|
schema = (
|
||||||
|
"dian:gov:co:facturaelectronica:NominaIndividual"
|
||||||
|
" NominaIndividualElectronicaXSD.xsd"
|
||||||
|
)
|
||||||
|
|
||||||
super().__init__('NominaIndividual', schemaLocation=schema)
|
super().__init__('NominaIndividual', schemaLocation=schema)
|
||||||
self.informacion_general_version = 'V1.0: Documento Soporte de Pago de Nómina Electrónica'
|
self.informacion_general_version = (
|
||||||
|
'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):
|
||||||
@@ -594,7 +749,8 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
|||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
# NIAE214
|
# NIAE214
|
||||||
fragment.set_element('./TipoNota', '1')
|
fragment.set_element('./TipoNota', '1')
|
||||||
fragment.set_element('./Reemplazar/ReemplazandoPredecesor', None,
|
fragment.set_element(
|
||||||
|
'./Reemplazar/ReemplazandoPredecesor', None,
|
||||||
# NIAE090
|
# NIAE090
|
||||||
NumeroPred=self.numero,
|
NumeroPred=self.numero,
|
||||||
# NIAE191
|
# NIAE191
|
||||||
@@ -604,18 +760,28 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
schema = (
|
||||||
|
"dian:gov:co:facturaelectronica:NominaIndividualDeAjuste"
|
||||||
|
" NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||||
|
)
|
||||||
|
|
||||||
super().__init__('NominaIndividualDeAjuste', './Reemplazar', schemaLocation=schema, namespace_ajuste='dian:gov:co:facturaelectronica:NominaIndividualDeAjuste')
|
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'
|
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
|
||||||
@@ -636,10 +802,21 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
schema = (
|
||||||
super().__init__('NominaIndividualDeAjuste', './Eliminar', schemaLocation=schema, namespace_ajuste='dian:gov:co:facturaelectronica:NominaIndividualDeAjuste')
|
"dian:gov:co:facturaelectronica:NominaIndividualDeAjuste"
|
||||||
|
" NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||||
|
)
|
||||||
|
super().__init__(
|
||||||
|
'NominaIndividualDeAjuste',
|
||||||
|
'./Eliminar',
|
||||||
|
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"
|
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):
|
||||||
@@ -648,4 +825,3 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__('NominaIndividualDeAjuste')
|
super().__init__('NominaIndividualDeAjuste')
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
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 *
|
from .deduccion import Deduccion
|
||||||
from .salud import *
|
from .salud import DeduccionSalud
|
||||||
from .fondo_pension import *
|
from .fondo_pension import DeduccionFondoPension
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Deduccion',
|
'Deduccion',
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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
|
||||||
@@ -16,4 +17,3 @@ class DeduccionSalud(Deduccion):
|
|||||||
# NIE163
|
# NIE163
|
||||||
Deduccion=self.deduccion
|
Deduccion=self.deduccion
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from .. import form
|
from .. import form
|
||||||
|
|
||||||
|
|
||||||
class Departamento(form.CountrySubentity):
|
class Departamento(form.CountrySubentity):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
|
|
||||||
from .basico import *
|
from .basico import DevengadoBasico
|
||||||
from .transporte import *
|
from .transporte import DevengadoTransporte
|
||||||
from .devengado import *
|
from .devengado import Devengado
|
||||||
from .horas_extras import *
|
from .horas_extras import (
|
||||||
|
DevengadoHoraExtra,
|
||||||
|
DevengadoHorasExtrasDiarias,
|
||||||
|
DevengadoHorasExtrasNocturnas,
|
||||||
|
DevengadoHorasRecargoNocturno,
|
||||||
|
DevengadoHorasExtrasDiariasDominicalesYFestivos,
|
||||||
|
DevengadoHorasRecargoDiariasDominicalesYFestivos,
|
||||||
|
DevengadoHorasExtrasNocturnasDominicalesYFestivos,
|
||||||
|
DevengadoHorasRecargoNocturnoDominicalesYFestivos,
|
||||||
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Devengado',
|
'Devengado',
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class DevengadoHorasExtrasDiarias(Devengado):
|
|||||||
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]
|
||||||
@@ -56,6 +57,7 @@ class DevengadoHorasRecargoNocturno(Devengado):
|
|||||||
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]
|
||||||
@@ -65,6 +67,7 @@ class DevengadoHorasExtrasDiariasDominicalesYFestivos(Devengado):
|
|||||||
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]
|
||||||
@@ -74,6 +77,7 @@ class DevengadoHorasRecargoDiariasDominicalesYFestivos(Devengado):
|
|||||||
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]
|
||||||
@@ -83,6 +87,7 @@ class DevengadoHorasExtrasNocturnasDominicalesYFestivos(Devengado):
|
|||||||
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]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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
|
||||||
@@ -17,5 +18,6 @@ class DevengadoTransporte(Devengado):
|
|||||||
# NIE072
|
# NIE072
|
||||||
ViaticoManuAlojS=self.viatico_manutencion,
|
ViaticoManuAlojS=self.viatico_manutencion,
|
||||||
# NIE073
|
# NIE073
|
||||||
ViaticoManuAlojNS = self.viatico_manutencion_no_salarial
|
ViaticoManuAlojNS=(
|
||||||
|
self.viatico_manutencion_no_salarial)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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
|
||||||
@@ -31,5 +32,3 @@ class Empleador:
|
|||||||
|
|
||||||
RazonSocial=self.razon_social
|
RazonSocial=self.razon_social
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import datetime
|
|||||||
|
|
||||||
from facho import fe
|
from facho import fe
|
||||||
|
|
||||||
|
|
||||||
class Habilitacion:
|
class Habilitacion:
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -16,18 +17,18 @@ class Habilitacion:
|
|||||||
self.metadata = metadata
|
self.metadata = metadata
|
||||||
|
|
||||||
def generar(self, zipname, fecha):
|
def generar(self, zipname, fecha):
|
||||||
nominas = []
|
fe.DianZIP(open(zipname, 'w'))
|
||||||
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)
|
||||||
nomina = self._crear_nomina_individual()
|
self._crear_nomina_individual()
|
||||||
|
|
||||||
# pag 96
|
# pag 96
|
||||||
nombre = "nie%010d%s%08x.xml" % (int(self.nit), fecha.strftime('%s'), consecutivo)
|
"nie%010d%s%08x.xml" % (
|
||||||
|
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
|
||||||
@@ -36,10 +37,15 @@ 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')
|
||||||
informacion_general = nomina.informacion_general()
|
nomina.informacion_general()
|
||||||
|
|
||||||
|
def _poblar_nomina(
|
||||||
def _poblar_nomina(self, nomina, metadata, fecha, prefijo='N', consecutivo='0001'):
|
self,
|
||||||
|
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(
|
||||||
@@ -152,4 +158,3 @@ class Habilitacion:
|
|||||||
|
|
||||||
nomina = fe.nomina.DIANNominaIndividual()
|
nomina = fe.nomina.DIANNominaIndividual()
|
||||||
self._poblar_nomina(nomina, metadata, fecha)
|
self._poblar_nomina(nomina, metadata, fecha)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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,6 +3,7 @@ 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
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ 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,6 +2,7 @@ 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
|
||||||
@@ -11,4 +12,3 @@ 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,4 +1,5 @@
|
|||||||
from .. import form
|
from .. import form
|
||||||
|
|
||||||
|
|
||||||
class Pais(form.Country):
|
class Pais(form.Country):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ from dataclasses import dataclass, field
|
|||||||
|
|
||||||
from ..amount import Amount
|
from ..amount import Amount
|
||||||
|
|
||||||
from .tipo_contrato import *
|
from .tipo_contrato import TipoContrato
|
||||||
from .tipo_documento import *
|
from .tipo_documento import TipoDocumento
|
||||||
from .lugar_trabajo import *
|
from .lugar_trabajo import LugarTrabajo
|
||||||
from .tipo_trabajador import *
|
from .tipo_trabajador import TipoTrabajador
|
||||||
from .sub_tipo_trabajador import *
|
from .sub_tipo_trabajador import SubTipoTrabajador
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -29,10 +28,13 @@ class Trabajador:
|
|||||||
|
|
||||||
codigo_trabajador: str = None
|
codigo_trabajador: str = None
|
||||||
otros_nombres: str = None
|
otros_nombres: str = None
|
||||||
sub_tipo: SubTipoTrabajador = field(default_factory=lambda: SubTipoTrabajador(code='00'))
|
sub_tipo: SubTipoTrabajador = field(
|
||||||
|
default_factory=lambda: SubTipoTrabajador(code="00")
|
||||||
|
)
|
||||||
|
|
||||||
def apply(self, fragment):
|
def apply(self, fragment):
|
||||||
fragment.set_attributes('./Trabajador',
|
fragment.set_attributes(
|
||||||
|
"./Trabajador",
|
||||||
# NIE041
|
# NIE041
|
||||||
TipoTrabajador=self.tipo.code,
|
TipoTrabajador=self.tipo.code,
|
||||||
# NIE042
|
# NIE042
|
||||||
@@ -53,13 +55,12 @@ class Trabajador:
|
|||||||
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 = self.lugar_trabajo.departamento.code,
|
LugarTrabajoDepartamentoEstado=(
|
||||||
|
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
|
||||||
@@ -69,5 +70,5 @@ class Trabajador:
|
|||||||
# NIE062
|
# NIE062
|
||||||
Sueldo=str(self.sueldo),
|
Sueldo=str(self.sueldo),
|
||||||
# NIE063
|
# NIE063
|
||||||
CodigoTrabajador = self.codigo_trabajador
|
CodigoTrabajador=self.codigo_trabajador,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
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,12 +2,13 @@ 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,14 +2,13 @@ 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,12 +2,13 @@ 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,12 +2,13 @@ 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"]
|
||||||
|
|||||||
Reference in New Issue
Block a user