forked from elmau/empresa-libre
Generate PDF from cfdi pay
This commit is contained in:
parent
9dc2c72de7
commit
fd75da65fc
|
@ -320,6 +320,9 @@ def get_template_ods(name, default='plantilla_factura.ods'):
|
||||||
if is_file(path):
|
if is_file(path):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
if 'pagos' in name:
|
||||||
|
default='plantilla_pagos.ods'
|
||||||
|
|
||||||
path = _join(PATH_TEMPLATES, default)
|
path = _join(PATH_TEMPLATES, default)
|
||||||
if is_file(path):
|
if is_file(path):
|
||||||
return path
|
return path
|
||||||
|
@ -954,6 +957,9 @@ class LIBO(object):
|
||||||
|
|
||||||
self._set_cell('{total_cantidades}', str(self._total_cantidades))
|
self._set_cell('{total_cantidades}', str(self._total_cantidades))
|
||||||
|
|
||||||
|
if self._pagos:
|
||||||
|
return
|
||||||
|
|
||||||
cell_title = self._set_cell('{subtotal.titulo}', 'SubTotal')
|
cell_title = self._set_cell('{subtotal.titulo}', 'SubTotal')
|
||||||
value = data['subtotal']
|
value = data['subtotal']
|
||||||
cell_value = self._set_cell('{subtotal}', value, value=True)
|
cell_value = self._set_cell('{subtotal}', value, value=True)
|
||||||
|
@ -1150,16 +1156,114 @@ class LIBO(object):
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _cfdipays(self, data):
|
||||||
|
related = data.pop('related', [])
|
||||||
|
for k, v in data.items():
|
||||||
|
if k.lower() in ('monto',):
|
||||||
|
self._set_cell('{pago.%s}' % k, v, value=True)
|
||||||
|
else:
|
||||||
|
self._set_cell('{pago.%s}' % k, v)
|
||||||
|
|
||||||
|
col1 = []
|
||||||
|
col2 = []
|
||||||
|
col3 = []
|
||||||
|
col4 = []
|
||||||
|
col5 = []
|
||||||
|
col6 = []
|
||||||
|
col7 = []
|
||||||
|
col8 = []
|
||||||
|
col9 = []
|
||||||
|
count = len(related)
|
||||||
|
for i, doc in enumerate(related):
|
||||||
|
uuid = doc['IdDocumento'].upper()
|
||||||
|
serie = doc['Serie']
|
||||||
|
folio = doc['Folio']
|
||||||
|
metodo_pago = doc['MetodoDePagoDR']
|
||||||
|
moneda = doc['MonedaDR']
|
||||||
|
parcialidad = doc['NumParcialidad']
|
||||||
|
saldo_anterior = doc['ImpSaldoAnt']
|
||||||
|
importe_pagado = doc['ImpPagado']
|
||||||
|
saldo_insoluto = doc['ImpSaldoInsoluto']
|
||||||
|
if i == 0:
|
||||||
|
cell_1 = self._set_cell('{doc.uuid}', uuid)
|
||||||
|
cell_2 = self._set_cell('{doc.serie}', serie)
|
||||||
|
cell_3 = self._set_cell('{doc.folio}', folio)
|
||||||
|
cell_4 = self._set_cell('{doc.metodopago}', metodo_pago)
|
||||||
|
cell_5 = self._set_cell('{doc.moneda}', moneda)
|
||||||
|
cell_6 = self._set_cell('{doc.parcialidad}', parcialidad)
|
||||||
|
cell_7 = self._set_cell('{doc.saldoanterior}', saldo_anterior, value=True)
|
||||||
|
cell_8 = self._set_cell('{doc.importepagado}', importe_pagado, value=True)
|
||||||
|
cell_9 = self._set_cell('{doc.saldoinsoluto}', saldo_insoluto, value=True)
|
||||||
|
else:
|
||||||
|
col1.append((uuid,))
|
||||||
|
col2.append((serie,))
|
||||||
|
col3.append((folio,))
|
||||||
|
col4.append((metodo_pago,))
|
||||||
|
col5.append((moneda,))
|
||||||
|
col6.append((parcialidad,))
|
||||||
|
col7.append((float(saldo_anterior),))
|
||||||
|
col8.append((float(importe_pagado),))
|
||||||
|
col9.append((float(saldo_insoluto),))
|
||||||
|
|
||||||
|
if count == 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
count -= 1
|
||||||
|
row1 = cell_1.getCellAddress().Row + 1
|
||||||
|
row2 = row1 + count - 1
|
||||||
|
self._sheet.getRows().insertByIndex(row1, count)
|
||||||
|
self._copy_paste_rows(cell_1, count)
|
||||||
|
|
||||||
|
# ~ style_7 = self._get_style(cell_7)
|
||||||
|
# ~ style_8 = self._get_style(cell_8)
|
||||||
|
# ~ style_9 = self._get_style(cell_9)
|
||||||
|
|
||||||
|
col = cell_1.getCellAddress().Column
|
||||||
|
target1 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
col = cell_2.getCellAddress().Column
|
||||||
|
target2 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
col = cell_3.getCellAddress().Column
|
||||||
|
target3 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
col = cell_4.getCellAddress().Column
|
||||||
|
target4 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
col = cell_5.getCellAddress().Column
|
||||||
|
target5 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
col = cell_6.getCellAddress().Column
|
||||||
|
target6 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
col = cell_7.getCellAddress().Column
|
||||||
|
target7 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
col = cell_8.getCellAddress().Column
|
||||||
|
target8 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
col = cell_9.getCellAddress().Column
|
||||||
|
target9 = self._sheet.getCellRangeByPosition(col, row1, col, row2)
|
||||||
|
|
||||||
|
target1.setFormulaArray(tuple(col1))
|
||||||
|
target2.setDataArray(tuple(col2))
|
||||||
|
target3.setFormulaArray(tuple(col3))
|
||||||
|
target4.setDataArray(tuple(col4))
|
||||||
|
target5.setDataArray(tuple(col5))
|
||||||
|
target6.setDataArray(tuple(col6))
|
||||||
|
target7.setDataArray(tuple(col7))
|
||||||
|
target8.setDataArray(tuple(col8))
|
||||||
|
target9.setDataArray(tuple(col9))
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
def _render(self, data):
|
def _render(self, data):
|
||||||
self._set_search()
|
self._set_search()
|
||||||
self._es_pre = data.pop('es_pre', False)
|
self._es_pre = data.pop('es_pre', False)
|
||||||
self._is_ticket = data.pop('is_ticket', False)
|
self._is_ticket = data.pop('is_ticket', False)
|
||||||
self._currency = data['totales']['moneda']
|
self._currency = data['totales']['moneda']
|
||||||
|
self._pagos = data.pop('pagos', False)
|
||||||
|
|
||||||
self._comprobante(data['comprobante'])
|
self._comprobante(data['comprobante'])
|
||||||
self._emisor(data['emisor'])
|
self._emisor(data['emisor'])
|
||||||
self._receptor(data['receptor'])
|
self._receptor(data['receptor'])
|
||||||
self._conceptos(data['conceptos'])
|
self._conceptos(data['conceptos'])
|
||||||
|
|
||||||
|
if self._pagos:
|
||||||
|
self._cfdipays(data['pays'])
|
||||||
|
|
||||||
if 'nomina' in data and data['nomina']:
|
if 'nomina' in data and data['nomina']:
|
||||||
self._nomina(data['nomina'])
|
self._nomina(data['nomina'])
|
||||||
else:
|
else:
|
||||||
|
@ -1167,6 +1271,7 @@ class LIBO(object):
|
||||||
self._timbre(data['timbre'])
|
self._timbre(data['timbre'])
|
||||||
self._donataria(data['donataria'])
|
self._donataria(data['donataria'])
|
||||||
self._ine(data['ine'])
|
self._ine(data['ine'])
|
||||||
|
|
||||||
self._cancelado(data['cancelada'])
|
self._cancelado(data['cancelada'])
|
||||||
self._clean()
|
self._clean()
|
||||||
return
|
return
|
||||||
|
@ -1444,13 +1549,17 @@ def to_pdf(data, emisor_rfc, ods=False):
|
||||||
if 'nomina' in data and data['nomina']:
|
if 'nomina' in data and data['nomina']:
|
||||||
version = '{}_{}'.format(data['nomina']['version'], version)
|
version = '{}_{}'.format(data['nomina']['version'], version)
|
||||||
|
|
||||||
|
pagos = ''
|
||||||
|
if data.get('pagos', False):
|
||||||
|
pagos = '_pagos_'
|
||||||
|
|
||||||
if APP_LIBO:
|
if APP_LIBO:
|
||||||
app = LIBO()
|
app = LIBO()
|
||||||
if app.is_running:
|
if app.is_running:
|
||||||
donativo = ''
|
donativo = ''
|
||||||
if data['donativo']:
|
if data['donativo']:
|
||||||
donativo = '_donativo'
|
donativo = '_donativo'
|
||||||
name = '{}_{}{}.ods'.format(rfc.lower(), version, donativo)
|
name = '{}_{}{}{}.ods'.format(rfc.lower(), pagos, version, donativo)
|
||||||
path = get_template_ods(name)
|
path = get_template_ods(name)
|
||||||
if path:
|
if path:
|
||||||
return app.pdf(path, data, ods)
|
return app.pdf(path, data, ods)
|
||||||
|
@ -1553,6 +1662,7 @@ def _comprobante(doc, options):
|
||||||
'I': 'ingreso',
|
'I': 'ingreso',
|
||||||
'E': 'egreso',
|
'E': 'egreso',
|
||||||
'T': 'traslado',
|
'T': 'traslado',
|
||||||
|
'P': 'pago',
|
||||||
}
|
}
|
||||||
data['tipodecomprobante'] = tipos.get(data['tipodecomprobante'])
|
data['tipodecomprobante'] = tipos.get(data['tipodecomprobante'])
|
||||||
data['lugarexpedicion'] = \
|
data['lugarexpedicion'] = \
|
||||||
|
@ -1854,6 +1964,27 @@ def _nomina(doc, data, values, version_cfdi):
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def _cfdipays(doc, data, version):
|
||||||
|
node = doc.find('{}Complemento/{}Pagos'.format(PRE[version], PRE['pagos']))
|
||||||
|
if node is None:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
info = CaseInsensitiveDict(node.attrib.copy())
|
||||||
|
related = []
|
||||||
|
for n1 in node:
|
||||||
|
info.update(CaseInsensitiveDict(n1.attrib.copy()))
|
||||||
|
for n2 in n1:
|
||||||
|
related.append(CaseInsensitiveDict(n2.attrib.copy()))
|
||||||
|
|
||||||
|
info['related'] = related
|
||||||
|
|
||||||
|
data['comprobante']['totalenletras'] = to_letters(
|
||||||
|
float(info['monto']), info['monedap'])
|
||||||
|
data['comprobante']['moneda'] = info['monedap']
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
def get_data_from_xml(invoice, values):
|
def get_data_from_xml(invoice, values):
|
||||||
data = {'cancelada': invoice.cancelada, 'donativo': False}
|
data = {'cancelada': invoice.cancelada, 'donativo': False}
|
||||||
if hasattr(invoice, 'donativo'):
|
if hasattr(invoice, 'donativo'):
|
||||||
|
@ -1878,6 +2009,9 @@ def get_data_from_xml(invoice, values):
|
||||||
data['comprobante'].update(data['timbre'])
|
data['comprobante'].update(data['timbre'])
|
||||||
|
|
||||||
data['nomina'] = _nomina(doc, data, values, version)
|
data['nomina'] = _nomina(doc, data, values, version)
|
||||||
|
data['pagos'] = values.get('pagos', False)
|
||||||
|
if data['pagos']:
|
||||||
|
data['pays'] = _cfdipays(doc, data, version)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
|
@ -5364,7 +5364,7 @@ class CfdiPagos(BaseModel):
|
||||||
Facturas.folio.alias('Folio'),
|
Facturas.folio.alias('Folio'),
|
||||||
Facturas.moneda.alias('MonedaDR'),
|
Facturas.moneda.alias('MonedaDR'),
|
||||||
# ~ Facturas.tipo_cambio.alias('TipoCambioDR'),
|
# ~ Facturas.tipo_cambio.alias('TipoCambioDR'),
|
||||||
Facturas.metodo_pago.alias('MetodoDePagoDR'),
|
# ~ Facturas.metodo_pago.alias('MetodoDePagoDR'),
|
||||||
FacturasPagos.numero.alias('NumParcialidad'),
|
FacturasPagos.numero.alias('NumParcialidad'),
|
||||||
FacturasPagos.saldo_anterior.alias('ImpSaldoAnt'),
|
FacturasPagos.saldo_anterior.alias('ImpSaldoAnt'),
|
||||||
FacturasPagos.importe.alias('ImpPagado'),
|
FacturasPagos.importe.alias('ImpPagado'),
|
||||||
|
@ -5379,6 +5379,7 @@ class CfdiPagos(BaseModel):
|
||||||
r['Folio'] = str(r['Folio'])
|
r['Folio'] = str(r['Folio'])
|
||||||
r['NumParcialidad'] = str(r['NumParcialidad'])
|
r['NumParcialidad'] = str(r['NumParcialidad'])
|
||||||
# ~ r['TipoCambioDR'] = FORMAT.format(r['TipoCambioDR'])
|
# ~ r['TipoCambioDR'] = FORMAT.format(r['TipoCambioDR'])
|
||||||
|
r['MetodoDePagoDR'] = 'PDD'
|
||||||
r['ImpSaldoAnt'] = FORMAT.format(r['ImpSaldoAnt'])
|
r['ImpSaldoAnt'] = FORMAT.format(r['ImpSaldoAnt'])
|
||||||
r['ImpPagado'] = FORMAT.format(r['ImpPagado'])
|
r['ImpPagado'] = FORMAT.format(r['ImpPagado'])
|
||||||
r['ImpSaldoInsoluto'] = FORMAT.format(r['ImpSaldoInsoluto'])
|
r['ImpSaldoInsoluto'] = FORMAT.format(r['ImpSaldoInsoluto'])
|
||||||
|
@ -5523,6 +5524,32 @@ class CfdiPagos(BaseModel):
|
||||||
name = '{}{}_{}.xml'.format(obj.serie, folio, obj.socio.rfc)
|
name = '{}{}_{}.xml'.format(obj.serie, folio, obj.socio.rfc)
|
||||||
return obj.xml, name
|
return obj.xml, name
|
||||||
|
|
||||||
|
def _get_not_in_xml(self, invoice, emisor):
|
||||||
|
values = {}
|
||||||
|
|
||||||
|
values['notas'] = invoice.notas
|
||||||
|
values['fechadof'] = None
|
||||||
|
|
||||||
|
obj = SATRegimenes.get(SATRegimenes.key==invoice.regimen_fiscal)
|
||||||
|
values['regimenfiscal'] = str(obj)
|
||||||
|
|
||||||
|
obj = SATUsoCfdi.get(SATUsoCfdi.key=='P01')
|
||||||
|
values['usocfdi'] = str(obj)
|
||||||
|
|
||||||
|
values['moneda'] = 'XXX'
|
||||||
|
|
||||||
|
if invoice.tipo_relacion:
|
||||||
|
obj = SATTipoRelacion.get(SATTipoRelacion.key==invoice.tipo_relacion)
|
||||||
|
values['tiporelacion'] = str(obj)
|
||||||
|
|
||||||
|
receptor = Socios.select().where(Socios.id==invoice.socio.id).dicts()[0]
|
||||||
|
values['receptor'] = {}
|
||||||
|
for k, v in receptor.items():
|
||||||
|
values['receptor'][k] = v
|
||||||
|
|
||||||
|
values['pagos'] = True
|
||||||
|
return values
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_file_pdf(cls, id):
|
def get_file_pdf(cls, id):
|
||||||
try:
|
try:
|
||||||
|
@ -5537,12 +5564,13 @@ class CfdiPagos(BaseModel):
|
||||||
if obj.uuid is None:
|
if obj.uuid is None:
|
||||||
return b'', name
|
return b'', name
|
||||||
|
|
||||||
# ~ values = cls._get_not_in_xml(cls, obj, emisor)
|
values = cls._get_not_in_xml(cls, obj, emisor)
|
||||||
data = util.get_data_from_xml(obj, {})
|
data = util.get_data_from_xml(obj, values)
|
||||||
print(data)
|
obj = SATFormaPago.get(SATFormaPago.key==data['pays']['FormaDePagoP'])
|
||||||
# ~ doc = util.to_pdf(data, emisor.rfc)
|
data['pays']['formadepago'] = '{} ({})'.format(obj.name, obj.key)
|
||||||
|
doc = util.to_pdf(data, emisor.rfc)
|
||||||
|
|
||||||
return b'', name
|
return doc, name
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_values(cls, values):
|
def get_values(cls, values):
|
||||||
|
|
|
@ -132,7 +132,8 @@ PRE = {
|
||||||
'NOMINA': {
|
'NOMINA': {
|
||||||
'1.1': '{http://www.sat.gob.mx/nomina}',
|
'1.1': '{http://www.sat.gob.mx/nomina}',
|
||||||
'1.2': '{http://www.sat.gob.mx/nomina12}',
|
'1.2': '{http://www.sat.gob.mx/nomina12}',
|
||||||
}
|
},
|
||||||
|
'pagos': '{http://www.sat.gob.mx/Pagos}',
|
||||||
}
|
}
|
||||||
|
|
||||||
CURRENT_CFDI = '3.3'
|
CURRENT_CFDI = '3.3'
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue