diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b1b5fe..84ca76b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -v 1.21.0 [11-oct-2018] +v 1.21.0 [12-oct-2018] ---------------------- - Error #287 - Mejora: Complemento de pago con datos de cuentas @@ -11,7 +11,7 @@ v 1.20.0 [08-oct-2018] - Error #295 - Mejora: Cuentas de banco para clientes -* IMPORTANTE: Es necesario realizar una migración, despues de actualizar la rama principal. +* IMPORTANTE: Es necesario realizar una migración, despues de actualizar. v 1.19.1 [03-oct-2018] diff --git a/docs/empresalibre/docs/notas.md b/docs/empresalibre/docs/notas.md index e2f225f..36a8f00 100644 --- a/docs/empresalibre/docs/notas.md +++ b/docs/empresalibre/docs/notas.md @@ -6,7 +6,7 @@ siempre actualizado.** Solo se da soporte sobre la ultima versión de **Empresa Libre**. -### 1.21.0 [11-oct-2018] +### 1.21.0 [12-oct-2018] - Error [#287](https://gitlab.com/mauriciobaeza/empresa-libre/issues/287) - Mejora: Complemento de pago con datos de cuentas diff --git a/docs/empresalibre/docs/preguntas.md b/docs/empresalibre/docs/preguntas.md index 610686a..e24507f 100644 --- a/docs/empresalibre/docs/preguntas.md +++ b/docs/empresalibre/docs/preguntas.md @@ -77,6 +77,16 @@ Toma en cuenta que este sitio esta en constante actualización y desarrollo, los datos generados se limpian de forma regular. +
+### ¿Dondé descargar los archivos necesarios? + +Todos los archivos necesarios para probar localmente **Empresa Libre** en tu +equipo, los puedes descargar desde nuestra carpeta compartida, donde también +puedes descargar todas las plantillas necesarias para el sistema + +[Carpeta pública de Empresa Libre][7] + +
### Después de actualizar, no veo los cambios esperados en pantalla @@ -92,3 +102,4 @@ tu pantalla, en la mayoría de los navegadores con la combinación de teclas [4]: https://gitlab.com/mauriciobaeza/empresa-libre/issues [5]: [6]: https://universolibre.org/hacemos/ +[7]: https://doc.elmau.net/d/dbb11c9186684457beb6/ diff --git a/source/app/models/main.py b/source/app/models/main.py index fcfbb0e..7e94bd6 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -45,6 +45,7 @@ FORMAT6 = '{0:.6f}' FORMAT_TAX = FORMAT4 FORMAT_PRECIO = FORMAT4 RFC_PUBLICO = 'XAXX010101000' +RFC_EXTRANJERO = 'XEXX010101000' database_proxy = Proxy() @@ -241,7 +242,8 @@ def config_main(): 'nomina': nomina, 'timbres': 0, 'decimales_precios': DECIMALES, - 'pagos': Configuracion.get_bool('chk_config_pagos') + 'pagos': Configuracion.get_bool('chk_config_pagos'), + 'pays_data_bank': Configuracion.get_bool('chk_cfg_pays_data_bank') } dp = Configuracion.get_bool('chk_config_decimales_precios') if dp: @@ -320,6 +322,28 @@ class Configuracion(BaseModel): values = {r.clave: util.get_bool(r.valor) for r in data} return values + def _get_complements(self): + fields = ( + 'chk_config_ine', + 'chk_config_edu', + 'chk_config_pagos', + 'chk_cfg_pays_data_bank', + ) + data = (Configuracion + .select() + .where(Configuracion.clave.in_(fields)) + ) + values = {r.clave: util.get_bool(r.valor) for r in data} + + fields = ( + 'txt_config_cfdipay_serie', + 'txt_config_cfdipay_folio', + ) + for f in fields: + values[f] = Configuracion.get_(f) + + return values + @classmethod def get_(cls, keys): if isinstance(keys, str): @@ -331,7 +355,7 @@ class Configuracion(BaseModel): return data[0].valor return '' - options = ('partners',) + options = ('partners', 'complements') opt = keys['fields'] if opt in options: return getattr(cls, '_get_{}'.format(opt))(cls) @@ -388,9 +412,6 @@ class Configuracion(BaseModel): 'chk_config_codigo_barras', 'chk_config_precio_con_impuestos', 'chk_llevar_inventario', - 'chk_config_ine', - 'chk_config_edu', - 'chk_config_pagos', 'chk_usar_punto_de_venta', 'chk_ticket_pdf_show', 'chk_ticket_direct_print', @@ -2547,6 +2568,7 @@ class Socios(BaseModel): class SociosCuentasBanco(BaseModel): socio = ForeignKeyField(Socios) + activa = BooleanField(default=True) banco = ForeignKeyField(SATBancos) cuenta = TextField(default='') clabe = TextField(default='') @@ -2561,10 +2583,15 @@ class SociosCuentasBanco(BaseModel): def __str__(self): return '{} ({})'.format(self.banco.name, self.cuenta[-4:]) - @classmethod - def get_values(cls, values): - opt = values.pop('opt') - return getattr(cls, '_get_{}'.format(opt))(cls, values) + def _get_by_name(self, values): + name = values['name'] + query = (SociosCuentasBanco + .select() + .where(SociosCuentasBanco.activa==True, Socios.nombre==name) + .join(Socios).switch(SociosCuentasBanco) + ) + rows = tuple([{'id': q.id, 'value': str(q)} for q in query]) + return {'ok': True, 'values': rows} def _get_by_partner(self, values): id = int(values['id_partner']) @@ -2579,6 +2606,11 @@ class SociosCuentasBanco(BaseModel): .dicts()) return tuple(rows) + @classmethod + def get_values(cls, values): + opt = values.pop('opt') + return getattr(cls, '_get_{}'.format(opt))(cls, values) + @classmethod def post(cls, values): opt = values.pop('opt') @@ -2612,6 +2644,13 @@ class SociosCuentasBanco(BaseModel): msg = 'Cuenta borrada correctamente' return {'ok': result, 'msg': msg} + @classmethod + def validate_partner_account(cls, id, invoices): + id_invoice = int(tuple(invoices.keys())[0]) + account = SociosCuentasBanco.get(SociosCuentasBanco.id==id) + invoice = Facturas.get(Facturas.id==id_invoice) + return account.socio == invoice.cliente + class Contactos(BaseModel): socio = ForeignKeyField(Socios) @@ -2737,6 +2776,16 @@ class MovimientosBanco(BaseModel): def _add(self, values): ids = values.pop('ids', '') + cuenta_socio = values.get('cuenta_socio', None) + if not ids: + cuenta_socio = None + + if ids and cuenta_socio and \ + not SociosCuentasBanco.validate_partner_account(cuenta_socio, util.loads(ids)): + msg = 'La cuenta seleccionada no corresponde al cliente' + data = {'ok': False, 'msg': msg} + return data + if ids and not Facturas.validate_count_partners(util.loads(ids)): msg = 'Facturas relacionadas a diferentes clientes' data = {'ok': False, 'msg': msg} @@ -2751,6 +2800,7 @@ class MovimientosBanco(BaseModel): account = CuentasBanco.get(CuentasBanco.id==int(values['cuenta'])) values['fecha'] = '{}T{}'.format(values['fecha'][:10], hora) values['cuenta'] = account + values['cuenta_socio'] = cuenta_socio values['moneda'] = account.moneda.key values['retiro'] = util.get_float(values['retiro']) values['deposito'] = util.get_float(values['deposito']) @@ -3456,13 +3506,6 @@ class Facturas(BaseModel): @classmethod def validate_count_partners(cls, ids): filters = (Facturas.id.in_(tuple(ids.keys()))) - # ~ partners = (Facturas.select(fn.COUNT(Facturas.cliente)) - # ~ .where(filters) - # ~ .group_by(Facturas.cliente) - # ~ .order_by(Facturas.cliente).tuples()) - # ~ if len(partners) > 1: - # ~ return False - # ~ return True partners = (Facturas.select(fn.COUNT(Socios.rfc)) .where(filters) .join(Socios).switch(Facturas) @@ -5795,6 +5838,7 @@ class CfdiPagos(BaseModel): def _generate_xml(self, invoice, auth): emisor = Emisor.select()[0] cert = Certificado.get_cert() + used_data_bank = Configuracion.get_bool('chk_cfg_pays_data_bank') cfdi = {} related = {} @@ -5844,7 +5888,6 @@ class CfdiPagos(BaseModel): impuestos = {} mov = invoice.movimiento - # ~ currency = mov.cuenta.moneda.key currency = mov.moneda related_docs = self._get_related_xml(self, invoice.movimiento, currency) pagos = { @@ -5854,6 +5897,20 @@ class CfdiPagos(BaseModel): 'Monto': FORMAT.format(mov.deposito), 'relacionados': related_docs, } + if mov.numero_operacion: + pagos['NumOperacion'] = mov.numero_operacion + + if used_data_bank and mov.cuenta_socio: + if mov.cuenta_socio.banco.rfc: + pagos['RfcEmisorCtaOrd'] = mov.cuenta_socio.banco.rfc + if mov.cuenta_socio.banco.rfc == RFC_EXTRANJERO: + pagos['NomBancoOrdExt'] = mov.cuenta_socio.banco.name + pagos['CtaOrdenante'] = mov.cuenta_socio.cuenta + if mov.cuenta.banco.rfc: + pagos['RfcEmisorCtaBen'] = mov.cuenta.banco.rfc + pagos['CtaBeneficiario'] = mov.cuenta.cuenta + + if currency != CURRENCY_MN: pagos['TipoCambioP'] = FORMAT_TAX.format(mov.tipo_cambio) @@ -8416,15 +8473,21 @@ def _migrate_tables(rfc=''): table = 'movimientosbanco' columns = [c.name for c in database_proxy.get_columns(table)] - if not 'cuenta_socio' in columns: + if not 'cuenta_socio_id' in columns: cuenta_socio = ForeignKeyField(SociosCuentasBanco, null=True, to_field=SociosCuentasBanco.id) - migrations.append(migrator.add_column(table, 'socioscuentasbanco_id', cuenta_socio)) + migrations.append(migrator.add_column(table, 'cuenta_socio_id', cuenta_socio)) migrations.append(migrator.drop_column(table, 'origen_rfc')) migrations.append(migrator.drop_column(table, 'origen_nombre')) migrations.append(migrator.drop_column(table, 'origen_cuenta')) migrations.append(migrator.drop_column(table, 'destino_rfc')) migrations.append(migrator.drop_column(table, 'destino_cuenta')) + table = 'socioscuentasbanco' + columns = [c.name for c in database_proxy.get_columns(table)] + if not 'activa' in columns: + activa = BooleanField(default=True) + migrations.append(migrator.add_column(table, 'activa', activa)) + if migrations: with database_proxy.atomic() as txn: migrate(*migrations) diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js index d9b2a75..9569a3c 100644 --- a/source/static/js/controller/admin.js +++ b/source/static/js/controller/admin.js @@ -92,6 +92,7 @@ var controllers = { $$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_edu').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_pagos').attachEvent('onItemClick', chk_config_item_click) + $$('chk_cfg_pays_data_bank').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) @@ -1133,6 +1134,7 @@ function tab_options_change(nv, ov){ var cv = { tab_admin_templates: 'templates', tab_admin_partners: 'partners', + tab_admin_complements: 'complements', tab_admin_otros: 'configotros', } get_config_values(cv[nv]) diff --git a/source/static/js/controller/bancos.js b/source/static/js/controller/bancos.js index 2f5c319..30f6f07 100644 --- a/source/static/js/controller/bancos.js +++ b/source/static/js/controller/bancos.js @@ -37,8 +37,12 @@ function init_config_bank(){ g3.showColumn('total') g3.showColumn('currency') } - show('cmd_complemento_pago', get_config('used_cfdi_pays')) - show('cmd_show_invoice_pay', get_config('used_cfdi_pays')) + var used_cfdi_pays = get_config('used_cfdi_pays') + show('cmd_complemento_pago', used_cfdi_pays) + show('cmd_show_invoice_pay', used_cfdi_pays) + if(used_cfdi_pays){ + show_column('grid_cuentabanco', 'invoice') + } set_year_month() } @@ -69,6 +73,7 @@ var bancos_controllers = { $$('cmd_pay_delete').attachEvent('onItemClick', cmd_pay_delete_click) $$('grid_cfdi_pay').attachEvent('onItemClick', grid_cfdi_pay_click) $$('grid_cfdi_por_pagar').attachEvent('onItemDblClick', grid_cfdi_por_pagar_double_click) + $$('grid_cfdi_por_pagar').attachEvent('onAfterFilter', grid_cfdi_por_pagar_on_after_filter) $$('grid_cfdi_este_deposito').attachEvent('onItemDblClick', grid_cfdi_este_deposito_double_click) $$('cmd_show_invoice_pay').attachEvent('onItemClick', cmd_show_invoice_pay_click) $$('filter_invoice_pay_year').attachEvent('onChange', filter_invoice_pay_change) @@ -246,7 +251,6 @@ function get_facturas_por_pagar(){ function cmd_agregar_retiro_click(){ - //~ get_bancos_forma_pago(true) set_way_payment('lst_retiro_forma_pago', true, current_way_payment) var title = 'Agregar retiro de banco a la cuenta ' + $$('lst_cuentas_banco').getText() + ' en ' + $$('txt_cuenta_moneda').getValue() $$('title_bank_retiro').setValue(title) @@ -256,14 +260,17 @@ function cmd_agregar_retiro_click(){ function cmd_agregar_deposito_click(){ msg_importe = '' - //~ get_bancos_forma_pago(false) + get_facturas_por_pagar() set_way_payment('lst_deposito_forma_pago', true, current_way_payment) var g = $$('grid_cfdi_este_deposito') g.config.columns[g.getColumnIndex('importe')].header = 'Este Pago ' + current_currency g.refreshColumns() + show('deposit_type_change', current_currency!=CURRENCY_MN) + var pays = get_config('used_cfdi_pays') && get_config('pays_data_bank') + show('lst_partner_account_bank', pays) var title = 'Agregar depósito de banco a la cuenta ' + $$('lst_cuentas_banco').getText() + ' en ' + $$('txt_cuenta_moneda').getValue() $$('title_bank_deposit').setValue(title) @@ -668,6 +675,7 @@ function guardar_deposito(values){ data['tipo_cambio'] = values.deposit_type_change.to_float4() data['retiro'] = 0.0 data['descripcion'] = values.deposito_descripcion + data['cuenta_socio'] = values.partner_account_bank current_way_payment = data['forma_pago'] @@ -718,41 +726,40 @@ function cmd_guardar_deposito_click(){ return } + msg = 'Todos los datos son correctos.

' + if(!grid.count()){ - msg = 'Todos los datos son correctos
br>' - msg = 'El depósito no tiene facturas relacionadas

¿Estás ' - msg += ' seguro de guardar el depósito sin facturas relacionadas?' - webix.confirm({ - title: 'Guardar depósito', - ok: 'Si', - cancel: 'No', - type: 'confirm-error', - text: msg, - callback:function(result){ - if(result){ - guardar_deposito(values) - } - } - }) + msg += 'El depósito no tiene facturas relacionadas
¿Estás ' + msg += ' seguro de guardar el depósito sin facturas relacionadas?

' }else{ if(!msg_importe){ - msg_importe = 'Se van a relacionar ' + grid.count() + ' facturas.' - } - msg = 'Todos los datos son correctos.

' + msg_importe + '

' - msg += '¿Deseas agregar este depósito?' - webix.confirm({ - title: 'Guardar depósito', - ok: 'Si', - cancel: 'No', - type: 'confirm-error', - text: msg, - callback:function(result){ - if(result){ - guardar_deposito(values) - } + if(grid.count()==1){ + msg += 'Se va a relacionar 1 factura.

' + }else{ + msg += 'Se van a relacionar ' + grid.count() + ' facturas.

' } - }) + } } + + if(get_config('pays_data_bank') && grid.count() && !values.partner_account_bank){ + msg += 'NO seleccionaste cuenta origen.

' + } + + msg += '¿Deseas agregar este depósito?' + + webix.confirm({ + title: 'Guardar depósito', + ok: 'Si', + cancel: 'No', + type: 'confirm-error', + text: msg, + callback:function(result){ + if(result){ + guardar_deposito(values) + } + } + }) + } @@ -1261,3 +1268,28 @@ function get_invoices_pay(rango){ } }) } + + +function grid_cfdi_por_pagar_on_after_filter(){ + var partner = $$('grid_cfdi_por_pagar').getFilter('cliente').value + var lst = $$('lst_partner_account_bank') + + lst_clear(lst) + if(partner){ + var args = {opt: 'by_name', name: partner} + webix.ajax().get('/socioscb', args, { + error:function(text, data, XmlHttpRequest){ + msg = 'Ocurrio un error, consulta a soporte técnico' + msg_error(msg) + }, + success:function(text, data, XmlHttpRequest){ + var result = data.json() + if (result.ok){ + lst_parse(lst, result.values) + }else{ + msg_error(result.msg) + } + } + }) + } +} diff --git a/source/static/js/controller/main.js b/source/static/js/controller/main.js index 06632bd..a1bf37e 100644 --- a/source/static/js/controller/main.js +++ b/source/static/js/controller/main.js @@ -39,6 +39,7 @@ function configuracion_inicial(){ add_config({'key': 'decimales_precios', 'value': values.decimales_precios}) add_config({'key': 'used_cfdi_pays', 'value': values.pagos}) add_config({'key': 'multi_currency', 'value': values.multi_currency}) + add_config({'key': 'pays_data_bank', 'value': values.pays_data_bank}) }) diff --git a/source/static/js/controller/partners.js b/source/static/js/controller/partners.js index 9c6d329..e6dd2ab 100644 --- a/source/static/js/controller/partners.js +++ b/source/static/js/controller/partners.js @@ -488,7 +488,7 @@ function cmd_partner_add_account_bank_click(){ return } - if(account.cuenta.length < 9){ + if(account.cuenta.length < 10){ msg = 'Longitud incorrecta de la cuenta' msg_error(msg) return diff --git a/source/static/js/controller/util.js b/source/static/js/controller/util.js index e5f2fee..bae66bd 100644 --- a/source/static/js/controller/util.js +++ b/source/static/js/controller/util.js @@ -112,6 +112,11 @@ function show(nombre, value){ } +function show_column(table, column){ + $$(table).showColumn(column) +} + + function enable(nombre, value){ if(value == '0'){ value = false @@ -560,5 +565,16 @@ function pause(milliseconds) { } + //~ Revisado +function lst_clear(lst){ + lst.setValue('') + lst.define('options', []) + lst.refresh() +} + + +function lst_parse(lst, values){ + lst.getList().parse(values) +} diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js index 756bd86..30fd7e7 100644 --- a/source/static/js/ui/admin.js +++ b/source/static/js/ui/admin.js @@ -667,22 +667,6 @@ var options_admin_otros = [ labelRight: 'Mostrar inventario'}, ]}, {maxHeight: 20}, - {template: 'Complementos', type: 'section'}, - {cols: [{maxWidth: 15}, - {view: 'checkbox', id: 'chk_config_ine', labelWidth: 0, - labelRight: 'Usar el complemento INE'}, - {view: 'checkbox', id: 'chk_config_edu', labelWidth: 0, - labelRight: 'Usar el complemento EDU'}, - {}]}, - {cols: [{maxWidth: 15}, - {view: 'checkbox', id: 'chk_config_pagos', labelWidth: 0, - labelRight: 'Usar complemento de pagos'}, - {view: 'text', id: 'txt_config_cfdipay_serie', name: 'txt_config_cfdipay_serie', - label: 'Serie', labelWidth: 50, labelAlign: 'right'}, - {view: 'text', id: 'txt_config_cfdipay_folio', name: 'txt_config_cfdipay_serie', - label: 'Folio', labelWidth: 50, labelAlign: 'right'}, - {}]}, - {maxHeight: 20}, {template: 'Punto de venta', type: 'section'}, {cols: [{maxWidth: 15}, {view: 'checkbox', id: 'chk_usar_punto_de_venta', labelWidth: 0, @@ -723,6 +707,29 @@ var options_admin_partners = [ ] +var options_admin_complements = [ + {maxHeight: 20}, + {cols: [{maxWidth: 15}, + {view: 'checkbox', id: 'chk_config_ine', labelWidth: 0, + labelRight: 'Usar el complemento INE'}, + {view: 'checkbox', id: 'chk_config_edu', labelWidth: 0, + labelRight: 'Usar el complemento EDU'}, + {}]}, + {maxHeight: 20}, + {template: 'Complemento de Pagos', type: 'section'}, + {cols: [{maxWidth: 15}, + {view: 'checkbox', id: 'chk_config_pagos', labelWidth: 0, + labelRight: 'Usar complemento de pagos'}, + {view: 'checkbox', id: 'chk_cfg_pays_data_bank', labelWidth: 0, + labelRight: 'Usar datos bancarios'}, + {view: 'text', id: 'txt_config_cfdipay_serie', name: 'txt_config_cfdipay_serie', + label: 'Serie', labelWidth: 50, labelAlign: 'right'}, + {view: 'text', id: 'txt_config_cfdipay_folio', name: 'txt_config_cfdipay_serie', + label: 'Folio', labelWidth: 50, labelAlign: 'right'}, + {maxWidth: 15}]}, +] + + var tab_options = { view: 'tabview', id: 'tab_options', @@ -732,6 +739,8 @@ var tab_options = { rows: options_templates}}, {header: 'Clientes y Proveedores', body: {id: 'tab_admin_partners', view: 'scrollview', body: {rows: options_admin_partners}}}, + {header: 'Complementos', body: {id: 'tab_admin_complements', + view: 'scrollview', body: {rows: options_admin_complements}}}, {header: 'Otros', body: {id: 'tab_admin_otros', view: 'scrollview', body: {rows: options_admin_otros}}}, ], diff --git a/source/static/js/ui/bancos.js b/source/static/js/ui/bancos.js index 2f804ae..d5aa289 100644 --- a/source/static/js/ui/bancos.js +++ b/source/static/js/ui/bancos.js @@ -64,7 +64,7 @@ var grid_cuentabanco_cols = [ width: 125, format: webix.i18n.priceFormat, css: 'right'}, {id: 'saldo', header: ['Saldo'], width: 125, format: webix.i18n.priceFormat, css: 'right'}, - {id: 'invoice', header: ['FP'], width: 40, css: 'center'}, + {id: 'invoice', header: ['FP'], width: 40, css: 'center', hidden: true}, ] @@ -438,6 +438,10 @@ var controls_banco_deposito = [ ]}, {cols: [ {view: 'label', label: 'Facturas por pagar: '}, + {view: 'richselect', id: 'lst_partner_account_bank', hidden: true, + name: 'partner_account_bank', label: 'Cuenta Origen', required: false, + options: [], labelWidth: 125, labelAlign: 'right'}, + {}, {view: 'button', id: 'cmd_invoice_payed', label: 'Solo marcar pagada', type: 'iconButton', autowidth: true, icon: 'check-circle', tooltip: 'No afecta a saldos'},