diff --git a/CHANGELOG.md b/CHANGELOG.md
index 172a404..108a56d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,9 @@
-v 1.20.0 [04-oct-2018]
+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.
v 1.19.1 [03-oct-2018]
diff --git a/docs/empresalibre/docs/notas.md b/docs/empresalibre/docs/notas.md
index 3380f94..a16e9e0 100644
--- a/docs/empresalibre/docs/notas.md
+++ b/docs/empresalibre/docs/notas.md
@@ -6,8 +6,11 @@ siempre actualizado.** Solo se da soporte sobre la ultima versión de **Empresa
Libre**.
-### 1.20.0 [04-oct-2018]
+### 1.20.0 [08-oct-2018]
- Error [#295](https://gitlab.com/mauriciobaeza/empresa-libre/issues/295)
+- Mejora - Cuentas de banco para clientes
+
+* IMPORTANTE: Es necesario realizar una migración, despues de actualizar la rama principal.
### 1.19.1 [03-oct-2018]
diff --git a/source/app/controllers/main.py b/source/app/controllers/main.py
index 69ed5e5..41a169c 100644
--- a/source/app/controllers/main.py
+++ b/source/app/controllers/main.py
@@ -550,13 +550,29 @@ class AppSATBancos(object):
def __init__(self, db):
self._db = db
- # ~ def on_get(self, req, resp):
- # ~ values = req.params
- # ~ req.context['result'] = self._db.get_sat_bancos(values)
- # ~ resp.status = falcon.HTTP_200
+ def on_get(self, req, resp):
+ values = req.params
+ req.context['result'] = self._db.get_satbancos(values)
+ resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.satbancos(values)
resp.status = falcon.HTTP_200
+
+class AppSociosCuentasBanco(object):
+
+ def __init__(self, db):
+ self._db = db
+
+ def on_get(self, req, resp):
+ values = req.params
+ req.context['result'] = self._db.get_partners_accounts_bank(values)
+ resp.status = falcon.HTTP_200
+
+ def on_post(self, req, resp):
+ values = req.params
+ req.context['result'] = self._db.partners_accounts_bank(values)
+ resp.status = falcon.HTTP_200
+
diff --git a/source/app/main.py b/source/app/main.py
index 87352e9..66298f2 100644
--- a/source/app/main.py
+++ b/source/app/main.py
@@ -17,7 +17,7 @@ from controllers.main import (AppEmpresas,
AppMain, AppValues, AppPartners, AppProducts, AppInvoices, AppFolios,
AppDocumentos, AppFiles, AppPreInvoices, AppCuentasBanco,
AppMovimientosBanco, AppTickets, AppStudents, AppEmployees, AppNomina,
- AppInvoicePay, AppCfdiPay, AppSATBancos
+ AppInvoicePay, AppCfdiPay, AppSATBancos, AppSociosCuentasBanco
)
@@ -59,6 +59,7 @@ api.add_route('/nomina', AppNomina(db))
api.add_route('/invoicepay', AppInvoicePay(db))
api.add_route('/cfdipay', AppCfdiPay(db))
api.add_route('/satbancos', AppSATBancos(db))
+api.add_route('/socioscb', AppSociosCuentasBanco(db))
# ~ Activa si usas waitress y NO estas usando servidor web
diff --git a/source/app/models/db.py b/source/app/models/db.py
index b1ff1f7..45a8108 100644
--- a/source/app/models/db.py
+++ b/source/app/models/db.py
@@ -436,6 +436,12 @@ class StorageEngine(object):
def get_cfdipay(self, values):
return main.CfdiPagos.get_values(values)
+ def get_satbancos(self, values):
+ return main.SATBancos.get_values(values)
+
+ def get_partners_accounts_bank(self, values):
+ return main.SociosCuentasBanco.get_values(values)
+
def cfdipay(self, values):
return main.CfdiPagos.post(values)
@@ -444,3 +450,6 @@ class StorageEngine(object):
def satbancos(self, values):
return main.SATBancos.post(values)
+
+ def partners_accounts_bank(self, values):
+ return main.SociosCuentasBanco.post(values)
diff --git a/source/app/models/main.py b/source/app/models/main.py
index 0f2daca..7a9153f 100644
--- a/source/app/models/main.py
+++ b/source/app/models/main.py
@@ -1536,6 +1536,21 @@ class SATBancos(BaseModel):
opt = values.pop('opt')
return getattr(cls, '_{}'.format(opt))(cls, values)
+ @classmethod
+ def get_values(cls, values):
+ opt = values.pop('opt')
+ return getattr(cls, '_get_{}'.format(opt))(cls, values)
+
+ def _get_active(cls, values):
+ rows = (SATBancos
+ .select(
+ SATBancos.id,
+ SATBancos.name.alias('value'))
+ .where(SATBancos.activo==True)
+ .dicts()
+ )
+ return tuple(rows)
+
@classmethod
def get_(cls):
rows = SATBancos.select().dicts()
@@ -1575,6 +1590,16 @@ class SATBancos(BaseModel):
log.error(msg)
return
+ @classmethod
+ def get_by_name(cls, name):
+ try:
+ obj = SATBancos.get(SATBancos.name==name)
+ return obj
+ except SATBancos.DoesNotExist:
+ msg = 'SATBancos no existe: {}'.format(key)
+ log.error(msg)
+ return
+
class SATNivelesEducativos(BaseModel):
name = TextField(index=True)
@@ -2697,6 +2722,73 @@ class Socios(BaseModel):
return {'ok': False}
+class SociosCuentasBanco(BaseModel):
+ socio = ForeignKeyField(Socios)
+ banco = ForeignKeyField(SATBancos)
+ cuenta = TextField(default='')
+ clabe = TextField(default='')
+ moneda = ForeignKeyField(SATMonedas, null=True)
+
+ class Meta:
+ order_by = ('socio', 'banco', 'cuenta')
+ indexes = (
+ (('socio', 'banco', 'cuenta'), True),
+ )
+
+ 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_partner(self, values):
+ id = int(values['id_partner'])
+ rows = (SociosCuentasBanco.select(
+ SociosCuentasBanco.id,
+ SQL(" '-' AS delete"),
+ SATBancos.name.alias('banco'),
+ SociosCuentasBanco.cuenta,
+ SociosCuentasBanco.clabe)
+ .join(SATBancos).switch(SociosCuentasBanco)
+ .where(SociosCuentasBanco.socio==id)
+ .dicts())
+ return tuple(rows)
+
+ @classmethod
+ def post(cls, values):
+ opt = values.pop('opt')
+ return getattr(cls, '_{}'.format(opt))(cls, values)
+
+ def _new(self, values):
+ values = util.loads(values['values'])
+ bank = SATBancos.get_by_name(values['banco'])
+ fields = {
+ 'socio': values['id_partner'],
+ 'banco': bank,
+ 'cuenta': values['cuenta'],
+ 'clabe': values['clabe'],
+ }
+ try:
+ obj = SociosCuentasBanco.create(**fields)
+ except IntegrityError as e:
+ msg = 'Ya existe esta cuenta'
+ data = {'ok': False, 'msg': msg}
+ return data
+
+ msg = 'Cuenta de banco agregada correctamente'
+ data = {'ok': True, 'id': obj.id, 'msg': msg}
+ return data
+
+ def _delete(self, values):
+ values = util.loads(values['values'])
+ id = int(values['id'])
+ q = SociosCuentasBanco.delete().where(SociosCuentasBanco.id==id)
+ result = bool(q.execute())
+ msg = 'Cuenta borrada correctamente'
+ return {'ok': result, 'msg': msg}
+
class Contactos(BaseModel):
socio = ForeignKeyField(Socios)
@@ -8123,8 +8215,9 @@ def _crear_tablas(rfc):
SATOrigenRecurso, SATTipoContrato, SATTipoDeduccion, SATTipoHoras,
SATTipoIncapacidad, SATTipoJornada, SATTipoNomina, SATTipoOtroPago,
SATTipoPercepcion, SATTipoRegimen,
- Socios, Contactos, ContactoCorreos, ContactoDirecciones, Empleados,
- ContactoTelefonos, Departamentos, Puestos,
+ Socios, SociosCuentasBanco, Contactos, ContactoCorreos,
+ ContactoDirecciones, Empleados, ContactoTelefonos, Departamentos,
+ Puestos,
Tags, Roles, Usuarios, CuentasBanco, TipoCambio, MovimientosBanco,
TipoCorreo, TipoDireccion, TipoPariente, TipoResponsable, TipoTelefono,
TipoTitulo, TipoMovimientoAlumno, TipoMovimientoAlmacen,
@@ -8190,7 +8283,8 @@ def _migrate_tables(rfc=''):
CfdiNominaHorasExtra, CfdiNominaIncapacidad, CfdiNominaJubilacion,
CfdiNominaOtroPago, CfdiNominaOtros, CfdiNominaPercepciones,
CfdiNominaRelacionados, CfdiNominaSeparacion, CfdiNominaSubcontratos,
- CfdiNominaTotales, SATNivelesEducativos, Roles, Permisos
+ CfdiNominaTotales, SATNivelesEducativos, Roles, Permisos,
+ SociosCuentasBanco
]
log.info('Creando tablas nuevas...')
database_proxy.create_tables(tablas, True)
diff --git a/source/static/js/controller/partners.js b/source/static/js/controller/partners.js
index 8376708..611f275 100644
--- a/source/static/js/controller/partners.js
+++ b/source/static/js/controller/partners.js
@@ -21,12 +21,12 @@ var cfg_partners = new Object()
var partners_controllers = {
init: function(){
$$('cmd_new_partner').attachEvent('onItemClick', cmd_new_partner_click);
- $$('cmd_new_contact').attachEvent('onItemClick', cmd_new_contact_click);
+ //~ $$('cmd_new_contact').attachEvent('onItemClick', cmd_new_contact_click);
$$('cmd_edit_partner').attachEvent('onItemClick', cmd_edit_partner_click);
$$('cmd_delete_partner').attachEvent('onItemClick', cmd_delete_partner_click);
$$('cmd_save_partner').attachEvent('onItemClick', cmd_save_partner_click);
$$('cmd_cancel_partner').attachEvent('onItemClick', cmd_cancel_partner_click);
- $$('cmd_cancel_contact').attachEvent('onItemClick', cmd_cancel_contact_click);
+ //~ $$('cmd_cancel_contact').attachEvent('onItemClick', cmd_cancel_contact_click);
//~ $$('cmd_partner_zero').attachEvent('onItemClick', cmd_partner_zero_click);
$$('codigo_postal').attachEvent('onKeyPress', postal_code_key_press);
$$('codigo_postal').attachEvent('onTimedKeyPress', postal_code_key_up);
@@ -40,6 +40,8 @@ var partners_controllers = {
//~ $$('grid_partners').attachEvent('onSelectChange', grid_partners_on_select_change)
$$('partner_balance').attachEvent('onChange', partner_balance_on_change)
+ $$('cmd_partner_add_account_bank').attachEvent('onItemClick', cmd_partner_add_account_bank_click)
+ $$('grid_partner_account_bank').attachEvent('onItemClick', grid_partner_account_bank_click)
default_config_partners()
}
}
@@ -89,6 +91,8 @@ function cmd_new_partner_click(id, e, node){
query = table_usocfdi.chain().find({fisica: true}).data()
$$('lst_uso_cfdi_socio').getList().parse(query)
$$('partner_balance').define('readonly', !cfg_partners['chk_config_change_balance_partner'])
+ get_partner_banks()
+ get_partner_accounts_bank(0)
}
@@ -136,12 +140,14 @@ function cmd_edit_partner_click(){
if(values.es_proveedor){
$$('cuenta_proveedor').enable()
}
+ get_partner_accounts_bank(row['id'])
}
})
$$('multi_partners').setValue('partners_new')
$$('tab_partner').setValue('Datos Fiscales')
-};
+ get_partner_banks()
+}
function cmd_delete_partner_click(id, e, node){
@@ -387,57 +393,6 @@ function is_supplier_change(new_value, old_value){
}
-//~ function partner_reset_saldo(id){
- //~ webix.ajax().post('/partners', {opt: 'reset', id: id}, {
- //~ error:function(text, data, XmlHttpRequest){
- //~ msg = 'Ocurrio un error, consulta a soporte técnico';
- //~ msg_error(msg)
- //~ },
- //~ success:function(text, data, XmlHttpRequest){
- //~ var values = data.json();
- //~ if(values.ok){
- //~ msg = 'Saldo actualizado correctamente'
- //~ $$('grid_partners').updateItem(id, {saldo_cliente: 0.0})
- //~ $$('cmd_partner_zero').disable()
- //~ msg_ok(msg)
- //~ }
- //~ }
- //~ })
-//~ }
-
-
-//~ function cmd_partner_zero_click(){
- //~ var g = $$('grid_partners')
- //~ var row = g.getSelectedItem()
- //~ var saldo = row.saldo_cliente.to_float()
-
- //~ if(saldo){
- //~ msg = '¿Estas seguro de poner en cero el saldo del cliente?
'
- //~ msg += 'ESTA ACCIÓN NO SE PUEDE DESHACER'
- //~ webix.confirm({
- //~ title: 'Saldo Cliente',
- //~ ok: 'Si',
- //~ cancel: 'No',
- //~ type: 'confirm-error',
- //~ text: msg,
- //~ callback:function(result){
- //~ if (result){
- //~ partner_reset_saldo(row.id)
- //~ }
- //~ }
- //~ })
- //~ }else{
- //~ $$('cmd_partner_zero').disable()
- //~ }
-//~ }
-
-
-//~ function grid_partners_on_select_change(){
- //~ $$('cmd_partner_zero').enable()
-//~ }
-
-
-
function rfc_lost_focus(prev_view){
//~ var form = this.getFormView()
//~ var values = form.getValues()
@@ -493,3 +448,162 @@ function partner_balance_on_change(new_value, old_value){
this.refresh()
}
}
+
+
+function cmd_partner_add_account_bank_click(){
+ var form = $$('form_partner_account_bank')
+
+ if (!form.validate()){
+ msg = 'Valores inválidos'
+ msg_error(msg)
+ return
+ }
+
+ var values = form.getValues()
+ var id_partner = $$('form_partner').getValues().id
+
+ var account = {
+ id_partner: id_partner,
+ delete: '-',
+ banco: $$('lst_partner_bank').getText(),
+ cuenta: values.partner_account.trim(),
+ clabe: values.partner_clabe.trim(),
+ }
+
+ if(!account.cuenta){
+ msg = 'La cuenta es requerida'
+ msg_error(msg)
+ return
+ }
+
+ if(!account.cuenta.is_number()){
+ msg = 'Solo digitos en la cuenta'
+ msg_error(msg)
+ return
+ }
+
+ if(account.cuenta.length < 9){
+ msg = 'Longitud incorrecta de la cuenta'
+ msg_error(msg)
+ return
+ }
+
+ if(!account.clabe){
+ msg = 'La CLABE es requerida'
+ msg_error(msg)
+ return
+ }
+
+ if(account.clabe.length != 18){
+ msg = 'La CLABE debe ser de 18 digitos'
+ msg_error(msg)
+ return
+ }
+
+ if(!account.clabe.is_number()){
+ msg = 'Solo digitos en la CLABE'
+ msg_error(msg)
+ return
+ }
+
+ var grid = $$('grid_partner_account_bank')
+
+ if(id_partner){
+ partner_new_account_bank(account, grid)
+ }else{
+ grid.add(account)
+ }
+
+ form.setValues({})
+}
+
+
+function get_partner_banks(){
+ webix.ajax().get('/satbancos', {opt: 'active'}, function(text, data){
+ var values = data.json()
+ $$('lst_partner_bank').getList().parse(values)
+ })
+}
+
+
+function partner_new_account_bank(account, grid){
+ webix.ajax().post('/socioscb', {opt: 'new', values: account}, {
+ error: function(text, data, xhr) {
+ msg = 'Error al guardar'
+ msg_error(msg)
+ },
+ success: function(text, data, xhr) {
+ var values = data.json()
+ if(values.ok){
+ account['id'] = values.id
+ grid.add(account)
+ msg_ok(values.msg)
+ }else{
+ msg_error(values.msg)
+ }
+ }
+ })
+}
+
+
+function get_partner_accounts_bank(id_partner){
+ var grid = $$('grid_partner_account_bank')
+ grid.clearAll()
+
+ if(id_partner){
+ var data = {opt: 'by_partner', id_partner: id_partner}
+ webix.ajax().get('/socioscb', data, {
+ error: function(text, data, xhr) {
+ msg = 'Error al consultar'
+ msg_error(msg)
+ },
+ success: function(text, data, xhr) {
+ var values = data.json()
+ grid.parse(values)
+ }
+ })
+ }
+}
+
+
+function grid_partner_account_bank_click(id, e, node){
+ if(id.column != 'delete'){
+ return
+ }
+
+ var msg = '¿Estás seguro de eliminar la cuenta de banco seleccionada?
'
+ msg += 'ESTA ACCION NO SE PUEDE DESHACER'
+ webix.confirm({
+ title: 'Eliminar cuenta de banco',
+ ok: 'Si',
+ cancel: 'No',
+ type: 'confirm-error',
+ text: msg,
+ callback:function(result){
+ if (result){
+ partner_delete_account_bank(id.row)
+ }
+ }
+ })
+}
+
+
+function partner_delete_account_bank(row){
+ var grid = $$('grid_partner_account_bank')
+
+ webix.ajax().post('/socioscb', {opt: 'delete', values: {id: row}}, {
+ error: function(text, data, xhr) {
+ msg = 'Error al eliminar'
+ msg_error(msg)
+ },
+ success: function(text, data, xhr) {
+ var values = data.json()
+ if(values.ok){
+ grid.remove(row)
+ msg_ok(values.msg)
+ }else{
+ msg_error(values.msg)
+ }
+ }
+ })
+}
diff --git a/source/static/js/ui/partners.js b/source/static/js/ui/partners.js
index 4a059d7..d7aeab2 100644
--- a/source/static/js/ui/partners.js
+++ b/source/static/js/ui/partners.js
@@ -165,6 +165,50 @@ var controls_others = [
]
+var grid_partner_account_bank_cols = [
+ {id: 'id', header: 'ID', hidden: true},
+ {id: 'delete', header: '', width: 30, css: 'delete'},
+ {id: 'banco', header: 'Banco', fillspace: 1},
+ {id: 'cuenta', header: 'Cuenta', fillspace: 1},
+ {id: 'clabe', header: 'CLABE', fillspace: 1},
+ //~ {id: 'moneda', header: 'Moneda', fillspace: 1},
+]
+
+
+var grid_partner_account_bank = {
+ view: 'datatable',
+ id: 'grid_partner_account_bank',
+ select: 'row',
+ adjust: true,
+ autoheight: true,
+ columns: grid_partner_account_bank_cols,
+}
+
+
+var controls_partner_bank = [
+ {template: 'Agregar cuenta de banco', type: 'section'},
+ {view: 'form', id: 'form_partner_account_bank', rows: [
+ {cols: [
+ {view: 'richselect', id: 'lst_partner_bank', name: 'partner_bank',
+ label: 'Banco: ', required: true, options: []},
+ {view: 'text', id: 'partner_account', name: 'partner_account',
+ label: 'Cuenta: ', required: true},
+ {view: 'text', id: 'partner_clabe', name: 'partner_clabe',
+ label: 'CLABE: ', required: true},
+ ]},
+ {minHeight: 10},
+ {cols: [{},
+ {view: 'button', id: 'cmd_partner_add_account_bank', maxWidth: 200,
+ label: 'Agregar cuenta'},
+ {}]},
+ ],
+ },
+ {minHeight: 20, maxHeight: 20},
+ {template: 'Cuentas de banco existentes', type: 'section'},
+ grid_partner_account_bank,
+ {minHeight: 50},
+]
+
var toolbar_contacts = [
{view: 'button', id: 'cmd_new_contact', label: 'Nuevo', type: 'iconButton',
@@ -302,11 +346,12 @@ var controls_partner = [
{
view: 'tabview',
id: 'tab_partner',
- tabbar: {options: ['Datos Fiscales', 'Otros Datos', 'Contactos']}, animate: true,
+ tabbar: {ptions: ['Datos Fiscales', 'Otros Datos', 'Cuentas de Banco']},
+ animate: true,
cells: [
{id: 'Datos Fiscales', rows: controls_fiscales},
{id: 'Otros Datos', rows: controls_others},
- {id: 'Contactos', rows: [multi_contacts]},
+ {id: 'Cuentas de Banco', rows: controls_partner_bank}
]
},
{rows: [