From 8a58fa10eb65b072448598a41ac55776d9f39ec2 Mon Sep 17 00:00:00 2001 From: el Mau Date: Tue, 8 Nov 2022 19:47:44 -0600 Subject: [PATCH] Add support for complements Pagos and Comercio --- source/helper/util.py | 159 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 150 insertions(+), 9 deletions(-) diff --git a/source/helper/util.py b/source/helper/util.py index d933e0c..04dbd0e 100644 --- a/source/helper/util.py +++ b/source/helper/util.py @@ -76,9 +76,9 @@ class DictToCfdi(): } _PAGOS = { 'version': '2.0', - 'prefix': '', - 'xmlns': 'http://www.sat.gob.mx/', - 'schema': ' http://www.sat.gob.mx/ http://www.sat.gob.mx/sitio_internet/cfd//.xsd', + 'prefix': 'pago20', + 'xmlns': 'http://www.sat.gob.mx/Pagos20', + 'schema': ' http://www.sat.gob.mx/Pagos20 http://www.sat.gob.mx/sitio_internet/cfd/Pagos/Pagos20.xsd', } _COMERCIO = { 'version': '1.1', @@ -123,6 +123,11 @@ class DictToCfdi(): self._attr_complementos['leyendas'] = { self._LEYENDAS['prefix']: self._LEYENDAS['xmlns'] } + if 'pagos' in self._data['complementos']: + self._schema += self._PAGOS['schema'] + self._attr_complementos['pagos'] = { + self._PAGOS['prefix']: self._PAGOS['xmlns'] + } if 'comercio' in self._data['complementos']: self._schema += self._COMERCIO['schema'] self._attr_complementos['comercio'] = { @@ -260,7 +265,58 @@ class DictToCfdi(): return def _complemento_pagos(self, data, node): - attr = {'version': self._PAGOS['version']} + pago = data.pop('pago') + docs = data.pop('docs') + taxesd = data.pop('taxesd') + taxes = data.pop('taxes') + + attr = {'Version': data.pop('Version')} + node_name = f"{{{self._PAGOS['xmlns']}}}Pagos" + node_pagos = ET.SubElement(node, node_name, attr) + + attr = data + node_name = f"{{{self._PAGOS['xmlns']}}}Totales" + ET.SubElement(node_pagos, node_name, attr) + + node_name = f"{{{self._PAGOS['xmlns']}}}Pago" + node_pago = ET.SubElement(node_pagos, node_name, pago) + + for i, doc in enumerate(docs): + node_name = f"{{{self._PAGOS['xmlns']}}}DoctoRelacionado" + node_doc = ET.SubElement(node_pago, node_name, doc) + if taxesd: + node_name = f"{{{self._PAGOS['xmlns']}}}ImpuestosDR" + node_taxes_doc = ET.SubElement(node_doc, node_name) + if 'retenciones' in taxesd: + node_name = f"{{{self._PAGOS['xmlns']}}}RetencionesDR" + node_taxes_dr = ET.SubElement(node_taxes_doc, node_name) + for r in taxesd['retenciones']: + node_name = f"{{{self._PAGOS['xmlns']}}}RetencionDR" + ET.SubElement(node_taxes_dr, node_name, r) + if 'traslados' in taxesd: + node_name = f"{{{self._PAGOS['xmlns']}}}TrasladosDR" + node_taxes_dt = ET.SubElement(node_taxes_doc, node_name) + for t in taxesd['traslados']: + node_name = f"{{{self._PAGOS['xmlns']}}}TrasladoDR" + ET.SubElement(node_taxes_dt, node_name, t) + + node_name = f"{{{self._PAGOS['xmlns']}}}ImpuestosP" + node_taxes = ET.SubElement(node_pago, node_name) + + if 'retenciones' in taxes: + node_name = f"{{{self._PAGOS['xmlns']}}}RetencionesP" + node_taxes_r = ET.SubElement(node_taxes, node_name) + for r in taxes['retenciones']: + node_name = f"{{{self._PAGOS['xmlns']}}}RetencionP" + ET.SubElement(node_taxes_r, node_name, r) + if 'traslados' in taxes: + node_name = f"{{{self._PAGOS['xmlns']}}}TrasladosP" + node_taxes_t = ET.SubElement(node_taxes, node_name) + for t in taxes['traslados']: + node_name = f"{{{self._PAGOS['xmlns']}}}TrasladoP" + ET.SubElement(node_taxes_t, node_name, t) + + return def _complemento_comercio(self, data, node): @@ -655,6 +711,9 @@ class DataToDict(): version = {'Version': data[1]} if self._complement == '1': self._cfdi['complementos']['pagos'] = version + self._cfdi['complementos']['pagos']['docs'] = [] + self._cfdi['complementos']['pagos']['taxes'] = {} + self._cfdi['complementos']['pagos']['taxesd'] = {} elif self._complement == '2': self._cfdi['complementos']['comercio'] = version @@ -704,7 +763,25 @@ class DataToDict(): return if self._complement == '1': - pass + fields = ( + 'FechaPago', + 'FormaDePagoP', + 'MonedaP', + 'TipoCambioP', + 'Monto', + 'NumOperacion', + 'RfcEmisorCtaOrd', + 'NomBancoOrdExt', + 'CtaOrdenante', + 'RfcEmisorCtaBen', + 'CtaBeneficiario', + 'TipoCadPago', + 'CertPago', + 'CadPago', + 'SelloPago', + ) + attr = self._fields_to_dict(fields, data) + self._cfdi['complementos']['pagos']['pago'] = attr elif self._complement == '2': fields = ( 'Curp', @@ -723,12 +800,23 @@ class DataToDict(): self._cfdi['complementos']['comercio']['emisor'] = attr return + def _get_retenciones_by_pay(self, data): + retenciones = [] + for i in range(0, len(data), 2): + tax = { + 'ImpuestoP': data[i], + 'ImporteP': data[i + 1], + } + retenciones.append(tax) + return retenciones + def _complemento_14(self, data): if not data: return if self._complement == '1': - pass + attr = self._get_retenciones_by_pay(data) + self._cfdi['complementos']['pagos']['taxes']['retenciones'] = attr elif self._complement == '2': fields = ('NumRegIdTrib', 'ResidenciaFiscal') attr = self._fields_to_dict(fields, data) @@ -736,12 +824,26 @@ class DataToDict(): self._cfdi['complementos']['comercio']['propietario'] = attr return + def _get_traslados_by_pay(self, data): + traslados = [] + for i in range(0, len(data), 5): + tax = { + 'BaseP': data[i], + 'ImpuestoP': data[i + 1], + 'TipoFactorP': data[i + 2], + 'TasaOCuotaP': data[i + 3], + 'ImporteP': data[i + 4], + } + traslados.append(tax) + return traslados + def _complemento_15(self, data): if not data: return if self._complement == '1': - pass + attr = self._get_traslados_by_pay(data) + self._cfdi['complementos']['pagos']['taxes']['traslados'] = attr elif self._complement == '2': fields = ( 'NumRegIdTrib', @@ -765,7 +867,20 @@ class DataToDict(): return if self._complement == '1': - pass + fields = ( + 'IdDocumento', + 'Serie', + 'Folio', + 'MonedaDR', + 'EquivalenciaDR', + 'NumParcialidad', + 'ImpSaldoAnt', + 'ImpPagado', + 'ImpSaldoInsoluto', + 'ObjetoImpDR', + ) + attr = self._fields_to_dict(fields, data) + self._cfdi['complementos']['pagos']['docs'].append(attr) elif self._complement == '2': fields = ( 'NumRegIdTrib', @@ -785,12 +900,38 @@ class DataToDict(): self._cfdi['complementos']['comercio']['destinatario'] = attr return + def _get_taxes_by_doc(self, data): + taxes = {} + traslados = [] + retenciones = [] + for i in range(0, len(data), 6): + type_tax = data[i] + tax = { + 'BaseDR': data[i + 1], + 'ImpuestoDR': data[i + 2], + 'TipoFactorDR': data[i + 3], + 'TasaOCuotaDR': data[i + 4], + 'ImporteDR': data[i + 5], + } + if type_tax == self.TRASLADO: + traslados.append(tax) + elif type_tax == self.RETENCION: + retenciones.append(tax) + + if traslados: + taxes['traslados'] = traslados + if retenciones: + taxes['retenciones'] = retenciones + + return taxes + def _complemento_17(self, data): if not data: return if self._complement == '1': - pass + attr = self._get_taxes_by_doc(data) + self._cfdi['complementos']['pagos']['taxesd'] = attr elif self._complement == '2': fields = ( 'NoIdentificacion',