From 8118ac306c9ac3c7ad630b55e891a4a059f1069f Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Thu, 1 Feb 2018 19:54:54 -0600 Subject: [PATCH 1/2] Actualizar gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3dc9bc1..0d1fdb6 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,6 @@ credenciales.conf *.sqlite *.sql *.service +*.orig rfc.db From acb3d3f40c19b121301adc7328ad70ddefb8c162 Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Fri, 2 Feb 2018 13:46:15 -0600 Subject: [PATCH 2/2] Fix Issue #170 --- source/app/controllers/util.py | 51 +++++++++++++++++++++++-- source/app/models/main.py | 51 +++++++++++++++++++++++-- source/static/js/controller/admin.js | 39 +++++++++++++++++++ source/static/js/controller/invoices.js | 1 - source/static/js/controller/nomina.js | 4 +- source/static/js/ui/admin.js | 5 +++ 6 files changed, 140 insertions(+), 11 deletions(-) diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py index 7d757de..99ca028 100644 --- a/source/app/controllers/util.py +++ b/source/app/controllers/util.py @@ -936,6 +936,10 @@ class LIBO(object): self._set_cell('{ine.%s}' % k, v) return + def _nomina(self, data): + print(data) + return + def _render(self, data): self._set_search() self._es_pre = data.pop('es_pre', False) @@ -944,7 +948,10 @@ class LIBO(object): self._emisor(data['emisor']) self._receptor(data['receptor']) self._conceptos(data['conceptos']) - self._totales(data['totales']) + if 'nomina' in data and data['nomina']: + self._nomina(data['nomina']) + else: + self._totales(data['totales']) self._timbre(data['timbre']) self._donataria(data['donataria']) self._ine(data['ine']) @@ -1200,6 +1207,8 @@ def to_pdf(data, emisor_rfc, ods=False): if DEBUG: rfc = emisor_rfc version = data['comprobante']['version'] + if 'nomina' in data and data['nomina']: + version = '{}_{}'.format(data['nomina']['version'], version) if APP_LIBO: app = LIBO() @@ -1288,6 +1297,11 @@ def _comprobante(doc, options): serie = '{} -'.format(data['serie']) data['seriefolio'] = '{}{}'.format(serie, data['folio']) data['totalenletras'] = to_letters(float(data['total']), data['moneda']) + + is_nomina = options.get('is_nomina', False) + if is_nomina: + return data + if data['version'] == '3.3': tipos = { 'I': 'ingreso', @@ -1372,11 +1386,19 @@ def _receptor(doc, version, values): return data -def _conceptos(doc, version): +def _conceptos(doc, version, options): + is_nomina = options.get('is_nomina', False) + data = [] conceptos = doc.find('{}Conceptos'.format(PRE[version])) for c in conceptos.getchildren(): values = CaseInsensitiveDict(c.attrib.copy()) + if is_nomina: + values['noidentificacion'] = values['ClaveProdServ'] + values['unidad'] = values['ClaveUnidad'] + data.append(values) + continue + if version == '3.3': values['noidentificacion'] = '{}\n(SAT {})'.format( values['noidentificacion'], values['ClaveProdServ']) @@ -1519,14 +1541,24 @@ def _ine(doc, version): return data +def _nomina(invoice, values): + is_nomina = values.get('is_nomina', False) + if not is_nomina: + return {} + + return {'version': '1.2'} + + def get_data_from_xml(invoice, values): - data = {'cancelada': invoice.cancelada, 'donativo': invoice.donativo} + data = {'cancelada': invoice.cancelada, 'donativo': False} + if hasattr('invoice', 'donativo'): + data['donativo'] = invoice.donativo doc = parse_xml(invoice.xml) data['comprobante'] = _comprobante(doc, values) version = data['comprobante']['version'] data['emisor'] = _emisor(doc, version, values) data['receptor'] = _receptor(doc, version, values) - data['conceptos'] = _conceptos(doc, version) + data['conceptos'] = _conceptos(doc, version, values) data['totales'] = _totales(doc, data['comprobante'], version) data['donataria'] = _donataria(doc, version, values['fechadof']) data['ine'] = _ine(doc, version) @@ -1540,6 +1572,8 @@ def get_data_from_xml(invoice, values): del data['timbre']['version'] data['comprobante'].update(data['timbre']) + data['nomina'] = _nomina(invoice, values) + return data @@ -1655,6 +1689,15 @@ def upload_file(rfc, opt, file_obj): name = '{}_3.3_donativo.ods'.format(rfc.lower()) path = _join(PATH_MEDIA, 'templates', name) + elif opt == 'txt_plantilla_nomina1233': + tmp = file_obj.filename.split('.') + ext = tmp[-1].lower() + if ext != 'ods': + msg = 'Extensión de archivo incorrecta, selecciona un archivo ODS' + return {'status': 'server', 'name': msg, 'ok': False} + + name = '{}_1.2_3.3.ods'.format(rfc.lower()) + path = _join(PATH_MEDIA, 'templates', name) elif opt == 'bdfl': tmp = file_obj.filename.split('.') ext = tmp[-1].lower() diff --git a/source/app/models/main.py b/source/app/models/main.py index 6ad3cf1..fa2a0bb 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -186,10 +186,12 @@ def get_doc(type_doc, id, rfc): data, file_name = PreFacturas.get_pdf(id) elif type_doc == 'tpdf': data, file_name = Tickets.get_pdf(id) - elif type_doc == 'xmlnom': + elif type_doc == 'nomxml': data, file_name = CfdiNomina.get_xml(id) elif type_doc == 'nomlog': data, file_name = util.get_log('nomina') + elif type_doc == 'nompdf': + data, file_name = CfdiNomina.get_pdf(id, rfc) return data, file_name, content_type @@ -3595,10 +3597,12 @@ class Facturas(BaseModel): for tax in p.impuestos: if tax_locales and tax.tipo == 'R' and tax.key == '000': base = product['importe'] + if tax_decimals: impuesto_producto = round(float(tax.tasa) * base, DECIMALES_TAX) else: impuesto_producto = round(float(tax.tasa) * base, DECIMALES) + if tax.tipo == 'T' and tax.key != '000': total_trasladados = (total_trasladados or 0) + impuesto_producto elif tax.tipo == 'R' and tax.key != '000': @@ -3814,14 +3818,17 @@ class Facturas(BaseModel): if impuesto.key == '000': continue - base = row.importe - row.descuento + base = float(row.importe - row.descuento) + tasa = float(impuesto.tasa) + if tax_decimals: - import_tax = round(impuesto.tasa * base, DECIMALES_TAX) + import_tax = round(tasa * base, DECIMALES_TAX) tmp += import_tax xml_importe = FORMAT_TAX.format(import_tax) else: - import_tax = round(impuesto.tasa * base, DECIMALES) + import_tax = round(tasa * base, DECIMALES) xml_importe = FORMAT.format(import_tax) + tipo_factor = 'Tasa' if impuesto.factor != 'T': tipo_factor = 'Cuota' @@ -4366,10 +4373,12 @@ class PreFacturas(BaseModel): for tax in p.impuestos: if tax_locales and tax.tipo == 'R' and tax.key == '000': base = product['importe'] + if tax_decimals: impuesto_producto = round(float(tax.tasa) * base, DECIMALES_TAX) else: impuesto_producto = round(float(tax.tasa) * base, DECIMALES) + if tax.tipo == 'T' and tax.key != '000': total_trasladados = (total_trasladados or 0) + impuesto_producto elif tax.tipo == 'R' and tax.key != '000': @@ -6404,6 +6413,40 @@ class CfdiNomina(BaseModel): # ~ cls._sync_xml(cls, obj) return obj.xml, name + def _get_not_in_xml(self, invoice, emisor): + values = {'is_nomina': True} + + if invoice.version == '3.2': + return values + + values['regimenfiscal'] = invoice.regimen_fiscal + values['usocfdi'] = invoice.uso_cfdi + values['receptor'] = {} + values['fechadof'] = None + + return values + + @classmethod + def get_pdf(cls, id, rfc, sync=True): + try: + emisor = Emisor.select()[0] + except IndexError: + return b'', 'sin_datos_de_emisor.pdf' + + obj = CfdiNomina.get(CfdiNomina.id==id) + name = '{}{}_{}.pdf'.format(obj.serie, obj.folio, obj.empleado.rfc) + if obj.uuid is None: + return b'', name + + values = cls._get_not_in_xml(cls, obj, emisor) + data = util.get_data_from_xml(obj, values) + doc = util.to_pdf(data, emisor.rfc) + + # ~ if sync: + # ~ target = emisor.rfc + '/' + str(obj.fecha)[:7].replace('-', '/') + # ~ cls._sync_pdf(cls, doc, name, target) + return doc, name + @classmethod def filter_years(cls): data = [{'id': -1, 'value': 'Todos'}] diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js index 6fe960a..f1a8270 100644 --- a/source/static/js/controller/admin.js +++ b/source/static/js/controller/admin.js @@ -54,6 +54,7 @@ var controllers = { $$('txt_plantilla_factura_33j').attachEvent('onItemClick', txt_plantilla_factura_33j_click) $$('txt_plantilla_ticket').attachEvent('onItemClick', txt_plantilla_ticket_click) $$('txt_plantilla_donataria').attachEvent('onItemClick', txt_plantilla_donataria_click) + $$('txt_plantilla_nomina1233').attachEvent('onItemClick', txt_plantilla_nomina1233_click) $$('chk_config_ocultar_metodo_pago').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_ocultar_condiciones_pago').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_send_zip').attachEvent('onItemClick', chk_config_item_click) @@ -1020,6 +1021,44 @@ function txt_plantilla_donataria_click(e){ } +function txt_plantilla_nomina1233_click(e){ + + var body_elements = [ + {cols: [{width: 100}, {view: 'uploader', id: 'up_template', + autosend: true, link: 'lst_files', value: 'Seleccionar archivo', + upload: '/files/txt_plantilla_nomina1233', width: 200}, {width: 100}]}, + {view: 'list', id: 'lst_files', type: 'uploader', autoheight:true, + borderless: true}, + {}, + {cols: [{}, {view: 'button', label: 'Cerrar', autowidth: true, + click:("$$('win_template').close();")}, {}]} + ] + + var w = webix.ui({ + view: 'window', + id: 'win_template', + modal: true, + position: 'center', + head: 'Subir Plantilla Nómina', + body: { + view: 'form', + elements: body_elements, + } + }) + + w.show() + + $$('up_template').attachEvent('onUploadComplete', function(response){ + if(response.ok){ + $$('txt_plantilla_nomina1233').setValue(response.name) + msg_ok('Plantilla cargada correctamente') + }else{ + msg_error(response.name) + } + }) +} + + function tab_options_change(nv, ov){ var cv = { tab_admin_templates: 'templates', diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index ed97e97..5b81709 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -829,7 +829,6 @@ function calcular_impuestos(){ }else{ impuesto_producto = (impuesto.tasa * base).round(DECIMALES) } - tmp = table_totals.findOne({'tax': tax.tax}) if(tmp === null){ table_totals.insert({'tax': tax.tax, 'importe': impuesto_producto}) diff --git a/source/static/js/controller/nomina.js b/source/static/js/controller/nomina.js index a80a3cb..d5305bb 100644 --- a/source/static/js/controller/nomina.js +++ b/source/static/js/controller/nomina.js @@ -392,9 +392,9 @@ function grid_nomina_click(id, e, node){ var row = this.getItem(id) if(id.column == 'xml'){ - location = '/doc/xmlnom/' + row.id + location = '/doc/nomxml/' + row.id }else if(id.column == 'pdf'){ - //~ get_momina_pdf(row.id) + window.open('/doc/nompdf/' + row.id, '_blank') //~ }else if(id.column == 'email'){ //~ enviar_correo(row) } diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js index 36ba071..3dbd7f9 100644 --- a/source/static/js/ui/admin.js +++ b/source/static/js/ui/admin.js @@ -569,6 +569,11 @@ var options_templates = [ icon: 'file'}, {}]}, {maxHeight: 20}, + {cols: [{maxWidth: 15}, + {view: 'search', id: 'txt_plantilla_nomina1233', name: 'plantilla_nomina1233', + label: 'Plantilla Nomina v1.2 - Cfdi 3.3 (ODS): ', labelPosition: 'top', + icon: 'file'}, {}]}, + {maxHeight: 20}, {}]