diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ee2e6d..e206c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +v 1.39.0 [18-abr-2020] +---------------------- + - Mejora: Consulta de las facturas de pago en el SAT + - Mejora: Mostrar totales en nómina + - Mejora: Mostrar totales por cantidad al facturar + - Mejora: Validar líneas con importe cero antes de facturar + + v 1.38.1 [30-mar-2020] ---------------------- - Error: En nómina al timbrar asimilados diff --git a/VERSION b/VERSION index 11a36de..5edffce 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.38.1 +1.39.0 diff --git a/source/app/models/main.py b/source/app/models/main.py index 32cd112..2c70e42 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -311,6 +311,7 @@ def config_timbrar(): 'cfdi_tax_locales_truncate': Configuracion.get_bool('chk_config_tax_locales_truncate'), 'cfdi_folio_custom': Configuracion.get_bool('chk_folio_custom'), 'cfdi_leyendasfiscales': Configuracion.get_bool('chk_config_leyendas_fiscales'), + 'cfdi_show_total_cant': Configuracion.get_bool('chk_config_show_total_cant'), } return conf @@ -562,6 +563,7 @@ class Configuracion(BaseModel): 'chk_ticket_total_up', 'chk_ticket_user_show_doc', 'chk_config_invoice_by_ticket', + 'chk_config_show_total_cant', ) data = (Configuracion .select() @@ -6833,6 +6835,21 @@ class CfdiPagos(BaseModel): opt = values.pop('opt') return getattr(cls, '_get_{}'.format(opt))(cls, values) + def _get_status_sat(self, values): + id = int(values['id']) + obj = CfdiPagos.get(CfdiPagos.id == id) + estatus_sat = util.get_sat(obj.xml) + if obj.estatus_sat != estatus_sat: + obj.estatus_sat = estatus_sat + obj.save() + + # ~ if obj.estatus_sat == 'Vigente' and obj.estatus == 'Cancelada': + # ~ days = utils.get_days(obj.fecha_cancelacion) + # ~ if days > 3: + # ~ estatus_sat = 'uncancel' + + return estatus_sat + def _get_table(self, values): # ~ print('\n\n', values, '\n') if 'start' in values: diff --git a/source/app/settings.py b/source/app/settings.py index 0c80591..6e5eac9 100644 --- a/source/app/settings.py +++ b/source/app/settings.py @@ -47,7 +47,7 @@ except ImportError: DEBUG = DEBUG -VERSION = '1.38.1' +VERSION = '1.39.0' EMAIL_SUPPORT = ('soporte@empresalibre.mx',) TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION) diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js index 6b41287..398dd04 100644 --- a/source/static/js/controller/admin.js +++ b/source/static/js/controller/admin.js @@ -123,6 +123,7 @@ var controllers = { $$('chk_config_decimales_precios').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_user_show_doc').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_invoice_by_ticket').attachEvent('onItemClick', chk_config_item_click) + $$('chk_config_show_total_cant').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_anticipo').attachEvent('onItemClick', chk_config_item_click) diff --git a/source/static/js/controller/bancos.js b/source/static/js/controller/bancos.js index 1fa2946..d28181c 100644 --- a/source/static/js/controller/bancos.js +++ b/source/static/js/controller/bancos.js @@ -80,6 +80,7 @@ var bancos_controllers = { $$('filter_invoice_pay_month').attachEvent('onChange', filter_invoice_pay_change) $$('grid_bank_invoice_pay').attachEvent('onItemClick', grid_bank_invoice_pay_click) $$('grid_cuentabanco').attachEvent('onItemDblClick', grid_cuentabanco_double_click) + $$('cmd_invoice_pay_sat').attachEvent('onItemClick', cmd_invoice_pay_sat_click) init_config_bank() } @@ -1351,3 +1352,40 @@ function cmd_save_mov_description_click(){ function cmd_close_mov_description_click(){ $$('win_mov_description').close() } + + +function cmd_invoice_pay_sat_click(){ + var g = $$('grid_bank_invoice_pay') + + if(g.count() == 0){ + return + } + + var row = g.getSelectedItem() + if (row == undefined){ + msg_error('Selecciona una factura de pago') + return + } + + if (row instanceof Array){ + msg_error('Selecciona solo una factura de pago') + return + } + + if(!row.uuid){ + msg_error('La factura de pago no esta timbrada, solo es posible \ + consultar el estatus en el SAT de facturas timbradas') + return + } + + var options = {opt: 'status_sat', id: row.id} + webix.ajax().get('/cfdipay', options, function(text, data){ + var value = data.json() + if(value == 'Vigente'){ + msg_ok(value) + }else{ + msg_error(value) + } + }) + +} diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index a5ccf61..1cbd0a3 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -54,6 +54,7 @@ var invoices_controllers = { $$('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) + $$('grid_details').attachEvent('onAfterEditStop', grid_details_after_edit_stop) $$('cmd_invoice_timbrar').attachEvent('onItemClick', cmd_invoice_timbrar_click) $$('cmd_invoice_sat').attachEvent('onItemClick', cmd_invoice_sat_click) $$('cmd_invoice_verify_sat').attachEvent('onItemClick', cmd_invoice_verify_sat_click) @@ -229,6 +230,7 @@ function default_config(){ show('fs_students', values.cfdi_edu) show('fs_divisas', values.cfdi_divisas) show('txt_folio_custom', values.cfdi_folio_custom) + show('txt_total_cant', values.cfdi_show_total_cant) }) } @@ -447,14 +449,14 @@ function validate_invoice(values){ $$('tv_invoice').getTabbar().setValue('INE') msg = 'El ID de contabilidad deben ser solo digitos' msg_error(msg) - return False + return false } if(id_contabilidad.length != 6){ $$('tv_invoice').getTabbar().setValue('INE') msg = 'El ID de contabilidad deben ser 6 digitos' msg_error(msg) - return False + return false } } @@ -464,6 +466,16 @@ function validate_invoice(values){ msg_ok('El CFDI es de tipo Traslado') } + var rows = grid.data.getRange() + for (i = 0; i < rows.length; i++) { + var importe = rows[i]['importe'] + if(!importe){ + var msg = 'No es posible facturar importes en cero, revisa la línea: ' + (i + 1) + msg_error(msg) + return false + } + } + return true } @@ -810,6 +822,7 @@ function calcular_impuestos(){ var grid_totals = $$('grid_totals') var impuesto_producto = 0 var impuesto = null + var total_cant = 0 table_totals.clear() grid_totals.clearAll() @@ -826,7 +839,10 @@ function calcular_impuestos(){ var cantidad = parseFloat(product.cantidad) var import2 = (valor_unitario * cantidad).round(DECIMALES) var importe = parseFloat(product.importe) + subtotal += importe + total_cant += cantidad + query = table_pt.chain().find({'product': product.id_product}).data() for(var tax of query){ impuesto = table_taxes.findOne({'id': tax.tax}) @@ -839,10 +855,6 @@ function calcular_impuestos(){ base = import2 } - //~ if(impuesto.tipo == 'R'){ - //~ base = (base * -1).round(DECIMALES) - //~ } - if(cfg_invoice.tax_decimals){ impuesto_producto = (impuesto.tasa * base).round(DECIMALES_TAX) }else{ @@ -854,7 +866,6 @@ function calcular_impuestos(){ } if(impuesto.tipo == 'R'){ - //~ base = (base * -1).round(DECIMALES) impuesto_producto = (impuesto_producto * -1).round(DECIMALES) } @@ -889,6 +900,7 @@ function calcular_impuestos(){ var row = {importe: subtotal} grid_totals.updateItem(1, row) + $$('txt_total_cant').setValue(format_decimal_2(total_cant)) } @@ -1124,7 +1136,14 @@ function grid_details_before_edit_stop(state, editor){ row['importe'] = (cantidad * precio_final).round(DECIMALES) grid.refresh() - calcular_impuestos() +} + + +function grid_details_after_edit_stop(state, editor, ignoreUpdate){ + var columns = ['', 'cantidad', 'valor_unitario', 'descuento'] + if(columns.indexOf(editor.column) > 0){ + calcular_impuestos() + } } diff --git a/source/static/js/controller/nomina.js b/source/static/js/controller/nomina.js index 50cfb5d..702c03b 100644 --- a/source/static/js/controller/nomina.js +++ b/source/static/js/controller/nomina.js @@ -19,6 +19,7 @@ var nomina_controllers = { $$('filter_year_nomina').attachEvent('onChange', filter_year_nomina_change) $$('filter_month_nomina').attachEvent('onChange', filter_month_nomina_change) $$('filter_dates_nomina').attachEvent('onChange', filter_dates_nomina_change) + $$('grid_nomina').attachEvent('onSelectChange', grid_nomina_on_select_change) webix.extend($$('grid_nomina'), webix.ProgressBar) } } @@ -553,3 +554,19 @@ function cmd_nomina_download_click(){ } + +function grid_nomina_on_select_change(){ + var g = $$('grid_nomina') + var rows = g.getSelectedItem(true) + var total = 0 + + for (i = 0; i < rows.length; i++) { + if(typeof(rows[i].total) == 'string'){ + total += rows[i].total.to_float() + }else{ + total += rows[i].total + } + } + g.getColumnConfig('empleado').footer[0].text = webix.i18n.priceFormat(total) + g.refreshColumns() +} diff --git a/source/static/js/controller/util.js b/source/static/js/controller/util.js index 9150608..171036e 100644 --- a/source/static/js/controller/util.js +++ b/source/static/js/controller/util.js @@ -337,6 +337,28 @@ webix.ui.datafilter.summTimbrada = webix.extend({ }, webix.ui.datafilter.summColumn); +webix.ui.datafilter.summTimbradaN = webix.extend({ + refresh:function(master, node, value){ + node.firstChild.innerHTML = this.summGenerate(master); + }, + summGenerate:function(master){ + var sum = 0 + master.eachRow(function(id){ + var row = master.getItem(id) + if(row.estatus == 'Timbrado'){ + var importe = row.total + if(typeof importe === 'string'){ + importe = row.total.to_float() + } + sum += importe + } + }) + return webix.i18n.priceFormat(sum) + } +}, webix.ui.datafilter.summColumn); + + + function validate_rfc(value){ rfc = value.trim().toUpperCase(); if ( rfc == ""){ diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js index 0bc4e92..b0de215 100644 --- a/source/static/js/ui/admin.js +++ b/source/static/js/ui/admin.js @@ -685,6 +685,8 @@ var options_admin_otros = [ {cols: [{maxWidth: 15}, {view: 'checkbox', id: 'chk_config_invoice_by_ticket', labelWidth: 0, labelRight: 'Factura global por ticket'}, + {view: 'checkbox', id: 'chk_config_show_total_cant', labelWidth: 0, + labelRight: 'Mostrar total de cantidades'}, {}, ]}, {maxHeight: 15}, diff --git a/source/static/js/ui/bancos.js b/source/static/js/ui/bancos.js index a3861bb..db26ab4 100644 --- a/source/static/js/ui/bancos.js +++ b/source/static/js/ui/bancos.js @@ -297,7 +297,6 @@ var grid_bank_invoice_pay_cols = [ var grid_bank_invoice_pay = { view: 'datatable', id: 'grid_bank_invoice_pay', - //~ subview: sv_grid_invoices, select: 'row', adjust: true, footer: true, @@ -369,6 +368,8 @@ var toolbar_bank_invoice_pay_filter = [ labelAlign: 'right', labelWidth: 50, width: 200, options: months}, {view: 'daterangepicker', id: 'filter_invoice_pay_dates', label: 'Fechas', labelAlign: 'right', width: 300}, + {view: 'button', id: 'cmd_invoice_pay_sat', label: 'SAT', + type: 'iconButton', autowidth: true, icon: 'check-circle'}, {}, ] diff --git a/source/static/js/ui/invoices.js b/source/static/js/ui/invoices.js index 8e52024..8669632 100644 --- a/source/static/js/ui/invoices.js +++ b/source/static/js/ui/invoices.js @@ -559,6 +559,18 @@ var body_students = {rows:[ placeholder:'Captura al menos tres letras'}, ]} + +var txt_total_cant = {rows:[{ + view: 'text', + id: 'txt_total_cant', + readonly: true, + width: 300, + label: 'Total cantidades: ', + labelWidth: 150, + inputAlign: 'center' +}, {}]} + + var controls_generate = [ {minHeight: 10, maxHeight: 10}, toolbar_invoices_generate, @@ -610,7 +622,7 @@ var controls_generate = [ {view: 'label', label: 'Detalle', height: 30, align: 'left'}, grid_details, {minHeight: 15, maxHeight: 15}, - {cols: [{}, grid_totals]}, + {cols: [{}, txt_total_cant, grid_totals]}, {minHeight: 15, maxHeight: 15}, {margin: 20, cols: [{}, {view: "button", id: "cmd_timbrar", label: "Timbrar", icon: 'ticket', diff --git a/source/static/js/ui/nomina.js b/source/static/js/ui/nomina.js index 93c4a8b..feece5d 100644 --- a/source/static/js/ui/nomina.js +++ b/source/static/js/ui/nomina.js @@ -57,9 +57,9 @@ var grid_cols_nomina = [ adjust: 'data', sort: 'string'}, {id: 'total', header: ['Total', {content: 'numberFilter'}], width: 150, sort: 'int', format: webix.i18n.priceFormat, css: 'right', - footer: {content: 'summActive', css: 'right'}}, + footer: {content: 'summTimbradaN', css: 'right'}}, {id: "empleado", header: ["Empleado", {content: "selectFilter"}], - fillspace:true, sort:"string"}, + fillspace:true, sort:"string", footer: {text: '$ 0.00'}}, {id: 'xml', header: 'XML', adjust: 'data', template: get_icon('xml')}, {id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')}, {id: 'email', header: '@', adjust: 'data', template: get_icon('email')}