From f5b34eec5bade8e53ae2ccd5a2cb26662f8d65fe Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Fri, 5 Jan 2018 13:33:43 -0600 Subject: [PATCH 1/2] Llevar inventario --- source/app/models/main.py | 24 ++++++++++++++++++++++-- source/static/js/controller/admin.js | 3 ++- source/static/js/controller/products.js | 20 +++++++++++++++++++- source/static/js/ui/admin.js | 2 ++ source/static/js/ui/products.js | 11 ++++++----- 5 files changed, 51 insertions(+), 9 deletions(-) diff --git a/source/app/models/main.py b/source/app/models/main.py index 24ea30e..7e082cd 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -203,6 +203,7 @@ class Configuracion(BaseModel): 'chk_config_cuenta_predial', 'chk_config_codigo_barras', 'chk_config_precio_con_impuestos', + 'chk_llevar_inventario', ) data = (Configuracion .select() @@ -241,6 +242,7 @@ class Configuracion(BaseModel): 'chk_config_cuenta_predial', 'chk_config_codigo_barras', 'chk_config_precio_con_impuestos', + 'chk_llevar_inventario', 'chk_config_ine', 'chk_config_edu', 'chk_usar_punto_de_venta', @@ -2195,6 +2197,9 @@ class Productos(BaseModel): Productos.unidad, Productos.valor_unitario, Productos.cuenta_predial, + Productos.inventario, + Productos.existencia, + Productos.minimo, ) .where(Productos.id==id).dicts()[0] ) @@ -4050,6 +4055,10 @@ class Tickets(BaseModel): TicketsDetalle.create(**producto) + if p.inventario: + p.existencia -= Decimal(cantidad) + p.save() + base = producto['importe'] for tax in p.impuestos: impuesto_producto = round(float(tax.tasa) * base, DECIMALES) @@ -4292,13 +4301,24 @@ class Tickets(BaseModel): data = {'ok': True, 'msg': msg, 'id': obj.id} return data + def _update_inventory_if_cancel(self, id): + products = TicketsDetalle.select().where(TicketsDetalle.ticket==id) + for p in products: + if p.producto.inventario: + p.producto.existencia += p.cantidad + p.producto.save() + return + @classmethod def cancel(cls, values): id = int(values['id']) msg = 'Ticket cancelado correctamente' u = {'cancelado': True, 'estatus': 'Cancelado'} - obj = Tickets.update(**u).where(Tickets.id==id) - result = bool(obj.execute()) + with database_proxy.atomic() as txn: + obj = Tickets.update(**u).where(Tickets.id==id) + result = bool(obj.execute()) + if result: + cls._update_inventory_if_cancel(cls, id) row = {'estatus': 'Cancelado'} return {'ok': result, 'row': row, 'msg': msg} diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js index a82f41e..ebe9190 100644 --- a/source/static/js/controller/admin.js +++ b/source/static/js/controller/admin.js @@ -61,6 +61,7 @@ var controllers = { $$('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_llevar_inventario').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) $$('chk_ticket_direct_print').attachEvent('onItemClick', chk_config_item_click) @@ -1763,4 +1764,4 @@ function txt_ticket_printer_key_press(code, e){ } }) -} \ No newline at end of file +} diff --git a/source/static/js/controller/products.js b/source/static/js/controller/products.js index 45f07c1..20d19a1 100644 --- a/source/static/js/controller/products.js +++ b/source/static/js/controller/products.js @@ -11,6 +11,7 @@ var products_controllers = { $$("valor_unitario").attachEvent("onChange", valor_unitario_change) $$('precio_con_impuestos').attachEvent('onChange', precio_con_impuestos_change) $$('precio_con_impuestos').attachEvent('onTimedKeyPress', precio_con_impuestos_key_up); + $$("chk_inventario").attachEvent("onChange", chk_inventario_change) $$('grid_products').attachEvent('onItemDblClick', cmd_edit_product_click) } } @@ -28,6 +29,9 @@ function configurar_productos(is_new){ show('cuenta_predial', values.chk_config_cuenta_predial) show('codigo_barras', values.chk_config_codigo_barras) show('precio_con_impuestos', values.chk_config_precio_con_impuestos) + show('chk_inventario', values.chk_llevar_inventario) + show('txt_existencia', values.chk_llevar_inventario) + show('txt_minimo', values.chk_llevar_inventario) $$('unidad').setValue(values.default_unidad) if(is_new){ $$('grid_product_taxes').select(values.default_tax) @@ -228,6 +232,20 @@ function chk_automatica_change(new_value, old_value){ } +function chk_inventario_change(new_value, old_value){ + var value = Boolean(new_value) + if(value){ + $$('txt_existencia').enable() + $$('txt_minimo').enable() + }else{ + $$('txt_existencia').disable() + $$('txt_minimo').disable() + $$('txt_existencia').setValue(0) + $$('txt_minimo').setValue(0) + } +} + + function get_new_key(){ webix.ajax().get('/values/newkey', { error: function(text, data, xhr) { @@ -291,4 +309,4 @@ function precio_con_impuestos_key_up(){ return } calcular_sin_impuestos(parseFloat(value), taxes) -} \ No newline at end of file +} diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js index 4b946ca..7780c70 100644 --- a/source/static/js/ui/admin.js +++ b/source/static/js/ui/admin.js @@ -523,6 +523,8 @@ var options_admin_otros = [ labelRight: 'Mostrar código de barras'}, {view: 'checkbox', id: 'chk_config_precio_con_impuestos', labelWidth: 0, labelRight: 'Mostrar precio con impuestos'}, + {view: 'checkbox', id: 'chk_llevar_inventario', labelWidth: 0, + labelRight: 'Mostrar inventario'}, ]}, {maxHeight: 20}, {template: 'Complementos', type: 'section'}, diff --git a/source/static/js/ui/products.js b/source/static/js/ui/products.js index 2296f7c..e61eda1 100644 --- a/source/static/js/ui/products.js +++ b/source/static/js/ui/products.js @@ -134,13 +134,14 @@ var controls_generals = [ invalidMessage: 'Captura un valor númerico', inputAlign: 'right'}, {},]}, {cols: [ - {view: 'checkbox', id: 'inventario', name: 'inventario', hidden: true, + {view: 'checkbox', id: 'chk_inventario', name: 'inventario', hidden: true, label: 'Inventario', labelAlign: 'right', labelWidth: 130}, - {view: 'counter', id: 'existencia', name: 'existencia', hidden: true, - label: 'Existencia', step: 5, value: 0, min: 0, disabled: true}, - {view: 'counter', id: 'minimo', name: 'minimo', hidden: true, + {view: 'counter', id: 'txt_existencia', name: 'existencia', + hidden: true, label: 'Existencia', step: 5, value: 0, min: 0, + disabled: true}, + {view: 'counter', id: 'txt_minimo', name: 'minimo', hidden: true, label: 'Mínimo', step: 5, value: 0, min: 0, disabled: true}, - {id: 'txt_col2'}]}, + ]}, {cols:[{view:'label', label:'Impuestos', width: 300, align:'center'}, {}]}, {cols:[grid_product_taxes, {}]} ] From 6de21e75bd0c310d763c7d5aa2dc2806bc64d56b Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Mon, 8 Jan 2018 09:40:35 -0600 Subject: [PATCH 2/2] Soporte para pedimentos --- source/app/controllers/cfdi_xml.py | 19 ++++++++++++------- source/app/models/main.py | 6 ++++++ source/static/js/controller/admin.js | 1 + source/static/js/controller/invoices.js | 23 ++++++++++++++++++++++- source/static/js/controller/util.js | 18 +++++++++++++++++- source/static/js/ui/admin.js | 2 ++ source/static/js/ui/invoices.js | 1 + 7 files changed, 61 insertions(+), 9 deletions(-) diff --git a/source/app/controllers/cfdi_xml.py b/source/app/controllers/cfdi_xml.py index b66c579..67096e7 100644 --- a/source/app/controllers/cfdi_xml.py +++ b/source/app/controllers/cfdi_xml.py @@ -204,6 +204,7 @@ class CFDI(object): if 'complemento' in row: complemento = row.pop('complemento') cuenta_predial = row.pop('CuentaPredial', '') + pedimento = row.pop('Pedimento', '') taxes = {} if 'impuestos' in row: @@ -227,13 +228,17 @@ class CFDI(object): ET.SubElement( retenciones, '{}:Retencion'.format(self._pre), retencion) - if 'InformacionAduanera' in row: - for field in fields: - if field in row['InformacionAduanera']: - attributes[field] = row['InformacionAduanera'][field] - if attributes: - node_name = '{}:InformacionAduanera'.format(self._pre) - ET.SubElement(concepto, node_name, attributes) + # ~ if 'InformacionAduanera' in row: + # ~ for field in fields: + # ~ if field in row['InformacionAduanera']: + # ~ attributes[field] = row['InformacionAduanera'][field] + # ~ if attributes: + # ~ node_name = '{}:InformacionAduanera'.format(self._pre) + # ~ ET.SubElement(concepto, node_name, attributes) + if pedimento: + attributes = {'NumeroPedimento': pedimento} + node_name = '{}:InformacionAduanera'.format(self._pre) + ET.SubElement(concepto, node_name, attributes) if cuenta_predial: attributes = {'Numero': cuenta_predial} diff --git a/source/app/models/main.py b/source/app/models/main.py index 7e082cd..223ab6c 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -156,6 +156,7 @@ def config_timbrar(): 'cfdi_metodo_pago': Configuracion.get_bool('chk_config_ocultar_metodo_pago'), 'cfdi_condicion_pago': Configuracion.get_bool('chk_config_ocultar_condiciones_pago'), 'cfdi_open_pdf': Configuracion.get_bool('chk_config_open_pdf'), + 'cfdi_show_pedimento': Configuracion.get_bool('chk_config_show_pedimento'), } return conf @@ -238,6 +239,7 @@ class Configuracion(BaseModel): 'chk_config_ocultar_condiciones_pago', 'chk_config_send_zip', 'chk_config_open_pdf', + 'chk_config_show_pedimento', 'chk_config_anticipo', 'chk_config_cuenta_predial', 'chk_config_codigo_barras', @@ -2853,6 +2855,7 @@ class Facturas(BaseModel): locales_retenciones = 0 for product in products: + # ~ print (product) id_product = product.pop('id') p = Productos.get(Productos.id==id_product) @@ -3073,6 +3076,9 @@ class Facturas(BaseModel): if row.cuenta_predial: concepto['CuentaPredial'] = row.cuenta_predial + if row.pedimento: + concepto['Pedimento'] = row.pedimento + taxes = {} traslados = [] retenciones = [] diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js index ebe9190..26b7096 100644 --- a/source/static/js/controller/admin.js +++ b/source/static/js/controller/admin.js @@ -55,6 +55,7 @@ var controllers = { $$('chk_config_ocultar_condiciones_pago').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_send_zip').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_open_pdf').attachEvent('onItemClick', chk_config_item_click) + $$('chk_config_show_pedimento').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) diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index a4d4e1b..2b3ea4a 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -158,6 +158,9 @@ function default_config(){ $$('tv_invoice').getTabbar().showOption('INE') } cfg_invoice['open_pdf'] = values.cfdi_open_pdf + if(values.cfdi_show_pedimento){ + $$('grid_details').showColumn('pedimento') + } }) } @@ -881,7 +884,7 @@ function search_product_id_key_press(code, e){ function grid_details_before_edit_start(id){ - var columns = ['', 'descripcion', 'cantidad', 'valor_unitario', 'descuento'] + var columns = ['', 'descripcion', 'pedimento','cantidad', 'valor_unitario', 'descuento'] if(!columns.indexOf(id.column)){ return !this.getItem(id.row)[id.column] } @@ -912,6 +915,24 @@ function grid_details_before_edit_stop(state, editor){ return true } + if(editor.column == 'pedimento'){ + state.value = state.value.trim() + if(state.value.length > 21){ + msg = 'El Pedimento tiene más de 21 caracteres, será ' + msg += 'rechazado por el SAT. Edita estalo hasta que ya ' + msg += 'no veas este mensaje de error.
' + msg += '
Caracteres: ' + state.value.length + msg_error(msg) + } + if(state.value){ + if(!validate_pedimento(state.value)){ + msg = 'El formato del Pedimento es erroneo, será rechazado por el SAT' + msg_error(msg) + } + } + return true + } + if(editor.column == 'cantidad'){ var cantidad = parseFloat(state.value) if(isNaN(cantidad)){ diff --git a/source/static/js/controller/util.js b/source/static/js/controller/util.js index 06667f0..8c31ce7 100644 --- a/source/static/js/controller/util.js +++ b/source/static/js/controller/util.js @@ -345,4 +345,20 @@ function get_forma_pago(control){ var values = data.json() $$(control).getList().parse(values) }) -} \ No newline at end of file +} + + +function validate_regexp(value, pattern){ + re = new RegExp(pattern, 'i'); + if(value.match(re)){ + return true + }else{ + return false + } +} + + +function validate_pedimento(value){ + var pattern = '[0-9]{2} [0-9]{2} [0-9]{4} [0-9]{7}' + return validate_regexp(value, pattern) +} diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js index 7780c70..d9bc6cf 100644 --- a/source/static/js/ui/admin.js +++ b/source/static/js/ui/admin.js @@ -507,6 +507,8 @@ var options_admin_otros = [ labelRight: 'Enviar factura en ZIP'}, {view: 'checkbox', id: 'chk_config_open_pdf', labelWidth: 0, labelRight: 'Abrir PDF al timbrar'}, + {view: 'checkbox', id: 'chk_config_show_pedimento', labelWidth: 0, + labelRight: 'Mostrar Pedimento'}, ]}, {maxHeight: 20}, {template: 'Ayudas varias', type: 'section'}, diff --git a/source/static/js/ui/invoices.js b/source/static/js/ui/invoices.js index d9cb39e..961573e 100644 --- a/source/static/js/ui/invoices.js +++ b/source/static/js/ui/invoices.js @@ -279,6 +279,7 @@ var grid_details_cols = [ {id: "clave_sat", hidden: true}, {id: "descripcion", header:{text: 'Descripción', css: 'center'}, fillspace: true, editor: 'text'}, + {id: "pedimento", header: 'Pedimento', editor: 'text', hidden: true}, {id: "unidad", header:{text: 'Unidad', css: 'center'}, width: 100}, {id: 'cantidad', header: {text: 'Cantidad', css: 'center'}, width: 100, format: webix.i18n.numberFormat, css: 'right', editor: 'text'},