diff --git a/source/app/controllers/main.py b/source/app/controllers/main.py index d9ac7ee..ac74730 100644 --- a/source/app/controllers/main.py +++ b/source/app/controllers/main.py @@ -385,13 +385,13 @@ class AppDocumentos(object): def __init__(self, db): self._db = db - #~ self._not_json = True def on_get(self, req, resp, type_doc, id_doc): session = req.env['beaker.session'] req.context['result'], file_name, content_type = \ self._db.get_doc(type_doc, id_doc, session['rfc']) - # ~ resp.append_header('Content-Disposition', - # ~ 'attachment; filename={}'.format(file_name)) + if not type_doc in ('pdf', 'pre', 'tpdf'): + resp.append_header('Content-Disposition', + 'attachment; filename={}'.format(file_name)) resp.content_type = content_type resp.status = falcon.HTTP_200 diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py index 8f83bca..1404dd9 100644 --- a/source/app/controllers/util.py +++ b/source/app/controllers/util.py @@ -269,7 +269,7 @@ def get_size(path): def get_template(name, data={}): - #~ print ('NAME', name, data) + # ~ print ('NAME', name) template = template_lookup.get_template(name) return template.render(**data) @@ -774,18 +774,30 @@ class LIBO(object): cell_6 = self._set_cell(v=importe, cell=cell_6, value=True) return + def _add_totales(self, data): + currency = data['moneda'] + value = data['total'] + cell_value = self._set_cell('{total}', value, value=True) + if cell_value is None: + return False + + cell_value.CellStyle = currency + + return True + def _totales(self, data): currency = data['moneda'] cell_title = self._set_cell('{subtotal.titulo}', 'SubTotal') value = data['subtotal'] cell_value = self._set_cell('{subtotal}', value, value=True) - cell_value.CellStyle = currency + if not cell_value is None: + cell_value.CellStyle = currency #~ Si encuentra el campo {total}, se asume que los totales e impuestos #~ están declarados de forma independiente cada uno - #~ if self._add_totales(xml): - #~ return + if self._add_totales(data): + return #~ Si no se encuentra, copia las celdas hacia abajo de #~ {subtotal.titulo} y {subtotal} @@ -828,7 +840,7 @@ class LIBO(object): return def _timbre(self, data): - if self._es_pre: + if self._es_pre or self._is_ticket: return for k, v in data.items(): @@ -863,6 +875,7 @@ class LIBO(object): def _render(self, data): self._set_search() self._es_pre = data.pop('es_pre', False) + self._is_ticket = data.pop('is_ticket', False) self._comprobante(data['comprobante']) self._emisor(data['emisor']) self._receptor(data['receptor']) @@ -910,6 +923,7 @@ def to_pdf(data, emisor_rfc): if data['donativo']: donativo = '_donativo' name = '{}_{}{}.ods'.format(rfc.lower(), version, donativo) + print (name) path = get_template_ods(name) if path: return app.pdf(path, data) diff --git a/source/app/models/db.py b/source/app/models/db.py index 7a48236..7ec35a0 100644 --- a/source/app/models/db.py +++ b/source/app/models/db.py @@ -31,6 +31,9 @@ class StorageEngine(object): def _get_configtimbrar(self, values): return main.config_timbrar() + def _get_configticket(self, values): + return main.config_ticket() + def _get_saldocuenta(self, values): return main.CuentasBanco.get_saldo(values['id']) @@ -303,20 +306,7 @@ class StorageEngine(object): return main.Folios.add(values) def get_doc(self, type_doc, id, rfc): - if type_doc == 'xml': - data, file_name = main.Facturas.get_xml(id) - content_type = 'application/xml' - elif type_doc == 'pdf': - data, file_name = main.Facturas.get_pdf(id, rfc) - content_type = 'application/pdf' - elif type_doc == 'zip': - data, file_name = main.Facturas.get_zip(id, rfc) - content_type = 'application/octet-stream' - elif type_doc == 'pdf2': - data, file_name = main.PreFacturas.get_pdf(id) - content_type = 'application/pdf' - - return data, file_name, content_type + return main.get_doc(type_doc, id, rfc) def get_movimientosbanco(self, values): return main.MovimientosBanco.get_(values) diff --git a/source/app/models/main.py b/source/app/models/main.py index cb1eec8..77618d5 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -104,6 +104,26 @@ def validar_timbrar(): return {'ok': True, 'msg': msg} +def get_doc(type_doc, id, rfc): + types = { + 'xml': 'application/xml', + 'zip': 'application/octet-stream', + } + content_type = types.get(type_doc, 'application/pdf') + if type_doc == 'xml': + data, file_name = Facturas.get_xml(id) + elif type_doc == 'pdf': + data, file_name = Facturas.get_pdf(id, rfc) + elif type_doc == 'zip': + data, file_name = Facturas.get_zip(id, rfc) + elif type_doc == 'pre': + data, file_name = PreFacturas.get_pdf(id) + elif type_doc == 'tpdf': + data, file_name = Tickets.get_pdf(id) + + return data, file_name, content_type + + def config_main(): try: obj = Emisor.select()[0] @@ -141,6 +161,13 @@ def config_timbrar(): return conf +def config_ticket(): + conf = { + 'open_pdf': Configuracion.get_bool('chk_ticket_pdf_show'), + } + return conf + + class Configuracion(BaseModel): clave = TextField(unique=True) valor = TextField(default='') @@ -221,7 +248,9 @@ class Configuracion(BaseModel): 'chk_config_codigo_barras', 'chk_config_precio_con_impuestos', 'chk_config_ine', + 'chk_config_edu', 'chk_usar_punto_de_venta', + 'chk_ticket_pdf_show', ) data = (Configuracion .select() @@ -3261,6 +3290,7 @@ class PreFacturas(BaseModel): options = { 'para': obj.cliente.correo_facturas, 'copia': values['correo_copia'], + 'confirmar': util.get_bool(values.get('correo_confirmacion', '0')), 'asunto': asunto, 'mensaje': util.make_info_mail(values['correo_mensaje'], fields), 'files': files, @@ -4243,6 +4273,61 @@ class Tickets(BaseModel): data += [{'id': int(r.year), 'value': int(r.year)} for r in rows] return tuple(data) + def _get_info_to_pdf(self, id): + data = {} + obj = Tickets.select().where(Tickets.id==id).dicts()[0] + formapago = SATFormaPago.get(SATFormaPago.key==obj['forma_pago']) + + emisor = util.get_dict(Emisor.select().dicts()[0]) + emisor['nointerior'] = emisor['no_interior'] + emisor['noexterior'] = emisor['no_exterior'] + emisor['codigopostal'] = emisor['codigo_postal'] + + data['is_ticket'] = True + data['cancelada'] = obj['cancelado'] + data['donativo'] = '' + + data['comprobante'] = obj + data['comprobante']['version'] = 'ticket' + data['comprobante']['folio'] = str(data['comprobante']['folio']) + data['comprobante']['seriefolio'] = '{}-{}'.format( + data['comprobante']['serie'], data['comprobante']['folio']) + data['comprobante']['fecha'] = str(data['comprobante']['fecha']) + # ~ data['comprobante']['lugarexpedicion'] = \ + # ~ 'C.P. de Expedición: {}'.format( + # ~ data['comprobante']['lugar_expedicion']) + data['comprobante']['formadepago'] = str(formapago) + data['comprobante']['totalenletras'] = util.to_letters( + data['comprobante']['total'], 'peso') + + data['emisor'] = emisor + data['receptor'] = {'nombre': 'Público en general'} + + data['conceptos'] = TicketsDetalle.get_by_ticket(id) + data['totales'] = {} + data['totales']['total'] = str(data['comprobante']['total']) + data['totales']['subtotal'] = str(data['comprobante']['subtotal']) + data['totales']['moneda'] = 'peso' + data['totales']['traslados'] = () + data['totales']['retenciones'] = () + data['totales']['taxlocales'] = () + data['timbre'] = {} + data['donataria'] = {} + data['ine'] = {} + + # ~ if obj['descuento']: + # ~ data['totales']['descuento'] = float(obj['descuento']) + + return data + + @classmethod + def get_pdf(cls, id): + obj = Tickets.get(Tickets.id==id) + name = '{}{}.pdf'.format(obj.serie, obj.folio) + data = cls._get_info_to_pdf(cls, id) + doc = util.to_pdf(data, data['emisor']['rfc']) + return doc, name + class TicketsDetalle(BaseModel): ticket = ForeignKeyField(Tickets) @@ -4262,6 +4347,35 @@ class TicketsDetalle(BaseModel): class Meta: order_by = ('ticket',) + def _with_tax(self, product): + precio_final = float(product.precio_final) + base = float(product.precio_final) + for tax in product.producto.impuestos: + impuesto_producto = round(float(tax.tasa) * base, DECIMALES) + precio_final += impuesto_producto + + return precio_final + + @classmethod + def get_by_ticket(cls, id): + data = [] + + productos = TicketsDetalle.select().where(TicketsDetalle.ticket==id) + + for p in productos: + producto = {} + producto['noidentificacion'] = p.producto.clave + producto['descripcion'] = p.descripcion + producto['unidad'] = p.producto.unidad.name + producto['cantidad'] = str(p.cantidad) + price_with_tax = cls._with_tax(cls, p) + producto['valorunitario'] = str(price_with_tax) + importe = round(price_with_tax * float(p.cantidad), DECIMALES) + producto['importe'] = str(importe) + data.append(producto) + + return data + class TicketsImpuestos(BaseModel): ticket = ForeignKeyField(Tickets) diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js index 0317ee4..2cfe14c 100644 --- a/source/static/js/controller/admin.js +++ b/source/static/js/controller/admin.js @@ -56,10 +56,12 @@ var controllers = { $$('chk_config_open_pdf').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_anticipo').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click) + $$('chk_config_edu').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_cuenta_predial').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_codigo_barras').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_precio_con_impuestos').attachEvent('onItemClick', chk_config_item_click) $$('chk_usar_punto_de_venta').attachEvent('onItemClick', chk_config_item_click) + $$('chk_ticket_pdf_show').attachEvent('onItemClick', chk_config_item_click) $$('cmd_subir_bdfl').attachEvent('onItemClick', cmd_subir_bdfl_click) $$('up_bdfl').attachEvent('onUploadComplete', up_bdfl_upload_complete) diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index e255483..c24af1d 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -10,6 +10,33 @@ var cfg_invoice = new Object() var invoices_controllers = { init: function(){ + //~ Invoices + $$('cmd_new_invoice').attachEvent("onItemClick", cmd_new_invoice_click) + $$('cmd_refacturar').attachEvent("onItemClick", cmd_refacturar_click) + $$('cmd_delete_invoice').attachEvent("onItemClick", cmd_delete_invoice_click) + $$('cmd_timbrar').attachEvent('onItemClick', cmd_timbrar_click) + $$('cmd_close_invoice').attachEvent('onItemClick', cmd_close_invoice_click) + $$('search_client_id').attachEvent('onKeyPress', search_client_id_key_press) + $$('grid_clients_found').attachEvent('onValueSuggest', grid_clients_found_click) + $$('search_product_id').attachEvent('onKeyPress', search_product_id_key_press) + $$('grid_products_found').attachEvent('onValueSuggest', grid_products_found_click) + $$('grid_details').attachEvent('onItemClick', grid_details_click) + $$('grid_details').attachEvent('onHeaderClick', grid_details_header_click) + $$('grid_details').attachEvent('onBeforeEditStart', grid_details_before_edit_start) + $$('grid_details').attachEvent('onBeforeEditStop', grid_details_before_edit_stop) + $$('cmd_invoice_timbrar').attachEvent('onItemClick', cmd_invoice_timbrar_click) + $$('cmd_invoice_sat').attachEvent('onItemClick', cmd_invoice_sat_click) + $$('cmd_invoice_cancelar').attachEvent('onItemClick', cmd_invoice_cancelar_click) + $$('grid_invoices').attachEvent('onItemClick', grid_invoices_click) + $$('filter_year').attachEvent('onChange', filter_year_change) + $$('filter_month').attachEvent('onChange', filter_month_change) + $$('filter_dates').attachEvent('onChange', filter_dates_change) + $$('cmd_prefactura').attachEvent('onItemClick', cmd_prefactura_click) + $$('cmd_cfdi_relacionados').attachEvent('onItemClick', cmd_cfdi_relacionados_click) + $$('lst_metodo_pago').attachEvent('onChange', lst_metodo_pago_change) + $$('lst_moneda').attachEvent('onChange', lst_moneda_change) + $$('lst_serie').attachEvent('onChange', lst_serie_change) + $$('cmd_cfdi_notes').attachEvent('onItemClick', cmd_cfdi_notes_click) webix.extend($$('grid_invoices'), webix.ProgressBar) @@ -1442,7 +1469,7 @@ function enviar_prefactura(id){ text: msg, callback:function(result){ if(result){ - webix.ajax().post('/values/enviarprefac', {'id': id}, { + webix.ajax().post('/values/enviarprefac', {'id': id.row}, { error:function(text, data, XmlHttpRequest){ msg = 'Ocurrio un error, consulta a soporte técnico' msg_error(msg) @@ -1463,12 +1490,13 @@ function enviar_prefactura(id){ function grid_preinvoices_click(id, e, node){ - var row = this.getItem(id) + //~ var row = this.getItem(id) if(id.column == 'pdf'){ - location = '/doc/pdf2/' + row.id + //~ location = '/doc/pre/' + row.id + window.open('/doc/pre/' + id, '_blank') }else if(id.column == 'email'){ - enviar_prefactura(row.id) + enviar_prefactura(id) } } diff --git a/source/static/js/controller/main.js b/source/static/js/controller/main.js index 9d7fdf9..0e68323 100644 --- a/source/static/js/controller/main.js +++ b/source/static/js/controller/main.js @@ -33,33 +33,6 @@ var controllers = { $$('menu_user').attachEvent('onMenuItemClick', menu_user_click); configuracion_inicial() - //~ Invoices - $$('cmd_new_invoice').attachEvent("onItemClick", cmd_new_invoice_click) - $$('cmd_refacturar').attachEvent("onItemClick", cmd_refacturar_click) - $$('cmd_delete_invoice').attachEvent("onItemClick", cmd_delete_invoice_click) - $$('cmd_timbrar').attachEvent('onItemClick', cmd_timbrar_click) - $$('cmd_close_invoice').attachEvent('onItemClick', cmd_close_invoice_click) - $$('search_client_id').attachEvent('onKeyPress', search_client_id_key_press) - $$('grid_clients_found').attachEvent('onValueSuggest', grid_clients_found_click) - $$('search_product_id').attachEvent('onKeyPress', search_product_id_key_press) - $$('grid_products_found').attachEvent('onValueSuggest', grid_products_found_click) - $$('grid_details').attachEvent('onItemClick', grid_details_click) - $$('grid_details').attachEvent('onHeaderClick', grid_details_header_click) - $$('grid_details').attachEvent('onBeforeEditStart', grid_details_before_edit_start) - $$('grid_details').attachEvent('onBeforeEditStop', grid_details_before_edit_stop) - $$('cmd_invoice_timbrar').attachEvent('onItemClick', cmd_invoice_timbrar_click) - $$('cmd_invoice_sat').attachEvent('onItemClick', cmd_invoice_sat_click) - $$('cmd_invoice_cancelar').attachEvent('onItemClick', cmd_invoice_cancelar_click) - $$('grid_invoices').attachEvent('onItemClick', grid_invoices_click) - $$('filter_year').attachEvent('onChange', filter_year_change) - $$('filter_month').attachEvent('onChange', filter_month_change) - $$('filter_dates').attachEvent('onChange', filter_dates_change) - $$('cmd_prefactura').attachEvent('onItemClick', cmd_prefactura_click) - $$('cmd_cfdi_relacionados').attachEvent('onItemClick', cmd_cfdi_relacionados_click) - $$('lst_metodo_pago').attachEvent('onChange', lst_metodo_pago_change) - $$('lst_moneda').attachEvent('onChange', lst_moneda_change) - $$('lst_serie').attachEvent('onChange', lst_serie_change) - var tb_invoice = $$('tv_invoice').getTabbar() tb_invoice.attachEvent('onChange', tb_invoice_change) $$('prefilter_year').attachEvent('onChange', prefilter_year_change) diff --git a/source/static/js/controller/tickets.js b/source/static/js/controller/tickets.js index e07ca09..f920c39 100644 --- a/source/static/js/controller/tickets.js +++ b/source/static/js/controller/tickets.js @@ -1,5 +1,6 @@ var query = [] var msg = '' +var cfg_ticket = new Object() var tickets_controllers = { @@ -15,6 +16,7 @@ var tickets_controllers = { $$('cmd_move_tickets_left').attachEvent('onItemClick', cmd_move_tickets_left_click) $$('cmd_ticket_notes').attachEvent('onItemClick', cmd_ticket_notes_click) $$('tsearch_product_key').attachEvent('onKeyPress', tsearch_product_key_press) + $$('grid_tickets').attachEvent('onItemClick', grid_tickets_click) $$('grid_tdetails').attachEvent('onItemClick', grid_ticket_details_click) $$('grid_tdetails').attachEvent('onBeforeEditStop', grid_tickets_details_before_edit_stop) $$('gt_productos_found').attachEvent('onValueSuggest', gt_productos_found_click) @@ -26,6 +28,7 @@ var tickets_controllers = { $$('tsearch_client_key').attachEvent('onKeyPress', tsearch_client_key_press) $$('grid_ticket_clients_found').attachEvent('onValueSuggest', grid_ticket_clients_found_click) + webix.extend($$('grid_tickets'), webix.ProgressBar) webix.extend($$('grid_tickets_active'), webix.ProgressBar) } @@ -92,6 +95,12 @@ function filter_month_ticket_change(nv, ov){ function configuracion_inicial_ticket(){ current_dates_tickets() get_tickets() + + webix.ajax().sync().get('/values/configticket', function(text, data){ + var values = data.json() + //~ showvar(values) + cfg_ticket['open_pdf'] = values.open_pdf + }) } @@ -172,6 +181,11 @@ function validar_ticket(){ } +function get_ticket_pdf(id){ + window.open('/doc/tpdf/' + id, '_blank') +} + + function guardar_ticket(values){ var gd = $$('grid_tdetails') var grid = $$('grid_tickets') @@ -206,6 +220,9 @@ function guardar_ticket(values){ gd.clearAll() grid.add(values.row) $$('multi_tickets').setValue('tickets_home') + if(cfg_ticket.open_pdf){ + get_ticket_pdf(values.row.id) + } }else{ msg_error(values.msg) } @@ -631,4 +648,14 @@ function cmd_ticket_notes_click(){ function ticket_notes_key_up(){ var value = this.getValue() $$('form_new_ticket').setValues({notas: value}, true) +} + + +function grid_tickets_click(id, e, node){ + //~ var row = this.getItem(id) + if(id.column == 'pdf'){ + //~ window.open('/doc/tpdf/' + id, '_blank') + get_ticket_pdf(id) + } + } \ No newline at end of file diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js index 27065a4..b56e370 100644 --- a/source/static/js/ui/admin.js +++ b/source/static/js/ui/admin.js @@ -522,13 +522,17 @@ var options_admin_otros = [ {template: 'Complementos', type: 'section'}, {cols: [{maxWidth: 15}, {view: 'checkbox', id: 'chk_config_ine', labelWidth: 0, - labelRight: 'Mostrar el complemento INE al facturar'}, + labelRight: 'Usar el complemento INE'}, + {view: 'checkbox', id: 'chk_config_edu', labelWidth: 0, + labelRight: 'Usar el complemento EDU'}, {}]}, {maxHeight: 20}, {template: 'Punto de venta', type: 'section'}, {cols: [{maxWidth: 15}, {view: 'checkbox', id: 'chk_usar_punto_de_venta', labelWidth: 0, labelRight: 'Usar punto de venta'}, + {view: 'checkbox', id: 'chk_ticket_pdf_show', labelWidth: 0, + labelRight: 'Abrir PDF al generar'}, {}]}, {maxHeight: 20},