Machete Anexo ID NIE901

FossilOrigin-Name: ce5cd5e95d640dd97a277bfc072e376566bac007c33f9ff521a70470f39dc5bb
This commit is contained in:
pingara 2022-04-22 01:55:01 +00:00
parent 29db6b0342
commit ac1678b1cc
2 changed files with 35 additions and 14 deletions

View File

@ -32,9 +32,10 @@ POLICY_NAME = u'Política de firma para facturas electrónicas de la República
NAMESPACES = { NAMESPACES = {
'facho': 'http://git.disroot.org/Etrivial/facho',
'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2', 'atd': 'urn:oasis:names:specification:ubl:schema:xsd:AttachedDocument-2',
'no': 'dian:gov:co:facturaelectronica:NominaIndividual',
'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',
'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', 'cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', 'cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1', 'cdt': 'urn:DocumentInformation:names:specification:ubl:colombia:schema:xsd:DocumentInformationAggregateComponents-1',
@ -46,6 +47,7 @@ NAMESPACES = {
'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#',
'ds': 'http://www.w3.org/2000/09/xmldsig#', 'ds': 'http://www.w3.org/2000/09/xmldsig#',
'sig': 'http://www.w3.org/2000/09/xmldsig#', 'sig': 'http://www.w3.org/2000/09/xmldsig#',
} }
@ -87,7 +89,8 @@ class FeXML(FachoXML):
# 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
return super().tostring(**kw)\ return super().tostring(**kw)\
.replace("fe:", "")\ .replace("fe:", "")\
.replace("xmlns:fe", "xmlns") .replace("xmlns:no", "xmlns")\
.replace("change", "xsi:schemaLocation")
class DianXMLExtensionCUDFE(FachoXMLExtension): class DianXMLExtensionCUDFE(FachoXMLExtension):

View File

@ -50,6 +50,19 @@ class FechaPago(Fecha):
def apply(self, fragment): def apply(self, fragment):
fragment.set_element('./FechaPago', self.value) fragment.set_element('./FechaPago', self.value)
@dataclass
class Novedad:
value: False
def apply(self, fragment):
fragment.set_attributes('./Novedad',
CUNENov=self.value,
)
def post_apply(self, fexml, scopexml, fragment):
scopexml.set_element('./Novedad', "false")
@dataclass @dataclass
class NumeroSecuencia: class NumeroSecuencia:
consecutivo: int consecutivo: int
@ -131,6 +144,7 @@ class Proveedor:
raise RuntimeError('fail to get InformacionGeneral/@Ambiente') raise RuntimeError('fail to get InformacionGeneral/@Ambiente')
scopexml.set_element('./CodigoQR', codigo_qr) scopexml.set_element('./CodigoQR', codigo_qr)
scopexml.set_element('./Novedad', "false")
# NIE020 # NIE020
software_code = self._software_security_code(fexml, scopexml) software_code = self._software_security_code(fexml, scopexml)
@ -149,25 +163,28 @@ class Proveedor:
code = "".join([id_software, software_pin, numero]) code = "".join([id_software, software_pin, numero])
fexml.set_attributes(scopexml.xpath_from_root('/ProveedorXML'), fachoSoftwareSC=code) fexml.set_attributes(scopexml.xpath_from_root('/ProveedorXML'))
h = hashlib.sha384() h = hashlib.sha384()
h.update(code.encode('utf-8')) h.update(code.encode('utf-8'))
return h.hexdigest() return h.hexdigest()
@dataclass @dataclass
class Metadata: class Metadata:
novedad: Novedad
secuencia: NumeroSecuencia secuencia: NumeroSecuencia
# NIE013, NIE014, NIE015, NIE016 # NIE013, NIE014, NIE015, NIE016
lugar_generacion: Lugar lugar_generacion: Lugar
proveedor: Proveedor proveedor: Proveedor
def apply(self, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml): def apply(self, novedad, numero_secuencia_xml, lugar_generacion_xml, proveedor_xml):
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, 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)
self.novedad.post_apply(fexml, scopexml, proveedor_xml)
@dataclass @dataclass
class PeriodoNomina: class PeriodoNomina:
@ -245,7 +262,8 @@ class InformacionGeneral:
# NIE029 # NIE029
PeriodoNomina = self.periodo_nomina.code, PeriodoNomina = self.periodo_nomina.code,
# NIE030 # NIE030
TipoMoneda = self.tipo_moneda.code TipoMoneda = self.tipo_moneda.code,
TRM = 0
# TODO(bit4bit) resto... # TODO(bit4bit) resto...
# ..... # .....
) )
@ -278,8 +296,7 @@ class InformacionGeneral:
fragment.set_attributes( fragment.set_attributes(
'./InformacionGeneral', './InformacionGeneral',
# NIE024 # NIE024
CUNE = cune_hash, CUNE = cune_hash
fachoCUNE = cune
) )
class DianXMLExtensionSigner(fe.DianXMLExtensionSigner): class DianXMLExtensionSigner(fe.DianXMLExtensionSigner):
@ -299,7 +316,8 @@ class DIANNominaXML:
self.fexml = fe.FeXML(tag_document, 'http://www.dian.gov.co/contratos/facturaelectronica/v1') self.fexml = fe.FeXML(tag_document, 'http://www.dian.gov.co/contratos/facturaelectronica/v1')
if schemaLocation is not None: if schemaLocation is not None:
self.fexml.root.set("SchemaLocation", schemaLocation) self.fexml.root.set("SchemaLocation", "")
self.fexml.root.set("change", 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
@ -311,7 +329,7 @@ class DIANNominaXML:
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('./ReemplazandoPredecesor', optional=True)
self.root_fragment.placeholder_for('./EliminandoPredecesor', optional=True) self.root_fragment.placeholder_for('./EliminandoPredecesor', optional=True)
self.root_fragment.placeholder_for('./Novedad', optional=True) self.root_fragment.placeholder_for('./Novedad', optional=False)
self.root_fragment.placeholder_for('./Periodo') self.root_fragment.placeholder_for('./Periodo')
self.root_fragment.placeholder_for('./NumeroSecuenciaXML') self.root_fragment.placeholder_for('./NumeroSecuenciaXML')
self.root_fragment.placeholder_for('./LugarGeneracionXML') self.root_fragment.placeholder_for('./LugarGeneracionXML')
@ -325,7 +343,7 @@ class DIANNominaXML:
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)
self.novedad = self.root_fragment.fragment('./Novedad')
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')
@ -345,7 +363,7 @@ class DIANNominaXML:
if not isinstance(metadata, Metadata): if not isinstance(metadata, Metadata):
raise ValueError('se espera tipo Metadata') raise ValueError('se espera tipo Metadata')
self.metadata = metadata self.metadata = metadata
self.metadata.apply(self.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):
@ -461,7 +479,7 @@ class DIANNominaXML:
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.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
@ -501,7 +519,7 @@ class DIANNominaXML:
devengados_total = Amount(0.0) devengados_total = Amount(0.0)
for devengado in devengados: for devengado in devengados:
devengados_total += devengado devengados_total += devengado
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):