diff --git a/source/app/controllers/main.py b/source/app/controllers/main.py
index 8ec2e8f..06ba734 100644
--- a/source/app/controllers/main.py
+++ b/source/app/controllers/main.py
@@ -83,17 +83,13 @@ class AppPartners(object):
def on_post(self, req, resp):
values = req.params
- print ('VALUES', values)
- if values['id'] == '0':
- del values['id']
- req.context['result'] = self._db.new_partner(values)
- else:
- req.context['result'] = self._db.update_partner(values)
+ #~ print ('VALUES', values)
+ req.context['result'] = self._db.partner(values)
resp.status = falcon.HTTP_200
def on_delete(self, req, resp):
values = req.params
- if self._db.delete_partner(values['id']):
+ if self._db.delete('partner', values['id']):
resp.status = falcon.HTTP_200
else:
resp.status = falcon.HTTP_204
diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py
index 398c048..33e841e 100644
--- a/source/app/controllers/util.py
+++ b/source/app/controllers/util.py
@@ -5,20 +5,22 @@ import getpass
import json
import mimetypes
import os
+import re
import sqlite3
+import unicodedata
import uuid
-import bcrypt
+#~ import bcrypt
from settings import log, template_lookup, COMPANIES
-def _get_hash(password):
- return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
+#~ def _get_hash(password):
+ #~ return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
-def validate_password(hashed, password):
- return bcrypt.hashpw(password.encode(), hashed.encode()) == hashed.encode()
+#~ def validate_password(hashed, password):
+ #~ return bcrypt.hashpw(password.encode(), hashed.encode()) == hashed.encode()
def get_pass():
@@ -151,3 +153,14 @@ def parse_con(values):
return con
except IndexError:
return {}
+
+
+def spaces(value):
+ return ' '.join(value.split())
+
+
+def to_slug(string):
+ value = (unicodedata.normalize('NFKD', string)
+ .encode('ascii', 'ignore')
+ .decode('ascii').lower())
+ return value
diff --git a/source/app/main.py b/source/app/main.py
index 65fd108..75fbf11 100644
--- a/source/app/main.py
+++ b/source/app/main.py
@@ -12,13 +12,12 @@ from middleware import (
)
from models.db import StorageEngine
from controllers.main import (
- AppLogin, AppLogout, AppAdmin, AppMain, AppValues
+ AppLogin, AppLogout, AppAdmin, AppMain, AppValues, AppPartners
)
from settings import DEBUG
db = StorageEngine()
-#~ partners = AppPartners(db)
api = falcon.API(
middleware=[AuthMiddleware(), JSONTranslator(), ConnectionMiddleware()])
@@ -30,8 +29,7 @@ api.add_route('/logout', AppLogout(db))
api.add_route('/admin', AppAdmin(db))
api.add_route('/main', AppMain(db))
api.add_route('/values/{table}', AppValues(db))
-
-#~ api.add_route('/partners', partners)
+api.add_route('/partners', AppPartners(db))
if DEBUG:
diff --git a/source/app/models/db.py b/source/app/models/db.py
index cae1d5a..eddcf3b 100644
--- a/source/app/models/db.py
+++ b/source/app/models/db.py
@@ -20,11 +20,20 @@ class StorageEngine(object):
def _get_formapago(self, values):
return main.SATFormaPago.get_activos()
- def get_partners(self, values):
- return main.get_partners(values)
+ def delete(self, table, id):
+ if table == 'partner':
+ return main.Socios.remove(id)
+ return False
- def new_partner(self, values):
- return main.new_partner(values)
+ def get_partners(self, values):
+ return main.Socios.get(values)
+
+ def partner(self, values):
+ id = int(values['id'])
+ del values['id']
+ if id:
+ return main.Socios.update(values, id)
+ return main.Socios.add(values)
def update_partner(self, values):
id = int(values['id'])
@@ -42,10 +51,6 @@ class StorageEngine(object):
data = {'ok': True, 'row': row, 'new': False}
return data
- def delete_partner(self, id):
- q = Clients.delete().where(Clients.id==id)
- return bool(q.execute())
-
diff --git a/source/app/models/main.py b/source/app/models/main.py
index ecac5f2..fd73192 100644
--- a/source/app/models/main.py
+++ b/source/app/models/main.py
@@ -216,7 +216,7 @@ class SATFormaPago(BaseModel):
def get_activos(cls):
rows = (SATFormaPago
.select(
- SATFormaPago.key.alias('id'),
+ SATFormaPago.id,
SATFormaPago.name.alias('value'))
.where(SATFormaPago.activo==True)
.dicts()
@@ -290,9 +290,11 @@ class Addendas(BaseModel):
class Socios(BaseModel):
+ tipo_persona = IntegerField(default=1)
rfc = TextField(index=True)
nombre = TextField(index=True)
- nombre_comercial = TextField(index=True)
+ slug = TextField(default='')
+ nombre_comercial = TextField(index=True, default='')
calle = TextField(default='')
no_exterior = TextField(default='')
no_interior = TextField(default='')
@@ -304,8 +306,6 @@ class Socios(BaseModel):
notas = TextField(default='')
telefonos = TextField(default='')
es_activo = BooleanField(default=True)
- es_moral = BooleanField(default=False)
- es_extranjero = BooleanField(default=False)
es_ong = BooleanField(default=False)
fecha_alta = DateField(default=util.now)
dias_pago = IntegerField(default=0)
@@ -328,9 +328,59 @@ class Socios(BaseModel):
class Meta:
order_by = ('nombre',)
indexes = (
- (('rfc', 'nombre'), True),
+ (('rfc', 'slug'), True),
)
+ @classmethod
+ def get(cls, values):
+ if values:
+ id = int(values['id'])
+ row = Socios.select().where(Socios.id==id).dicts()[0]
+ return row
+
+ rows = Socios.select(Socios.id, Socios.rfc, Socios.nombre).dicts()
+ return {'ok': True, 'rows': tuple(rows)}
+
+ @classmethod
+ def add(cls, values):
+ fields = util.clean(values)
+ fields['rfc'] = fields['rfc'].upper()
+ fields['nombre'] = util.spaces(fields['nombre'])
+ fields['slug'] = util.to_slug(fields['nombre'])
+ fb = ('dias_habiles', 'es_activo', 'es_cliente',
+ 'es_proveedor', 'es_ong')
+ for name in fb:
+ fields[name] = bool(fields[name].replace('0', ''))
+
+ try:
+ obj = Socios.create(**fields)
+ except IntegrityError:
+ msg = 'Ya existe el RFC y Razón Social'
+ data = {'ok': False, 'row': {}, 'new': True, 'msg': msg}
+ return data
+
+ #~ ToDo Agregar Condicion de pago y tags
+
+ row = {
+ 'id': obj.id,
+ 'rfc': obj.rfc,
+ 'nombre': obj.nombre,
+ }
+ data = {'ok': True, 'row': row, 'new': True}
+ return data
+
+ @classmethod
+ def remove(cls, id):
+ count = (Facturas
+ .select(fn.COUNT(Facturas.id)).join(Socios)
+ .where(Socios.id==id)
+ .count())
+ if count:
+ return False
+
+ q = Socios.delete().where(Socios.id==id)
+ return bool(q.execute())
+
class Productos(BaseModel):
categoria = ForeignKeyField(Categorias, null=True)
@@ -453,30 +503,6 @@ def authenticate(args):
return respuesta
-def get_partners(values):
- if values:
- id = int(values['id'])
- row = Clients.select().where(Clients.id==id).dicts()[0]
- return row
-
- rows = Clients.select(Clients.id, Clients.rfc, Clients.name).dicts()
- return {'ok': True, 'rows': tuple(rows)}
-
-
-def new_partner(values):
- fields = util.clean(values)
- fields['rfc'] = fields['rfc'].upper()
- obj = Clients.create(**fields)
- row = {
- 'id': obj.id,
- 'cia': obj.cia,
- 'rfc': obj.rfc,
- 'name': obj.name,
- }
- data = {'ok': True, 'row': row, 'new': True}
- return data
-
-
def get_cp(cp):
con = sqlite3.connect(PATH_CP)
cursor = con.cursor()
diff --git a/source/static/js/controller/main.js b/source/static/js/controller/main.js
index 63d2946..f726fd2 100644
--- a/source/static/js/controller/main.js
+++ b/source/static/js/controller/main.js
@@ -23,6 +23,7 @@ var controllers = {
$$("es_cliente").attachEvent( "onChange", is_client_change)
$$("es_proveedor").attachEvent( "onChange", is_supplier_change)
$$("rfc").attachEvent( "onBlur", rfc_lost_focus)
+ $$('multi').attachEvent('onViewChange', multi_change)
//~ Products
$$("cmd_new_product").attachEvent("onItemClick", cmd_new_product_click);
$$("cmd_edit_product").attachEvent("onItemClick", cmd_edit_product_click);
@@ -61,3 +62,14 @@ function menu_user_click(id, e, node){
return
}
}
+
+
+function multi_change(prevID, nextID){
+ //~ webix.message(prevID)
+ if(nextID == 'app_partners'){
+ active = $$('multi_partners').getActiveId()
+ if(active == 'partners_home'){
+ get_partners()
+ }
+ }
+}
diff --git a/source/static/js/controller/partners.js b/source/static/js/controller/partners.js
index 390d8c1..892619d 100644
--- a/source/static/js/controller/partners.js
+++ b/source/static/js/controller/partners.js
@@ -6,6 +6,7 @@ function cmd_new_partner_click(id, e, node){
$$('forma_pago').getList().load('/values/formapago')
$$('grid_partners').clearSelection()
$$('multi_partners').setValue('partners_new')
+ $$('tab_partner').setValue('Datos Fiscales')
};
@@ -16,36 +17,46 @@ function cmd_new_contact_click(id, e, node){
function cmd_edit_partner_click(id, e, node){
- var row = $$('grid_partners').getSelectedItem();
+ var msg = ''
+ var row = $$('grid_partners').getSelectedItem()
+
if (row == undefined){
- webix.message({ type:'error', text:'Selecciona un Cliente' });
+ msg = 'Selecciona un Socio de Negocio'
+ webix.message({type:'error', text: msg})
return
- };
+ }
webix.ajax().get("/partners", {id:row['id']}, {
error: function(text, data, xhr) {
- webix.message({ type:"error", text: "Error al consultar"});
+ webix.message({type:"error", text: "Error al consultar"})
},
success: function(text, data, xhr){
var values = data.json();
- $$('form_partner').setValues(values);
+ $$('form_partner').setValues(values)
+ $$('forma_pago').getList().load('/values/formapago')
}
- });
+ })
- $$("multi_partners").setValue("partners_new")
+ $$('multi_partners').setValue('partners_new')
+ $$('tab_partner').setValue('Datos Fiscales')
};
function cmd_delete_partner_click(id, e, node){
- var row = $$('grid_partners').getSelectedItem();
- if (row == undefined){
- webix.message({ type:'error', text:'Selecciona un Cliente' });
- return
- };
+ var msg = ''
+ var row = $$('grid_partners').getSelectedItem()
- var msg = '¿Estás seguro de eliminar al cliente?
'
- msg += row['name'] + ' (' + row['rfc'] + ')'
- msg += '
ESTA ACCIÓN NO SE PUEDE DESHACER'
+ if (row == undefined){
+ msg = 'Selecciona un Cliente o Proveedor'
+ webix.message({type:'error', text: msg})
+ return
+ }
+
+ msg = '¿Estás seguro de eliminar al cliente?
'
+ msg += row['nombre'] + ' (' + row['rfc'] + ')'
+ msg += '
ESTA ACCIÓN NO SE PUEDE DESHACER
'
+ msg += 'Solo se pueden eliminar clientes o proveedores sin documentos '
+ msg += 'relacionados. Se recomienda solo desactivar en vez de eliminar'
webix.confirm({
title:'Eliminar Cliente',
ok:'Si',
@@ -62,28 +73,37 @@ function cmd_delete_partner_click(id, e, node){
function delete_partner(id){
- webix.ajax().del('/partners', {id:id}, function(text, xml, xhr){
- var msg = 'Cliente eliminado correctamente'
+ webix.ajax().del('/partners', {id: id}, function(text, xml, xhr){
+ var msg = 'Socio eliminado correctamente'
if (xhr.status == 200){
$$('grid_partners').remove(id);
- webix.message({type:'success', text:msg});
+ webix.message({type: 'success', text: msg})
} else {
- msg = 'No se pudo eliminar'
- webix.message({type:'error', text:msg});
+ msg = 'No se pudo eliminar. Asegurate de que no tenga documentos relacionados'
+ webix.message({type: 'error', text: msg})
}
- });
+ })
}
function cmd_save_partner_click(id, e, node){
+ var msg = 'Valores inválidos'
var form = this.getFormView();
if (!form.validate()) {
- webix.message({ type:'error', text:'Valores inválidos'})
+ webix.message({type: 'error', text: msg})
return
}
var values = form.getValues();
+
+ if (!values.es_cliente && !values.es_proveedor){
+ msg = 'Selecciona si es cliente, proveedor o ambos'
+ webix.message({type: 'error', text: msg})
+ $$('tab_partner').setValue('Otros Datos')
+ return
+ }
+
webix.ajax().post('/partners', values, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico';
@@ -97,9 +117,9 @@ function cmd_save_partner_click(id, e, node){
webix.message({type:'error', text:values.msg});
}
}
- });
+ })
-};
+}
function update_grid_partner(values){
@@ -263,3 +283,9 @@ function rfc_lost_focus(prev_view){
//~ }
//~ })
}
+
+
+function multi_partners_change(prevID, nextID){
+ webix.message(prevID)
+ webix.message(nextID)
+}
diff --git a/source/static/js/ui/partners.js b/source/static/js/ui/partners.js
index a424be0..358f7d1 100644
--- a/source/static/js/ui/partners.js
+++ b/source/static/js/ui/partners.js
@@ -11,13 +11,12 @@ var toolbar_partners = [
var grid_partners_cols = [
- {id: 'index', header:'#', adjust:'data', css:'right',
- footer: {content: 'rowCount'}},
- {id: 'id', header: 'Clave', adjust:'data', sort: 'int', css: 'right',
- footer: 'Clientes'},
+ {id: 'index', header:'#', adjust:'data', css: 'right',
+ footer: {content: 'rowCount', colspan: 2, css: 'right'}},
+ {id: 'id', header: 'Clave', adjust:'data', sort: 'int', css: 'right'},
{id: 'rfc', header: ['RFC', {content: 'textFilter'}], adjust:'data',
- sort: 'string'},
- {id: 'name', header: ['Razón Social', {content: 'textFilter'}],
+ sort: 'string', footer: {text: 'Clientes y Proveedores', colspan: 2}},
+ {id: 'nombre', header: ['Razón Social', {content: 'textFilter'}],
fillspace:true, sort: 'string'},
]
@@ -38,9 +37,6 @@ var grid_partners = {
})
}
},
- //~ onClick:{
- //~ cmd_edit_parter: cmd_edit_partner_click,
- //~ },
}
@@ -83,10 +79,12 @@ var controls_fiscales = [
label: 'Condiciones de Pago: '},
]},
{cols: [
- {view: 'counter', name: 'dias_pago', label: 'Días de pago', step:5,
- value: 0, min: 0, max: 365, tooltip: 'Permite calcular las fechas de pago'},
- {view: 'checkbox', id: 'chk_business_days', name: 'dias_habiles',
- label: 'Hábiles: ', value: false},
+ {view: 'counter', id: 'dias_pago', name: 'dias_pago',
+ label: 'Días de pago', step: 5, value: 0, min: 0, max: 365,
+ tooltip: 'Permite calcular las fechas de pago', width: 250},
+ {view: 'checkbox', id: 'dias_habiles', name: 'dias_habiles',
+ label: 'Hábiles: ', value: false, width: 180},
+ {},
]}
]
@@ -256,6 +254,7 @@ var multi_contacts = {
var controls_partner = [
{
view: 'tabview',
+ id: 'tab_partner',
tabbar: {options: ['Datos Fiscales', 'Otros Datos', 'Contactos']}, animate: true,
cells: [
{id: 'Datos Fiscales', rows: controls_fiscales},