diff --git a/CHANGELOG.md b/CHANGELOG.md index cfb87e5..e856dd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v 1.27.0 [17-ene-2019] +---------------------- + - Mejora: Permitir capturar folio manualmente + + v 1.26.1 [16-ene-2019] ---------------------- - Error: Guardar logos de emisor diff --git a/VERSION b/VERSION index dd43a14..5db08bf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.26.1 +1.27.0 diff --git a/source/app/models/main.py b/source/app/models/main.py index 0450986..86236ac 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -295,6 +295,7 @@ def config_timbrar(): 'cfdi_with_taxes': Configuracion.get_bool('chk_config_price_with_taxes_in_invoice'), 'cfdi_add_same_product': Configuracion.get_bool('chk_config_add_same_product'), 'cfdi_tax_locales_truncate': Configuracion.get_bool('chk_config_tax_locales_truncate'), + 'cfdi_folio_custom': Configuracion.get_bool('chk_folio_custom'), } return conf @@ -389,6 +390,17 @@ class Configuracion(BaseModel): return values + def _get_folios(self): + fields = ( + 'chk_folio_custom', + ) + data = (Configuracion + .select() + .where(Configuracion.clave.in_(fields)) + ) + values = {r.clave: util.get_bool(r.valor) for r in data} + return values + @classmethod def get_(cls, keys): if isinstance(keys, str): @@ -400,7 +412,7 @@ class Configuracion(BaseModel): return data[0].valor return '' - options = ('partners', 'complements') + options = ('partners', 'complements', 'folios') opt = keys['fields'] if opt in options: return getattr(cls, '_get_{}'.format(opt))(cls) @@ -4114,6 +4126,9 @@ class Facturas(BaseModel): return data def _get_opt(self, values): + if values['opt'] == 'foliocustom': + return self._get_folio_custom(self, values) + if values['opt'] == 'porpagar': return self._get_por_pagar(self, util.loads(values['ids'])) @@ -4244,6 +4259,28 @@ class Facturas(BaseModel): return inicio + def _get_folio_custom(self, values): + result = {'ok': False, 'msg': 'Folio libre para facturar'} + try: + folio = int(values['folio']) + except ValueError: + result['ok'] = True + result['msg'] = 'Valor de folio inválido' + return result + + serie = values['serie'] + + result['ok'] = (Facturas + .select() + .where((Facturas.serie==serie) & (Facturas.folio==folio)) + .exists()) + + if result['ok']: + result['msg'] = 'Folio previamente usado' + + return result + + def _calculate_totals(self, invoice, products, tipo_comprobante): tax_locales = Configuracion.get_bool('chk_config_tax_locales') tax_locales_truncate = Configuracion.get_bool('chk_config_tax_locales_truncate') @@ -4396,10 +4433,19 @@ class Facturas(BaseModel): relacionados = util.loads(values.pop('relacionados')) ine = values.pop('ine', {}) tipo_comprobante = values['tipo_comprobante'] + folio_custom = values.pop('folio_custom', '') emisor = Emisor.select()[0] values['serie'] = cls._get_serie(cls, user, values['serie']) - values['folio'] = cls._get_folio(cls, values['serie']) + if Configuracion.get_bool('chk_folio_custom') and folio_custom: + fc = {'folio': folio_custom, 'serie': values['serie']} + result = cls._get_folio_custom(cls, fc) + if result['ok']: + data = {'ok': False, 'row': {}, 'new': True, 'msg': result['msg']} + return data + values['folio'] = int(folio_custom) + else: + values['folio'] = cls._get_folio(cls, values['serie']) values['tipo_cambio'] = round(float(values['tipo_cambio']), 4) values['lugar_expedicion'] = emisor.cp_expedicion or emisor.codigo_postal values['anticipo'] = util.get_bool(values['anticipo']) diff --git a/source/app/settings.py b/source/app/settings.py index 7ffdb49..d5bbb19 100644 --- a/source/app/settings.py +++ b/source/app/settings.py @@ -47,7 +47,7 @@ except ImportError: DEBUG = DEBUG -VERSION = '1.26.1' +VERSION = '1.27.0' EMAIL_SUPPORT = ('soporte@empresalibre.net',) TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION) diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js index 7610f18..f8920ea 100644 --- a/source/static/js/controller/admin.js +++ b/source/static/js/controller/admin.js @@ -35,6 +35,7 @@ var controllers = { $$('up_cert').attachEvent('onUploadComplete', up_cert_upload_complete) $$('cmd_agregar_serie').attachEvent('onItemClick', cmd_agregar_serie_click) $$('grid_folios').attachEvent('onItemClick', grid_folios_click) + $$('chk_folio_custom').attachEvent('onItemClick', chk_config_item_click) $$('cmd_probar_correo').attachEvent('onItemClick', cmd_probar_correo_click) $$('cmd_guardar_correo').attachEvent('onItemClick', cmd_guardar_correo_click) $$('cmd_clean_email').attachEvent('onItemClick', cmd_clean_email_click) @@ -315,6 +316,18 @@ function get_table_folios(){ } }) + webix.ajax().get('/config', {'fields': 'folios'}, { + error: function(text, data, xhr) { + msg = 'Error al consultar' + msg_error(msg) + }, + success: function(text, data, xhr) { + var values = data.json() + Object.keys(values).forEach(function(k, i) { + $$(k).setValue(values[k]) + }) + } + }) } diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index 893312e..0d607d1 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -79,6 +79,9 @@ var invoices_controllers = { $$('cmd_admin_invoice_notes').attachEvent('onItemClick', cmd_admin_invoice_notes_click) $$('cmd_import_invoice').attachEvent('onItemClick', cmd_import_invoice_click) + $$('txt_folio_custom').attachEvent('onKeyPress', txt_folio_custom_key_press); + $$('txt_folio_custom').attachEvent('onBlur', txt_folio_custom_lost_focus); + webix.extend($$('grid_invoices'), webix.ProgressBar) init_config_invoices() @@ -214,6 +217,7 @@ function default_config(){ $$('grid_details').showColumn('student') } show('fs_students', values.cfdi_edu) + show('txt_folio_custom', values.cfdi_folio_custom) }) } @@ -633,6 +637,7 @@ function guardar_y_timbrar(values){ data['anticipo'] = anticipo data['donativo'] = donativo data['notas'] = values.notas + data['folio_custom'] = $$('txt_folio_custom').getValue() var usar_ine = $$('chk_cfdi_usar_ine').getValue() if(usar_ine){ @@ -2220,3 +2225,43 @@ function grid_invoices_on_subview_create(view, item){ function cmd_preinvoice_generate_delete_click(){ } + + +function txt_folio_custom_key_press(code, e){ + var data = [8, 9, 37, 39, 46] + if ( data.indexOf(code) >= 0 ){ + return true; + } + + if ( code < 48 || code > 57){ + return false; + } +} + + +function validate_folio_exists(folio){ + var serie = $$('lst_serie').getText() + var values = {'opt': 'foliocustom', 'folio': folio, 'serie': serie} + webix.ajax().get('/invoices', values, { + error: function(text, data, xhr) { + msg_error('Error al consultar') + }, + success: function(text, data, xhr) { + var result = data.json() + if(result.ok){ + msg_error(result.msg) + focus('txt_folio_custom') + }else{ + msg_ok(result.msg) + } + return result.ok + } + }) +} + + +function txt_folio_custom_lost_focus(prev){ + if(prev.getValue()){ + validate_folio_exists(prev.getValue()) + } +} diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js index f04eebc..617d011 100644 --- a/source/static/js/ui/admin.js +++ b/source/static/js/ui/admin.js @@ -461,7 +461,10 @@ var emisor_folios = [ autowidth: true, type: 'form'}, {}]}, {template: 'Series guardadas', type: 'section'}, - grid_folios + grid_folios, + {template: 'Opciones', type: 'section'}, + {view: 'checkbox', id: 'chk_folio_custom', labelWidth: 0, + labelRight: 'Permitir capturar el folio manualmente (no recomendado): '}, ] diff --git a/source/static/js/ui/invoices.js b/source/static/js/ui/invoices.js index 09d7e1d..0370bb1 100644 --- a/source/static/js/ui/invoices.js +++ b/source/static/js/ui/invoices.js @@ -500,6 +500,8 @@ var body_comprobante = {rows: [{ options: [], }, ]}, + {view: 'text', id: 'txt_folio_custom', label: 'Folio: ', labelWidth: 50, + hidden: true, placeholder: 'Solo números'}, {view: 'richselect', id: 'lst_uso_cfdi', name: 'uso_cfdi', required: true, labelPosition: 'top', label: 'Uso del CFDI', options: []}, ]}