se extendie NominaIndividualDeAjuste de NominaIndividual

FossilOrigin-Name: 10b3af439bee9b932e4f5067bec0768af60e514f595e00ecb1bdf7c88c39afc1
This commit is contained in:
bit4bit 2021-11-10 01:08:39 +00:00
parent b60fe675c1
commit bb16b5e968
3 changed files with 69 additions and 28 deletions

View File

@ -455,5 +455,16 @@ class FachoXML:
def tostring(self, **kw): def tostring(self, **kw):
return self.builder.tostring(self.root, **kw) return self.builder.tostring(self.root, **kw)
def xpath_from_root(self, xpath):
nsmap = {}
ns = ''
if isinstance(self.nsmap, dict):
nsmap = dict(map(reversed, self.nsmap.items()))
ns = nsmap[etree.QName(self.root).namespace] + ':'
new_xpath = '/' + ns + etree.QName(self.root).localname + '/' + xpath.lstrip('/')
return new_xpath
def __str__(self): def __str__(self):
return self.tostring() return self.tostring()

View File

@ -69,17 +69,17 @@ class InformacionGeneral:
# generar cune # generar cune
# ver 8.1.1.1 # ver 8.1.1.1
xpaths = [ xpaths = [
'/fe:NominaIndividual/NumeroSecuenciaXML/@Numero', fexml.xpath_from_root('/NumeroSecuenciaXML/@Numero'),
'/fe:NominaIndividual/InformacionGeneral/@FechaGen', fexml.xpath_from_root('/InformacionGeneral/@FechaGen'),
'/fe:NominaIndividual/InformacionGeneral/@HoraGen', fexml.xpath_from_root('/InformacionGeneral/@HoraGen'),
'/fe:NominaIndividual/DevengadosTotal', fexml.xpath_from_root('/DevengadosTotal'),
'/fe:NominaIndividual/DeduccionesTotal', fexml.xpath_from_root('/DeduccionesTotal'),
'/fe:NominaIndividual/ComprobanteTotal', fexml.xpath_from_root('/ComprobanteTotal'),
'/fe:NominaIndividual/Empleador/@NIT', fexml.xpath_from_root('/Empleador/@NIT'),
'/fe:NominaIndividual/Trabajador/@NumeroDocumento', fexml.xpath_from_root('/Trabajador/@NumeroDocumento'),
'/fe:NominaIndividual/InformacionGeneral/@TipoXML', fexml.xpath_from_root('/InformacionGeneral/@TipoXML'),
tuple([self.software_pin]), tuple([self.software_pin]),
'/fe:NominaIndividual/InformacionGeneral/@Ambiente' fexml.xpath_from_root('/InformacionGeneral/@Ambiente')
] ]
campos = fexml.get_elements_text_or_attributes(xpaths) campos = fexml.get_elements_text_or_attributes(xpaths)
@ -111,9 +111,10 @@ class Trabajador:
fragment.set_attributes('./Trabajador', fragment.set_attributes('./Trabajador',
NumeroDocumento = self.numero_documento) NumeroDocumento = self.numero_documento)
class DIANNominaIndividual: class DIANNominaXML:
def __init__(self): def __init__(self, tag_document):
self.fexml = fe.FeXML('NominaIndividual', 'http://www.dian.gov.co/contratos/facturaelectronica/v1') self.tag_document = tag_document
self.fexml = fe.FeXML(tag_document, 'http://www.dian.gov.co/contratos/facturaelectronica/v1')
# 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
@ -187,20 +188,23 @@ class DIANNominaIndividual:
if elem.get(key, None) is None: if elem.get(key, None) is None:
return errors.append(err) return errors.append(err)
check_attribute('/fe:NominaIndividual/Periodo', 'FechaIngreso', 'se requiere Periodo') check_attribute(
self.fexml.xpath_from_root('/Periodo'),
'FechaIngreso',
'se requiere Periodo')
check_element( check_element(
'/fe:NominaIndividual/Devengados/Basico', self.fexml.xpath_from_root('/Devengados/Basico'),
'se requiere DevengadoBasico' 'se requiere DevengadoBasico'
) )
check_element( check_element(
'/fe:NominaIndividual/Deducciones/Salud', self.fexml.xpath_from_root('/Deducciones/Salud'),
'se requiere DeduccionSalud' 'se requiere DeduccionSalud'
) )
check_element( check_element(
'/fe:NominaIndividual/Deducciones/FondoPension', self.fexml.xpath_from_root('/Deducciones/FondoPension'),
'se requiere DeduccionFondoPension' 'se requiere DeduccionFondoPension'
) )
@ -220,17 +224,17 @@ class DIANNominaIndividual:
return self.fexml return self.fexml
def _comprobante_total(self): def _comprobante_total(self):
devengados_total = self.fexml.get_element_text_or_attribute('/fe:NominaIndividual/DevengadosTotal', '0.0') devengados_total = self.fexml.get_element_text_or_attribute(self.fexml.xpath_from_root('/DevengadosTotal'), '0.0')
deducciones_total = self.fexml.get_element_text_or_attribute('/fe:NominaIndividual/DeduccionesTotal', '0.0') deducciones_total = self.fexml.get_element_text_or_attribute(self.fexml.xpath_from_root('/DeduccionesTotal'), '0.0')
comprobante_total = Amount(devengados_total) - Amount(deducciones_total) comprobante_total = Amount(devengados_total) - Amount(deducciones_total)
self.fexml.set_element('/fe:NominaIndividual/ComprobanteTotal', str(round(comprobante_total, 2))) self.fexml.set_element(self.fexml.xpath_from_root('/ComprobanteTotal'), str(round(comprobante_total, 2)))
def _deducciones_total(self): def _deducciones_total(self):
xpaths = [ xpaths = [
'/fe:NominaIndividual/Deducciones/Salud/@Deduccion', self.fexml.xpath_from_root('/Deducciones/Salud/@Deduccion'),
'/fe:NominaIndividual/Deducciones/FondoPension/@Deduccion' self.fexml.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))
@ -240,14 +244,14 @@ class DIANNominaIndividual:
for deduccion in deducciones: for deduccion in deducciones:
deducciones_total += deduccion deducciones_total += deduccion
self.fexml.set_element('/fe:NominaIndividual/DeduccionesTotal', str(round(deducciones_total, 2))) self.fexml.set_element(f'/fe:{self.tag_document}/DeduccionesTotal', str(round(deducciones_total, 2)))
def _devengados_total(self): def _devengados_total(self):
xpaths = [ xpaths = [
'/fe:NominaIndividual/Devengados/Basico/@SueldoTrabajado', self.fexml.xpath_from_root('/Devengados/Basico/@SueldoTrabajado'),
'/fe:NominaIndividual/Devengados/Transporte/@AuxilioTransporte', self.fexml.xpath_from_root('/Devengados/Transporte/@AuxilioTransporte'),
'/fe:NominaIndividual/Devengados/Transporte/@ViaticoManuAlojS', self.fexml.xpath_from_root('/Devengados/Transporte/@ViaticoManuAlojS'),
'/fe:NominaIndividual/Devengados/Transporte/@ViaticoManuAlojNS' self.fexml.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))
@ -256,7 +260,7 @@ class DIANNominaIndividual:
for devengado in devengados: for devengado in devengados:
devengados_total += devengado devengados_total += devengado
self.fexml.set_element('/fe:NominaIndividual/DevengadosTotal', str(round(devengados_total,2))) self.fexml.set_element(self.fexml.xpath_from_root('/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)
@ -270,3 +274,15 @@ class DIANNominaIndividual:
xpaths_values.append(xpath_value) xpaths_values.append(xpath_value)
return filter(lambda val: val is not None, xpaths_values) return filter(lambda val: val is not None, xpaths_values)
class DIANNominaIndividual(DIANNominaXML):
def __init__(self):
super().__init__('NominaIndividual')
# TODO(bit4bit) confirmar que no tienen en comun con NominaIndividual
class DIANNominaIndividualDeAjuste(DIANNominaXML):
def __init__(self):
super().__init__('NominaIndividualDeAjuste')

View File

@ -370,3 +370,17 @@ def test_facho_xml_query_element_text_or_attribute():
assert xml.get_element_text_or_attribute('/root/A') == 'contenido' assert xml.get_element_text_or_attribute('/root/A') == 'contenido'
assert xml.get_element_text_or_attribute('/root/A/@clave') == 'valor' assert xml.get_element_text_or_attribute('/root/A/@clave') == 'valor'
def test_facho_xml_build_xml_absolute():
xml = facho.FachoXML('root')
xpath = xml.xpath_from_root('/A')
assert xpath == '/root/A'
def test_facho_xml_build_xml_absolute_namespace():
xml = facho.FachoXML('{%s}root' % ('http://www.dian.gov.co/contratos/facturaelectronica/v1'),
nsmap={'fe': 'http://www.dian.gov.co/contratos/facturaelectronica/v1'})
xpath = xml.xpath_from_root('/A')
assert xpath == '/fe:root/A'