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:
@@ -11,18 +11,88 @@ import hashlib
|
||||
|
||||
|
||||
from .. import fe
|
||||
from .. import form
|
||||
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 .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:
|
||||
def __init__(self, fecha):
|
||||
@@ -46,6 +116,7 @@ class Fecha:
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
class FechaPago(Fecha):
|
||||
def apply(self, fragment):
|
||||
fragment.set_element('./FechaPago', self.value)
|
||||
@@ -82,7 +153,8 @@ class NumeroSecuencia:
|
||||
# NIE011
|
||||
Consecutivo=self.consecutivo,
|
||||
# NIE012
|
||||
Numero = numero)
|
||||
Numero=numero)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Periodo:
|
||||
@@ -96,25 +168,28 @@ class Periodo:
|
||||
|
||||
def __post_init__(self):
|
||||
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_retiro = Fecha.cast(self.fecha_retiro, optional=True)
|
||||
|
||||
|
||||
def apply(self, fragment):
|
||||
fragment.set_attributes('./Periodo',
|
||||
#NIE002
|
||||
# NIE002
|
||||
FechaIngreso=self.fecha_ingreso,
|
||||
#NIE003
|
||||
# NIE003
|
||||
FechaRetiro=self.fecha_retiro,
|
||||
#NIE004
|
||||
FechaLiquidacionInicio=self.fecha_liquidacion_inicio,
|
||||
#NIE005
|
||||
# NIE004
|
||||
FechaLiquidacionInicio=(
|
||||
self.fecha_liquidacion_inicio),
|
||||
# NIE005
|
||||
FechaLiquidacionFin=self.fecha_liquidacion_fin,
|
||||
#NIE006
|
||||
# NIE006
|
||||
TiempoLaborado=self.tiempo_laborado,
|
||||
#NIE008
|
||||
# NIE008
|
||||
FechaGen=self.fecha_generacion)
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class Proveedor:
|
||||
razon_social: str
|
||||
@@ -140,29 +215,36 @@ class Proveedor:
|
||||
def post_apply(self, fexml, scopexml, fragment):
|
||||
cune_xpath = scopexml.xpath_from_root('/InformacionGeneral')
|
||||
cune = fexml.get_element_attribute(cune_xpath, 'CUNE')
|
||||
|
||||
ambiente = fexml.get_element_attribute(scopexml.xpath_from_root('/InformacionGeneral'), 'Ambiente')
|
||||
codigo_qr = f"https://catalogo-vpfe.dian.gov.co/document/searchqr?documentkey={cune}"
|
||||
|
||||
ambiente = fexml.get_element_attribute(
|
||||
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:
|
||||
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:
|
||||
raise RuntimeError('fail to get InformacionGeneral/@Ambiente')
|
||||
|
||||
|
||||
scopexml.set_element('./CodigoQR', codigo_qr)
|
||||
|
||||
# NIE020
|
||||
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):
|
||||
|
||||
|
||||
# 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:
|
||||
raise RuntimeError('fallo obtener NumeroSequenciaXML/@Numero')
|
||||
|
||||
|
||||
id_software = self.software_id
|
||||
software_pin = self.software_pin
|
||||
|
||||
@@ -172,7 +254,8 @@ class Proveedor:
|
||||
h = hashlib.sha384()
|
||||
h.update(code.encode('utf-8'))
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class Metadata:
|
||||
novedad: Novedad
|
||||
@@ -181,18 +264,33 @@ class Metadata:
|
||||
lugar_generacion: Lugar
|
||||
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:
|
||||
self.novedad.apply(novedad)
|
||||
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)
|
||||
|
||||
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)
|
||||
if novedad:
|
||||
self.novedad.post_apply(fexml, scopexml, proveedor_xml)
|
||||
|
||||
self.novedad.post_apply(fexml, scopexml, proveedor_xml)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PeriodoNomina:
|
||||
code: str
|
||||
@@ -203,6 +301,7 @@ class PeriodoNomina:
|
||||
raise ValueError("code [%s] not found" % (self.code))
|
||||
self.name = codelist.PeriodoNomina[self.code]['name']
|
||||
|
||||
|
||||
@dataclass
|
||||
class TipoMoneda:
|
||||
code: str
|
||||
@@ -213,6 +312,7 @@ class TipoMoneda:
|
||||
raise ValueError("code [%s] not found" % (self.code))
|
||||
self.name = codelist.TipoMoneda[self.code]['name']
|
||||
|
||||
|
||||
@dataclass
|
||||
class InformacionGeneral:
|
||||
@dataclass
|
||||
@@ -235,7 +335,7 @@ class InformacionGeneral:
|
||||
valor: str = '2'
|
||||
|
||||
def __str__(self):
|
||||
self.valor
|
||||
self.valor
|
||||
|
||||
# TABLA 5.5.7
|
||||
@dataclass
|
||||
@@ -250,7 +350,7 @@ class InformacionGeneral:
|
||||
valor: str = '102'
|
||||
|
||||
def __str__(self):
|
||||
self.valor
|
||||
self.valor
|
||||
|
||||
@dataclass
|
||||
class TIPO_XML_AJUSTES(TIPO_XML):
|
||||
@@ -273,26 +373,26 @@ class InformacionGeneral:
|
||||
def apply(self, fragment, version):
|
||||
fragment.set_attributes('./InformacionGeneral',
|
||||
# NIE022
|
||||
Version = version,
|
||||
Version=version,
|
||||
# NIE023
|
||||
Ambiente = self.tipo_ambiente.valor,
|
||||
Ambiente=self.tipo_ambiente.valor,
|
||||
# NIE202
|
||||
# TABLA 5.5.2
|
||||
# TODO(bit4bit) solo NominaIndividual
|
||||
TipoXML = self.tipo_xml.valor,
|
||||
TipoXML=self.tipo_xml.valor,
|
||||
# NIE024
|
||||
CUNE = None,
|
||||
CUNE=None,
|
||||
# NIE025
|
||||
EncripCUNE = 'CUNE-SHA384',
|
||||
EncripCUNE='CUNE-SHA384',
|
||||
# NIE026
|
||||
FechaGen = self.fecha_generacion,
|
||||
FechaGen=self.fecha_generacion,
|
||||
# NIE027
|
||||
HoraGen = self.hora_generacion,
|
||||
HoraGen=self.hora_generacion,
|
||||
# NIE029
|
||||
PeriodoNomina = self.periodo_nomina.code,
|
||||
PeriodoNomina=self.periodo_nomina.code,
|
||||
# NIE030
|
||||
TipoMoneda = self.tipo_moneda.code,
|
||||
TRM = 0
|
||||
TipoMoneda=self.tipo_moneda.code,
|
||||
TRM=0
|
||||
# TODO(bit4bit) resto...
|
||||
# .....
|
||||
)
|
||||
@@ -321,24 +421,35 @@ class InformacionGeneral:
|
||||
h = hashlib.sha384()
|
||||
h.update(cune.encode('utf-8'))
|
||||
cune_hash = h.hexdigest()
|
||||
|
||||
|
||||
fragment.set_attributes(
|
||||
'./InformacionGeneral',
|
||||
# NIE024
|
||||
CUNE = cune_hash
|
||||
CUNE=cune_hash
|
||||
)
|
||||
|
||||
|
||||
class DianXMLExtensionSigner(fe.DianXMLExtensionSigner):
|
||||
|
||||
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):
|
||||
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:
|
||||
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.tag_document = tag_document
|
||||
@@ -346,21 +457,26 @@ class DIANNominaXML:
|
||||
if namespace_ajuste:
|
||||
self.fexml = fe.FeXML(tag_document, namespace_ajuste)
|
||||
else:
|
||||
self.fexml = fe.FeXML(tag_document, 'dian:gov:co:facturaelectronica:NominaIndividual')
|
||||
self.fexml = fe.FeXML(
|
||||
tag_document,
|
||||
'dian:gov:co:facturaelectronica:NominaIndividual')
|
||||
|
||||
self.fexml.root.set("SchemaLocation", "")
|
||||
self.fexml.root.set("schemaLocation", schemaLocation)
|
||||
|
||||
# layout, la dian requiere que los elementos
|
||||
# esten ordenados segun el anexo tecnico
|
||||
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.root_fragment = self.fexml
|
||||
if xpath_ajuste is not None:
|
||||
self.root_fragment = self.fexml.fragment(xpath_ajuste)
|
||||
self.root_fragment.placeholder_for('./ReemplazandoPredecesor', optional=True)
|
||||
self.root_fragment.placeholder_for('./EliminandoPredecesor', optional=True)
|
||||
self.root_fragment.placeholder_for(
|
||||
'./ReemplazandoPredecesor', optional=True)
|
||||
self.root_fragment.placeholder_for(
|
||||
'./EliminandoPredecesor', optional=True)
|
||||
if not namespace_ajuste:
|
||||
self.root_fragment.placeholder_for('./Novedad', optional=False)
|
||||
self.root_fragment.placeholder_for('./Periodo')
|
||||
@@ -374,16 +490,20 @@ class DIANNominaXML:
|
||||
self.root_fragment.placeholder_for('./Pago')
|
||||
self.root_fragment.placeholder_for('./FechasPagos')
|
||||
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:
|
||||
self.novedad = self.root_fragment.fragment('./Novedad')
|
||||
else:
|
||||
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.fecha_pagos_xml = self.root_fragment.fragment('./FechasPagos')
|
||||
self.numero_secuencia_xml = self.root_fragment.fragment('./NumeroSecuenciaXML')
|
||||
self.lugar_generacion_xml = self.root_fragment.fragment('./LugarGeneracionXML')
|
||||
self.numero_secuencia_xml = self.root_fragment.fragment(
|
||||
'./NumeroSecuenciaXML')
|
||||
self.lugar_generacion_xml = self.root_fragment.fragment(
|
||||
'./LugarGeneracionXML')
|
||||
self.proveedor_xml = self.root_fragment.fragment('./ProveedorXML')
|
||||
self.empleador = self.root_fragment.fragment('./Empleador')
|
||||
self.trabajador = self.root_fragment.fragment('./Trabajador')
|
||||
@@ -398,14 +518,20 @@ class DIANNominaXML:
|
||||
if not isinstance(metadata, Metadata):
|
||||
raise ValueError('se espera tipo Metadata')
|
||||
self.metadata = metadata
|
||||
|
||||
self.metadata.apply(self.novedad, self.numero_secuencia_xml, self.lugar_generacion_xml, self.proveedor_xml)
|
||||
|
||||
|
||||
self.metadata.apply(
|
||||
self.novedad,
|
||||
self.numero_secuencia_xml,
|
||||
self.lugar_generacion_xml,
|
||||
self.proveedor_xml)
|
||||
|
||||
def asignar_informacion_general(self, general):
|
||||
if not isinstance(general, InformacionGeneral):
|
||||
raise ValueError('se espera tipo InformacionGeneral')
|
||||
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):
|
||||
if not isinstance(periodo, Periodo):
|
||||
@@ -435,7 +561,7 @@ class DIANNominaXML:
|
||||
if not isinstance(trabajador, Trabajador):
|
||||
raise ValueError('se espera tipo Trabajador')
|
||||
trabajador.apply(self.trabajador)
|
||||
|
||||
|
||||
def adicionar_devengado(self, devengado):
|
||||
if not isinstance(devengado, Devengado):
|
||||
raise ValueError('se espera tipo Devengado')
|
||||
@@ -482,7 +608,7 @@ class DIANNominaXML:
|
||||
self.fexml.xpath_from_root('/Devengados/Basico'),
|
||||
'se requiere DevengadoBasico'
|
||||
)
|
||||
|
||||
|
||||
check_element(
|
||||
self.fexml.xpath_from_root('/Deducciones/Salud'),
|
||||
'se requiere DeduccionSalud'
|
||||
@@ -498,10 +624,13 @@ class DIANNominaXML:
|
||||
def informacion_general(self):
|
||||
xpath = self.root_fragment.xpath_from_root('/InformacionGeneral')
|
||||
return {
|
||||
'cune': self.fexml.get_element_attribute(cune_xpath, 'CUNE'),
|
||||
'fecha_generacion': self.fexml.get_element_attribute(xpath, 'FechaGen'),
|
||||
'numero': self.fexml.get_element_attribute(self.root_fragment('/NumeroSecuenciaXML', 'Numero'))
|
||||
}
|
||||
'cune': self.fexml.get_element_attribute(
|
||||
xpath, 'CUNE'),
|
||||
'fecha_generacion': self.fexml.get_element_attribute(
|
||||
xpath, 'FechaGen'),
|
||||
'numero': self.fexml.get_element_attribute(
|
||||
self.root_fragment(
|
||||
'/NumeroSecuenciaXML', 'Numero'))}
|
||||
|
||||
def toFachoXML(self):
|
||||
self._devengados_total()
|
||||
@@ -509,59 +638,78 @@ class DIANNominaXML:
|
||||
self._comprobante_total()
|
||||
|
||||
if self.informacion_general is not None:
|
||||
#TODO(bit4bit) acoplamiento temporal
|
||||
# TODO(bit4bit) acoplamiento temporal
|
||||
# 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:
|
||||
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
|
||||
|
||||
def _comprobante_total(self):
|
||||
devengados_total = self.root_fragment.get_element_text_or_attribute('./DevengadosTotal', '0.0')
|
||||
deducciones_total = self.root_fragment.get_element_text_or_attribute('./DeduccionesTotal', '0.0')
|
||||
devengados_total = self.root_fragment.get_element_text_or_attribute(
|
||||
'./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):
|
||||
xpaths = [
|
||||
self.root_fragment.xpath_from_root('/Deducciones/Salud/@Deduccion'),
|
||||
self.root_fragment.xpath_from_root('/Deducciones/FondoPension/@Deduccion')
|
||||
]
|
||||
self.root_fragment.xpath_from_root(
|
||||
'/Deducciones/Salud/@Deduccion'),
|
||||
self.root_fragment.xpath_from_root(
|
||||
'/Deducciones/FondoPension/@Deduccion')]
|
||||
deducciones = map(lambda valor: Amount(valor),
|
||||
self._values_of_xpaths(xpaths))
|
||||
|
||||
deducciones_total = Amount(0.0)
|
||||
|
||||
|
||||
for deduccion in deducciones:
|
||||
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):
|
||||
xpaths = [
|
||||
self.root_fragment.xpath_from_root('/Devengados/Basico/@SueldoTrabajado'),
|
||||
self.root_fragment.xpath_from_root('/Devengados/Transporte/@AuxilioTransporte'),
|
||||
self.root_fragment.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojS'),
|
||||
self.root_fragment.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojNS')
|
||||
]
|
||||
self.root_fragment.xpath_from_root(
|
||||
'/Devengados/Basico/@SueldoTrabajado'),
|
||||
self.root_fragment.xpath_from_root(
|
||||
'/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),
|
||||
self._values_of_xpaths(xpaths))
|
||||
|
||||
|
||||
devengados_total = Amount(0.0)
|
||||
for devengado in devengados:
|
||||
devengados_total += devengado
|
||||
# TODO(bit4bit) nque valor va redondeado?
|
||||
# NIE186
|
||||
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('./Redondeo', str(round(0, 2)))
|
||||
self.root_fragment.set_element(
|
||||
'./DevengadosTotal', str(round(devengados_total, 2)))
|
||||
|
||||
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 = []
|
||||
# toda esta carreta para hacer un aplano de lista
|
||||
for xpath_values in xpaths_values_of_values:
|
||||
@@ -573,15 +721,22 @@ class DIANNominaXML:
|
||||
|
||||
return filter(lambda val: val is not None, xpaths_values)
|
||||
|
||||
|
||||
class DIANNominaIndividual(DIANNominaXML):
|
||||
|
||||
def __init__(self):
|
||||
schema = "dian:gov:co:facturaelectronica:NominaIndividual NominaIndividualElectronicaXSD.xsd"
|
||||
schema = (
|
||||
"dian:gov:co:facturaelectronica:NominaIndividual"
|
||||
" NominaIndividualElectronicaXSD.xsd"
|
||||
)
|
||||
|
||||
super().__init__('NominaIndividual', schemaLocation=schema)
|
||||
self.informacion_general_version = 'V1.0: Documento Soporte de Pago de Nómina Electrónica'
|
||||
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
|
||||
|
||||
|
||||
class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
||||
|
||||
class Reemplazar(DIANNominaXML):
|
||||
@@ -593,31 +748,42 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
||||
|
||||
def apply(self, fragment):
|
||||
# NIAE214
|
||||
fragment.set_element('./TipoNota', '1')
|
||||
fragment.set_element('./Reemplazar/ReemplazandoPredecesor', None,
|
||||
# NIAE090
|
||||
NumeroPred = self.numero,
|
||||
# NIAE191
|
||||
CUNEPred = self.cune,
|
||||
# NIAE192
|
||||
FechaGenPred = self.fecha_generacion
|
||||
fragment.set_element('./TipoNota', '1')
|
||||
fragment.set_element(
|
||||
'./Reemplazar/ReemplazandoPredecesor', None,
|
||||
# NIAE090
|
||||
NumeroPred=self.numero,
|
||||
# NIAE191
|
||||
CUNEPred=self.cune,
|
||||
# NIAE192
|
||||
FechaGenPred=self.fecha_generacion
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||
|
||||
super().__init__('NominaIndividualDeAjuste', './Reemplazar', schemaLocation=schema, namespace_ajuste='dian:gov:co:facturaelectronica:NominaIndividualDeAjuste')
|
||||
|
||||
self.informacion_general_version = 'V1.0: Nota de Ajuste de Documento Soporte de Pago de Nómina Electrónica'
|
||||
schema = (
|
||||
"dian:gov:co:facturaelectronica:NominaIndividualDeAjuste"
|
||||
" NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
'NominaIndividualDeAjuste',
|
||||
'./Reemplazar',
|
||||
schemaLocation=schema,
|
||||
namespace_ajuste=(
|
||||
'dian:gov:co:facturaelectronica:'
|
||||
'NominaIndividualDeAjuste'))
|
||||
|
||||
self.informacion_general_version = (
|
||||
'V1.0: Nota de Ajuste de Documento Soporte de Pago de '
|
||||
'Nómina Electrónica')
|
||||
|
||||
def asignar_predecesor(self, predecesor):
|
||||
if not isinstance(predecesor, self.Predecesor):
|
||||
raise ValueError("se espera tipo Predecesor")
|
||||
predecesor.apply(self.fexml)
|
||||
|
||||
|
||||
class Eliminar(DIANNominaXML):
|
||||
|
||||
|
||||
@dataclass
|
||||
class Predecesor:
|
||||
numero: str
|
||||
@@ -628,24 +794,34 @@ class DIANNominaIndividualDeAjuste(DIANNominaXML):
|
||||
fragment.set_element('./TipoNota', '2')
|
||||
fragment.set_element('./Eliminar/EliminandoPredecesor', None,
|
||||
# NIAE090
|
||||
NumeroPred = self.numero,
|
||||
NumeroPred=self.numero,
|
||||
# NIAE191
|
||||
CUNEPred = self.cune,
|
||||
CUNEPred=self.cune,
|
||||
# NIAE192
|
||||
FechaGenPred = self.fecha_generacion
|
||||
FechaGenPred=self.fecha_generacion
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
schema = "dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"
|
||||
super().__init__('NominaIndividualDeAjuste', './Eliminar', schemaLocation=schema, namespace_ajuste='dian:gov:co:facturaelectronica:NominaIndividualDeAjuste')
|
||||
schema = (
|
||||
"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):
|
||||
if not isinstance(predecesor, self.Predecesor):
|
||||
raise ValueError("se espera tipo Eliminar.Predecesor")
|
||||
predecesor.apply(self.fexml)
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__('NominaIndividualDeAjuste')
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from .. import form
|
||||
|
||||
|
||||
class Amount(form.Amount):
|
||||
pass
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# al crear objetos de valor
|
||||
# se debe exportar en __all__
|
||||
|
||||
from .deduccion import *
|
||||
from .salud import *
|
||||
from .fondo_pension import *
|
||||
from .deduccion import Deduccion
|
||||
from .salud import DeduccionSalud
|
||||
from .fondo_pension import DeduccionFondoPension
|
||||
|
||||
__all__ = [
|
||||
'Deduccion',
|
||||
|
||||
@@ -3,6 +3,7 @@ from dataclasses import dataclass
|
||||
from ..amount import Amount
|
||||
from .deduccion import Deduccion
|
||||
|
||||
|
||||
@dataclass
|
||||
class DeduccionFondoPension(Deduccion):
|
||||
porcentaje: Amount
|
||||
@@ -10,9 +11,9 @@ class DeduccionFondoPension(Deduccion):
|
||||
|
||||
def apply(self, fragment):
|
||||
fragment.set_element('./FondoPension', None,
|
||||
append_ = True,
|
||||
append_=True,
|
||||
# NIE164
|
||||
Porcentaje = str(round(self.porcentaje, 2)),
|
||||
Porcentaje=str(round(self.porcentaje, 2)),
|
||||
# NIE166
|
||||
Deduccion = self.deduccion
|
||||
Deduccion=self.deduccion
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@ from dataclasses import dataclass
|
||||
from ..amount import Amount
|
||||
from .deduccion import Deduccion
|
||||
|
||||
|
||||
@dataclass
|
||||
class DeduccionSalud(Deduccion):
|
||||
porcentaje: Amount
|
||||
@@ -10,10 +11,9 @@ class DeduccionSalud(Deduccion):
|
||||
|
||||
def apply(self, fragment):
|
||||
fragment.set_element('./Salud', None,
|
||||
append_ = True,
|
||||
append_=True,
|
||||
# NIE161
|
||||
Porcentaje = str(round(self.porcentaje, 2)),
|
||||
Porcentaje=str(round(self.porcentaje, 2)),
|
||||
# NIE163
|
||||
Deduccion = self.deduccion
|
||||
Deduccion=self.deduccion
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from .. import form
|
||||
|
||||
|
||||
class Departamento(form.CountrySubentity):
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
|
||||
from .basico import *
|
||||
from .transporte import *
|
||||
from .devengado import *
|
||||
from .horas_extras import *
|
||||
from .basico import DevengadoBasico
|
||||
from .transporte import DevengadoTransporte
|
||||
from .devengado import Devengado
|
||||
from .horas_extras import (
|
||||
DevengadoHoraExtra,
|
||||
DevengadoHorasExtrasDiarias,
|
||||
DevengadoHorasExtrasNocturnas,
|
||||
DevengadoHorasRecargoNocturno,
|
||||
DevengadoHorasExtrasDiariasDominicalesYFestivos,
|
||||
DevengadoHorasRecargoDiariasDominicalesYFestivos,
|
||||
DevengadoHorasExtrasNocturnasDominicalesYFestivos,
|
||||
DevengadoHorasRecargoNocturnoDominicalesYFestivos,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'Devengado',
|
||||
|
||||
@@ -11,10 +11,10 @@ class DevengadoBasico(Devengado):
|
||||
|
||||
def apply(self, fragment):
|
||||
fragment.find_or_create_element('./Basico')
|
||||
|
||||
|
||||
fragment.set_attributes('/Basico',
|
||||
# NIE069
|
||||
DiasTrabajados = str(self.dias_trabajados),
|
||||
DiasTrabajados=str(self.dias_trabajados),
|
||||
# NIE070
|
||||
SueldoTrabajado = round(self.sueldo_trabajado, 2)
|
||||
SueldoTrabajado=round(self.sueldo_trabajado, 2)
|
||||
)
|
||||
|
||||
@@ -31,16 +31,17 @@ class DevengadoHoraExtra:
|
||||
@dataclass
|
||||
class DevengadoHorasExtrasDiarias(Devengado):
|
||||
horas_extras: list[DevengadoHoraExtra]
|
||||
|
||||
|
||||
def apply(self, fragment):
|
||||
hora_extra_xml = fragment.fragment('./HEDs')
|
||||
for hora_extra in self.horas_extras:
|
||||
hora_extra.apply('./HED', hora_extra_xml)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DevengadoHorasExtrasNocturnas(Devengado):
|
||||
horas_extras: list[DevengadoHoraExtra]
|
||||
|
||||
|
||||
def apply(self, fragment):
|
||||
hora_extra_xml = fragment.fragment('./HENs')
|
||||
for hora_extra in self.horas_extras:
|
||||
@@ -50,43 +51,47 @@ class DevengadoHorasExtrasNocturnas(Devengado):
|
||||
@dataclass
|
||||
class DevengadoHorasRecargoNocturno(Devengado):
|
||||
horas_extras: list[DevengadoHoraExtra]
|
||||
|
||||
|
||||
def apply(self, fragment):
|
||||
hora_extra_xml = fragment.fragment('./HRNs')
|
||||
for hora_extra in self.horas_extras:
|
||||
hora_extra.apply('./HRN', hora_extra_xml)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DevengadoHorasExtrasDiariasDominicalesYFestivos(Devengado):
|
||||
horas_extras: list[DevengadoHoraExtra]
|
||||
|
||||
|
||||
def apply(self, fragment):
|
||||
hora_extra_xml = fragment.fragment('./HEDDFs')
|
||||
for hora_extra in self.horas_extras:
|
||||
hora_extra.apply('./HEDDF', hora_extra_xml)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DevengadoHorasRecargoDiariasDominicalesYFestivos(Devengado):
|
||||
horas_extras: list[DevengadoHoraExtra]
|
||||
|
||||
|
||||
def apply(self, fragment):
|
||||
hora_extra_xml = fragment.fragment('./HRDDFs')
|
||||
for hora_extra in self.horas_extras:
|
||||
hora_extra.apply('./HRDDF', hora_extra_xml)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DevengadoHorasExtrasNocturnasDominicalesYFestivos(Devengado):
|
||||
horas_extras: list[DevengadoHoraExtra]
|
||||
|
||||
|
||||
def apply(self, fragment):
|
||||
hora_extra_xml = fragment.fragment('./HENDFs')
|
||||
for hora_extra in self.horas_extras:
|
||||
hora_extra.apply('./HENDF', hora_extra_xml)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DevengadoHorasRecargoNocturnoDominicalesYFestivos(Devengado):
|
||||
horas_extras: list[DevengadoHoraExtra]
|
||||
|
||||
|
||||
def apply(self, fragment):
|
||||
hora_extra_xml = fragment.fragment('./HRNDFs')
|
||||
for hora_extra in self.horas_extras:
|
||||
|
||||
@@ -3,6 +3,7 @@ from dataclasses import dataclass
|
||||
from ..amount import Amount
|
||||
from .devengado import Devengado
|
||||
|
||||
|
||||
@dataclass
|
||||
class DevengadoTransporte(Devengado):
|
||||
auxilio_transporte: Amount = None
|
||||
@@ -11,11 +12,12 @@ class DevengadoTransporte(Devengado):
|
||||
|
||||
def apply(self, fragment):
|
||||
fragment.set_element('./Transporte', None,
|
||||
append_ = True,
|
||||
append_=True,
|
||||
# NIE071
|
||||
AuxilioTransporte = self.auxilio_transporte,
|
||||
AuxilioTransporte=self.auxilio_transporte,
|
||||
# NIE072
|
||||
ViaticoManuAlojS = self.viatico_manutencion,
|
||||
ViaticoManuAlojS=self.viatico_manutencion,
|
||||
# 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 ..municipio import Municipio
|
||||
|
||||
|
||||
@dataclass
|
||||
class Empleador:
|
||||
razon_social: str
|
||||
@@ -17,19 +18,17 @@ class Empleador:
|
||||
def apply(self, fragment):
|
||||
fragment.set_attributes('./Empleador',
|
||||
# NIE033
|
||||
NIT = self.nit,
|
||||
NIT=self.nit,
|
||||
# NIE034
|
||||
DV = self.dv,
|
||||
DV=self.dv,
|
||||
# NIE035
|
||||
Pais = self.pais.code,
|
||||
Pais=self.pais.code,
|
||||
# NIE036
|
||||
DepartamentoEstado = self.departamento.code,
|
||||
DepartamentoEstado=self.departamento.code,
|
||||
# NIE037
|
||||
MunicipioCiudad = self.municipio.code,
|
||||
MunicipioCiudad=self.municipio.code,
|
||||
# NIE038
|
||||
Direccion = self.direccion,
|
||||
Direccion=self.direccion,
|
||||
|
||||
RazonSocial=self.razon_social
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import datetime
|
||||
|
||||
from facho import fe
|
||||
|
||||
|
||||
class Habilitacion:
|
||||
|
||||
@dataclass
|
||||
@@ -16,19 +17,19 @@ class Habilitacion:
|
||||
self.metadata = metadata
|
||||
|
||||
def generar(self, zipname, fecha):
|
||||
nominas = []
|
||||
dianzip = fe.DianZIP(open(zipname, 'w'))
|
||||
fe.DianZIP(open(zipname, 'w'))
|
||||
|
||||
fechabase = datetime.datetime.now()
|
||||
consecutivo = 0
|
||||
for _ in range(1, 11):
|
||||
consecutivo += 1
|
||||
fechabase += datetime.timedelta(days=1)
|
||||
nomina = self._crear_nomina_individual()
|
||||
self._crear_nomina_individual()
|
||||
|
||||
# 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):
|
||||
metadata = self.metadata
|
||||
|
||||
@@ -36,10 +37,15 @@ class Habilitacion:
|
||||
|
||||
nomina_ajuste = fe.nomina.DIANNominaIndividualDeAjuste.Reemplazar()
|
||||
self._poblar_nomina(nomina_ajuste, metadata, fecha, prefijo='R')
|
||||
informacion_general = nomina.informacion_general()
|
||||
|
||||
|
||||
def _poblar_nomina(self, nomina, metadata, fecha, prefijo='N', consecutivo='0001'):
|
||||
nomina.informacion_general()
|
||||
|
||||
def _poblar_nomina(
|
||||
self,
|
||||
nomina,
|
||||
metadata,
|
||||
fecha,
|
||||
prefijo='N',
|
||||
consecutivo='0001'):
|
||||
nomina.asignar_fecha_pago(fecha)
|
||||
|
||||
nomina.asignar_metadata(fe.nomina.Metadata(
|
||||
@@ -48,14 +54,14 @@ class Habilitacion:
|
||||
consecutivo=consecutivo
|
||||
),
|
||||
lugar_generacion=fe.nomina.Lugar(
|
||||
pais = fe.nomina.Pais(
|
||||
code = 'CO'
|
||||
pais=fe.nomina.Pais(
|
||||
code='CO'
|
||||
),
|
||||
departamento = fe.nomina.Departamento(
|
||||
code = '05'
|
||||
departamento=fe.nomina.Departamento(
|
||||
code='05'
|
||||
),
|
||||
municipio = fe.nomina.Municipio(
|
||||
code = '05001'
|
||||
municipio=fe.nomina.Municipio(
|
||||
code='05001'
|
||||
),
|
||||
),
|
||||
proveedor=fe.nomina.Proveedor(
|
||||
@@ -72,14 +78,14 @@ class Habilitacion:
|
||||
fecha_liquidacion_fin=fecha,
|
||||
fecha_generacion=fecha,
|
||||
))
|
||||
|
||||
|
||||
nomina.asignar_informacion_general(fe.nomina.InformacionGeneral(
|
||||
fecha_generacion = fecha,
|
||||
hora_generacion = '20:09:00-05:00',
|
||||
tipo_ambiente = fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
||||
software_pin = metadata.software_pin,
|
||||
periodo_nomina = fe.nomina.PeriodoNomina(code='1'),
|
||||
tipo_moneda = fe.nomina.TipoMoneda(code='COP')
|
||||
fecha_generacion=fecha,
|
||||
hora_generacion='20:09:00-05:00',
|
||||
tipo_ambiente=fe.nomina.InformacionGeneral.AMBIENTE_PRUEBAS,
|
||||
software_pin=metadata.software_pin,
|
||||
periodo_nomina=fe.nomina.PeriodoNomina(code='1'),
|
||||
tipo_moneda=fe.nomina.TipoMoneda(code='COP')
|
||||
))
|
||||
|
||||
nomina.asignar_pago(fe.nomina.Pago(
|
||||
@@ -91,53 +97,53 @@ class Habilitacion:
|
||||
)
|
||||
))
|
||||
nomina.asignar_empleador(fe.nomina.Empleador(
|
||||
nit = metadata.nit,
|
||||
dv = '0',
|
||||
pais = fe.nomina.Pais(
|
||||
code = 'CO'
|
||||
nit=metadata.nit,
|
||||
dv='0',
|
||||
pais=fe.nomina.Pais(
|
||||
code='CO'
|
||||
),
|
||||
departamento = fe.nomina.Departamento(
|
||||
code = '05'
|
||||
departamento=fe.nomina.Departamento(
|
||||
code='05'
|
||||
),
|
||||
municipio = fe.nomina.Municipio(
|
||||
code = '05001'
|
||||
municipio=fe.nomina.Municipio(
|
||||
code='05001'
|
||||
),
|
||||
direccion = 'calle etrivial'
|
||||
direccion='calle etrivial'
|
||||
))
|
||||
|
||||
nomina.asignar_trabajador(fe.nomina.Trabajador(
|
||||
tipo_contrato = fe.nomina.TipoContrato(
|
||||
code = '1'
|
||||
tipo_contrato=fe.nomina.TipoContrato(
|
||||
code='1'
|
||||
),
|
||||
alto_riesgo = False,
|
||||
tipo_documento = fe.nomina.TipoDocumento(
|
||||
code = '11'
|
||||
alto_riesgo=False,
|
||||
tipo_documento=fe.nomina.TipoDocumento(
|
||||
code='11'
|
||||
),
|
||||
primer_apellido = 'gnu',
|
||||
segundo_apellido = 'emacs',
|
||||
primer_nombre = 'facho',
|
||||
lugar_trabajo = fe.nomina.LugarTrabajo(
|
||||
pais = fe.nomina.Pais(code='CO'),
|
||||
departamento = fe.nomina.Departamento(code='05'),
|
||||
municipio = fe.nomina.Municipio(code='05001'),
|
||||
direccion = 'calle facho'
|
||||
primer_apellido='gnu',
|
||||
segundo_apellido='emacs',
|
||||
primer_nombre='facho',
|
||||
lugar_trabajo=fe.nomina.LugarTrabajo(
|
||||
pais=fe.nomina.Pais(code='CO'),
|
||||
departamento=fe.nomina.Departamento(code='05'),
|
||||
municipio=fe.nomina.Municipio(code='05001'),
|
||||
direccion='calle facho'
|
||||
),
|
||||
numero_documento = metadata.nit,
|
||||
tipo = fe.nomina.TipoTrabajador(
|
||||
code = '01'
|
||||
numero_documento=metadata.nit,
|
||||
tipo=fe.nomina.TipoTrabajador(
|
||||
code='01'
|
||||
),
|
||||
salario_integral = True,
|
||||
sueldo = fe.nomina.Amount(1_500_000)
|
||||
salario_integral=True,
|
||||
sueldo=fe.nomina.Amount(1_500_000)
|
||||
))
|
||||
|
||||
|
||||
nomina.adicionar_devengado(fe.nomina.DevengadoBasico(
|
||||
dias_trabajados = 60,
|
||||
sueldo_trabajado = fe.nomina.Amount(3_500_000)
|
||||
dias_trabajados=60,
|
||||
sueldo_trabajado=fe.nomina.Amount(3_500_000)
|
||||
))
|
||||
|
||||
nomina.adicionar_deduccion(fe.nomina.DeduccionSalud(
|
||||
porcentaje = fe.nomina.Amount(19),
|
||||
deduccion = fe.nomina.Amount(1_000_000)
|
||||
porcentaje=fe.nomina.Amount(19),
|
||||
deduccion=fe.nomina.Amount(1_000_000)
|
||||
))
|
||||
|
||||
nomina.adicionar_deduccion(fe.nomina.DeduccionFondoPension(
|
||||
@@ -152,4 +158,3 @@ class Habilitacion:
|
||||
|
||||
nomina = fe.nomina.DIANNominaIndividual()
|
||||
self._poblar_nomina(nomina, metadata, fecha)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from .departamento import Departamento
|
||||
from .municipio import Municipio
|
||||
from facho.fe.data.dian import codelist
|
||||
|
||||
|
||||
@dataclass
|
||||
class Lugar:
|
||||
pais: Pais
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from .. import form
|
||||
|
||||
|
||||
class Municipio(form.City):
|
||||
pass
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ from dataclasses import dataclass
|
||||
from .forma_pago import FormaPago
|
||||
from .metodo_pago import MetodoPago
|
||||
|
||||
|
||||
@dataclass
|
||||
class Pago:
|
||||
forma: FormaPago
|
||||
@@ -11,6 +12,6 @@ class Pago:
|
||||
def apply(self, fragment):
|
||||
fragment.set_attributes('./Pago',
|
||||
# NIE064
|
||||
Forma = self.forma.code,
|
||||
Forma=self.forma.code,
|
||||
# NIE065
|
||||
Metodo = self.metodo.code)
|
||||
Metodo=self.metodo.code)
|
||||
|
||||
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
||||
|
||||
from facho.fe.data.dian import codelist
|
||||
|
||||
|
||||
@dataclass
|
||||
class FormaPago:
|
||||
code: str
|
||||
|
||||
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
||||
|
||||
from facho.fe.data.dian import codelist
|
||||
|
||||
|
||||
@dataclass
|
||||
class MetodoPago:
|
||||
code: str
|
||||
@@ -11,4 +12,3 @@ class MetodoPago:
|
||||
if self.code not in codelist.MediosPago:
|
||||
raise ValueError("code [%s] not found" % (self.code))
|
||||
self.name = codelist.MediosPago[self.code]['name']
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from .. import form
|
||||
|
||||
|
||||
class Pais(form.Country):
|
||||
pass
|
||||
|
||||
@@ -2,12 +2,11 @@ from dataclasses import dataclass, field
|
||||
|
||||
from ..amount import Amount
|
||||
|
||||
from .tipo_contrato import *
|
||||
from .tipo_documento import *
|
||||
from .lugar_trabajo import *
|
||||
from .tipo_trabajador import *
|
||||
from .sub_tipo_trabajador import *
|
||||
|
||||
from .tipo_contrato import TipoContrato
|
||||
from .tipo_documento import TipoDocumento
|
||||
from .lugar_trabajo import LugarTrabajo
|
||||
from .tipo_trabajador import TipoTrabajador
|
||||
from .sub_tipo_trabajador import SubTipoTrabajador
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -29,45 +28,47 @@ class Trabajador:
|
||||
|
||||
codigo_trabajador: 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):
|
||||
fragment.set_attributes('./Trabajador',
|
||||
# NIE041
|
||||
TipoTrabajador = self.tipo.code,
|
||||
# NIE042
|
||||
SubTipoTrabajador = self.sub_tipo.code,
|
||||
# NIE043
|
||||
AltoRiesgoPension = str(self.alto_riesgo).lower(),
|
||||
# NIE044
|
||||
TipoDocumento = self.tipo_documento.code,
|
||||
# NIE045
|
||||
NumeroDocumento = self.numero_documento,
|
||||
# NIE046
|
||||
PrimerApellido = self.primer_apellido,
|
||||
# NIE047
|
||||
SegundoApellido = self.segundo_apellido,
|
||||
# NIE048
|
||||
PrimerNombre = self.primer_nombre,
|
||||
# NIE049
|
||||
OtrosNombres = self.otros_nombres,
|
||||
# NIE050
|
||||
LugarTrabajoPais = self.lugar_trabajo.pais.code,
|
||||
|
||||
# NIE051
|
||||
LugarTrabajoDepartamentoEstado = self.lugar_trabajo.departamento.code,
|
||||
|
||||
# NIE052
|
||||
LugarTrabajoMunicipioCiudad = self.lugar_trabajo.municipio.code,
|
||||
|
||||
# NIE053
|
||||
LugarTrabajoDireccion = self.lugar_trabajo.direccion,
|
||||
# NIE056
|
||||
SalarioIntegral = str(self.salario_integral).lower(),
|
||||
# NIE061
|
||||
TipoContrato = self.tipo_contrato.code,
|
||||
# NIE062
|
||||
Sueldo = str(self.sueldo),
|
||||
# NIE063
|
||||
CodigoTrabajador = self.codigo_trabajador
|
||||
)
|
||||
fragment.set_attributes(
|
||||
"./Trabajador",
|
||||
# NIE041
|
||||
TipoTrabajador=self.tipo.code,
|
||||
# NIE042
|
||||
SubTipoTrabajador=self.sub_tipo.code,
|
||||
# NIE043
|
||||
AltoRiesgoPension=str(self.alto_riesgo).lower(),
|
||||
# NIE044
|
||||
TipoDocumento=self.tipo_documento.code,
|
||||
# NIE045
|
||||
NumeroDocumento=self.numero_documento,
|
||||
# NIE046
|
||||
PrimerApellido=self.primer_apellido,
|
||||
# NIE047
|
||||
SegundoApellido=self.segundo_apellido,
|
||||
# NIE048
|
||||
PrimerNombre=self.primer_nombre,
|
||||
# NIE049
|
||||
OtrosNombres=self.otros_nombres,
|
||||
# NIE050
|
||||
LugarTrabajoPais=self.lugar_trabajo.pais.code,
|
||||
# NIE051
|
||||
LugarTrabajoDepartamentoEstado=(
|
||||
self.lugar_trabajo.departamento.code
|
||||
),
|
||||
# NIE052
|
||||
LugarTrabajoMunicipioCiudad=self.lugar_trabajo.municipio.code,
|
||||
# NIE053
|
||||
LugarTrabajoDireccion=self.lugar_trabajo.direccion,
|
||||
# NIE056
|
||||
SalarioIntegral=str(self.salario_integral).lower(),
|
||||
# NIE061
|
||||
TipoContrato=self.tipo_contrato.code,
|
||||
# NIE062
|
||||
Sueldo=str(self.sueldo),
|
||||
# NIE063
|
||||
CodigoTrabajador=self.codigo_trabajador,
|
||||
)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from . import *
|
||||
from ..pais import Pais
|
||||
from ..departamento import Departamento
|
||||
from ..municipio import Municipio
|
||||
|
||||
|
||||
@dataclass
|
||||
class LugarTrabajo:
|
||||
pais: Pais
|
||||
|
||||
@@ -2,12 +2,13 @@ from dataclasses import dataclass
|
||||
|
||||
from facho.fe.data.dian import codelist
|
||||
|
||||
|
||||
@dataclass
|
||||
class SubTipoTrabajador:
|
||||
code: str
|
||||
name: str = ''
|
||||
name: str = ""
|
||||
|
||||
def __post_init__(self):
|
||||
if self.code not in codelist.SubTipoTrabajador:
|
||||
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
|
||||
|
||||
|
||||
@dataclass
|
||||
class TipoContrato:
|
||||
code: str
|
||||
name: str = ''
|
||||
name: str = ""
|
||||
|
||||
def __post_init__(self):
|
||||
if self.code not in codelist.TipoContrato:
|
||||
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
|
||||
|
||||
|
||||
@dataclass
|
||||
class TipoDocumento:
|
||||
code: str
|
||||
name: str = ''
|
||||
name: str = ""
|
||||
|
||||
def __post_init__(self):
|
||||
if self.code not in codelist.TipoIdFiscal:
|
||||
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
|
||||
|
||||
|
||||
@dataclass
|
||||
class TipoTrabajador:
|
||||
code: str
|
||||
name: str = ''
|
||||
name: str = ""
|
||||
|
||||
def __post_init__(self):
|
||||
if self.code not in codelist.TipoTrabajador:
|
||||
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