diff --git a/source/app/models/db.py b/source/app/models/db.py
index ea6fe5c..d3fab7e 100644
--- a/source/app/models/db.py
+++ b/source/app/models/db.py
@@ -131,7 +131,7 @@ class StorageEngine(object):
return main.Emisor.get_regimenes()
def _get_usocfdi(self, values):
- return main.SATUsoCfdi.get_activos(values)
+ return main.SATUsoCfdi.get_activos()
def delete(self, table, id):
if table == 'partner':
@@ -191,6 +191,9 @@ class StorageEngine(object):
def _get_timbrar(self, values):
return main.Facturas.timbrar(int(values['id']))
+ def _get_anticipoegreso(self, values):
+ return main.Facturas.anticipo_egreso(int(values['id']))
+
def get_emisor(self, rfc):
return main.Emisor.get_(rfc)
diff --git a/source/app/models/main.py b/source/app/models/main.py
index de7f418..90f8429 100644
--- a/source/app/models/main.py
+++ b/source/app/models/main.py
@@ -910,7 +910,7 @@ class CuentasBanco(BaseModel):
.join(SATMonedas).switch(CuentasBanco)
.where(CuentasBanco.id==obj.id).dicts()
)
- data = {'ok': True, 'row': row[0]}
+ data = {'ok': True, 'row': rows[0]}
return data
@@ -932,13 +932,16 @@ class SATUsoCfdi(BaseModel):
return 'Uso del CFDI: {} ({})'.format(self.name, self.key)
@classmethod
- def get_activos(cls, values):
- field = SATUsoCfdi.id
- if values:
- field = SATUsoCfdi.key.alias('id')
+ def get_id(self, key):
+ if key is None:
+ return
+ return SATUsoCfdi.get(SATUsoCfdi.key==key).id
+
+ @classmethod
+ def get_activos(cls):
rows = (SATUsoCfdi
.select(
- field,
+ SATUsoCfdi.key.alias('id'),
SATUsoCfdi.name.alias('value'),
SATUsoCfdi.fisica,
SATUsoCfdi.moral,
@@ -1009,7 +1012,8 @@ class Socios(BaseModel):
fields['rfc'] = fields['rfc'].upper()
fields['nombre'] = util.spaces(fields['nombre'])
fields['slug'] = util.to_slug(fields['nombre'])
- fields['uso_cfdi'] = fields.pop('uso_cfdi_socio', None)
+ uso_cfdi = fields.pop('uso_cfdi_socio', None)
+ fields['uso_cfdi'] = SATUsoCfdi.get_id(uso_cfdi)
fields['condicion_pago'] = \
CondicionesPago.get_or(fields.get('condicion_pago', None))
@@ -1030,7 +1034,14 @@ class Socios(BaseModel):
str(CondicionesPago.get(id=row['condicion_pago']))
return row
- rows = Socios.select(Socios.id, Socios.rfc, Socios.nombre).dicts()
+ rows = (Socios
+ .select(
+ Socios.id,
+ Socios.rfc,
+ Socios.nombre,
+ Socios.saldo_cliente)
+ .dicts()
+ )
return {'ok': True, 'rows': tuple(rows)}
@classmethod
@@ -1047,7 +1058,6 @@ class Socios(BaseModel):
.where((Socios.id==id) & (Socios.es_cliente==True))
.dicts()
)
- #~ print (id, row)
if len(row):
return {'ok': True, 'row': row[0]}
return {'ok': False}
@@ -1077,12 +1087,13 @@ class Socios(BaseModel):
data = {'ok': False, 'row': {}, 'new': True, 'msg': msg}
return data
- #~ ToDo Agregar Condicion de pago y tags
+ #~ ToDo Agregar tags
row = {
'id': obj.id,
'rfc': obj.rfc,
'nombre': obj.nombre,
+ 'saldo_cliente': obj.saldo_cliente,
}
data = {'ok': True, 'row': row, 'new': True}
return data
@@ -1091,7 +1102,6 @@ class Socios(BaseModel):
def actualizar(cls, values, id):
fields = cls._clean(cls, values)
try:
- #~ print (fields)
q = Socios.update(**fields).where(Socios.id==id)
q.execute()
except IntegrityError:
@@ -1346,6 +1356,7 @@ class Facturas(BaseModel):
acuse = TextField(default='')
donativo = BooleanField(default=False)
anticipo = BooleanField(default=False)
+ egreso_anticipo = BooleanField(default=False)
tipo_relacion = TextField(default='')
error = TextField(default='')
@@ -1472,8 +1483,6 @@ class Facturas(BaseModel):
obj = SATTipoRelacion.get(SATTipoRelacion.key==invoice.tipo_relacion)
values['tiporelacion'] = str(obj)
- print ('\nTR', invoice.tipo_relacion)
-
return values
@classmethod
@@ -1511,6 +1520,21 @@ class Facturas(BaseModel):
def _send(self, id, rfc):
return Facturas.send(id, rfc)
+ @util.run_in_thread
+ def _actualizar_saldo_cliente(self, invoice):
+ if invoice.tipo_comprobante == 'T':
+ return
+
+ importe = invoice.total_mn
+ if invoice.tipo_comprobante == 'E':
+ importe *= -1
+
+ q = (Socios
+ .update(saldo_cliente=Socios.saldo_cliente + importe)
+ .where(Socios.id==invoice.cliente.id)
+ )
+ return bool(q.execute())
+
@classmethod
def send(cls, id, rfc):
values = Configuracion.get_({'fields': 'correo'})
@@ -1940,6 +1964,42 @@ class Facturas(BaseModel):
obj.save()
return obj.estatus_sat
+ @classmethod
+ def anticipo_egreso(cls, id):
+ origen = Facturas.get(Facturas.id == id)
+ relacionadas = (FacturasRelacionadas
+ .select(FacturasRelacionadas.factura_origen)
+ .where(FacturasRelacionadas.factura==origen))
+ conceptos = (FacturasDetalle
+ .select()
+ .where(FacturasDetalle.factura==origen))
+ impuestos = (FacturasImpuestos
+ .select()
+ .where(FacturasImpuestos.factura==origen))
+
+ #~ egreso_anticipo = BooleanField(default=False)
+
+ serie = Folios.get_egreso(origen.serie)
+ nueva = {
+ 'cliente': origen.cliente,
+ 'tipo_comprobante': 'E',
+ 'forma_pago': '30',
+ 'serie': serie,
+ 'folio': cls._get_folio(cls, serie),
+ 'tipo_relacion': '07',
+ 'pagada': True,
+ 'lugar_expedicion': origen.lugar_expedicion,
+ 'uso_cfdi': origen.uso_cfdi,
+ 'moneda': origen.moneda,
+ 'tipo_cambio': origen.tipo_cambio,
+ 'regimen_fiscal': origen.regimen_fiscal,
+ 'subtotal': origen.subtotal,
+ 'total': origen.total,
+ 'total_trasladados': origen.total_trasladados,
+ 'total_retenciones': origen.total_retenciones,
+ }
+ return
+
@classmethod
def timbrar(cls, id):
obj = Facturas.get(Facturas.id == id)
@@ -1950,6 +2010,7 @@ class Facturas(BaseModel):
enviar_correo = util.get_bool(Configuracion.get_('correo_directo'))
auth = Emisor.get_auth()
+ anticipo = False
msg = 'Factura timbrada correctamente'
result = util.timbra_xml(obj.xml, auth)
if result['ok']:
@@ -1962,6 +2023,9 @@ class Facturas(BaseModel):
row = {'uuid': obj.uuid, 'estatus': 'Timbrada'}
if enviar_correo:
cls._send(cls, id, auth['RFC'])
+ if obj.tipo_comprobante == 'I' and obj.tipo_relacion == '07':
+ anticipo = True
+ cls._actualizar_saldo_cliente(cls, obj)
else:
msg = result['error']
obj.estatus = 'Error'
@@ -1969,7 +2033,14 @@ class Facturas(BaseModel):
obj.save()
row = {'estatus': 'Error'}
- return {'ok': result['ok'], 'msg': msg, 'row': row}
+ result = {
+ 'ok': result['ok'],
+ 'msg': msg,
+ 'row': row,
+ 'anticipo': anticipo
+ }
+
+ return result
class PreFacturas(BaseModel):
diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js
index 127006e..5d1ab53 100644
--- a/source/static/js/controller/invoices.js
+++ b/source/static/js/controller/invoices.js
@@ -280,12 +280,54 @@ function update_grid_invoices(values){
}
}
+
+function send_anticipo_egreso(id){
+ webix.ajax().get('/values/anticipoegreso', {id: id}, function(text, data){
+ var values = data.json()
+ if(values.ok){
+ msg_sucess(values.msg)
+ gi.add(values.row)
+ }else{
+ webix.alert({
+ title: 'Error al Timbrar',
+ text: values.msg,
+ type: 'alert-error'
+ })
+ }
+ })
+
+}
+
+
+function generar_anticipo_egreso(id){
+ msg = 'La factura tiene un CFDI de anticipo relacionado
'
+ msg += '¿Deseas generar la factura de egreso correspondiente?'
+
+ webix.confirm({
+ title: 'Generar Egreso',
+ ok: 'Si',
+ cancel: 'No',
+ type: 'confirm-error',
+ text: msg,
+ callback:function(result){
+ if(result){
+ send_anticipo_egreso(id)
+ }
+ }
+ })
+}
+
+
function send_timbrar(id){
webix.ajax().get('/values/timbrar', {id: id}, function(text, data){
var values = data.json()
if(values.ok){
msg_sucess(values.msg)
gi.updateItem(id, values.row)
+ if(values.anticipo){
+ //~ generar_anticipo_egreso(id)
+ //~ show('Generar egreso de anticipo')
+ }
}else{
webix.alert({
title: 'Error al Timbrar',
@@ -406,6 +448,8 @@ function guardar_y_timbrar(values){
table_relaciones.clear()
tipo_relacion = ''
anticipo = false
+ $$('chk_cfdi_anticipo').setValue(0)
+
$$('form_invoice').setValues({id_partner: 0, lbl_partner: 'Ninguno'})
$$('multi_invoices').setValue('invoices_home')
@@ -1362,3 +1406,7 @@ function lst_tipo_relacion_change(nv, ov){
}
+
+function lst_serie_change(nv, ov){
+ show(nv)
+}
diff --git a/source/static/js/controller/main.js b/source/static/js/controller/main.js
index e9bcb1c..ab9fcdb 100644
--- a/source/static/js/controller/main.js
+++ b/source/static/js/controller/main.js
@@ -54,6 +54,7 @@ var controllers = {
$$('cmd_prefactura').attachEvent('onItemClick', cmd_prefactura_click)
$$('cmd_cfdi_relacionados').attachEvent('onItemClick', cmd_cfdi_relacionados_click)
$$('lst_metodo_pago').attachEvent('onChange', lst_metodo_pago_change)
+ $$('lst_serie').attachEvent('onChange', lst_serie_change)
var tb_invoice = $$('tv_invoice').getTabbar()
tb_invoice.attachEvent('onChange', tb_invoice_change)
@@ -66,8 +67,8 @@ var controllers = {
}
-function get_uso_cfdi_to_table(args){
- webix.ajax().sync().get('/values/usocfdi', args, function(text, data){
+function get_uso_cfdi_to_table(){
+ webix.ajax().sync().get('/values/usocfdi', function(text, data){
var values = data.json()
table_usocfdi.clear()
table_usocfdi.insert(values)
diff --git a/source/static/js/controller/partners.js b/source/static/js/controller/partners.js
index ae208eb..7b331ae 100644
--- a/source/static/js/controller/partners.js
+++ b/source/static/js/controller/partners.js
@@ -22,7 +22,7 @@ function cmd_new_partner_click(id, e, node){
$$('multi_partners').setValue('partners_new')
$$('tab_partner').setValue('Datos Fiscales')
- get_uso_cfdi_to_table({})
+ get_uso_cfdi_to_table()
query = table_usocfdi.chain().find({fisica: true}).data()
$$('lst_uso_cfdi_socio').getList().parse(query)
}
@@ -54,7 +54,7 @@ function cmd_edit_partner_click(id, e, node){
$$('form_partner').setValues(values)
$$('forma_pago').getList().load('/values/formapago')
- get_uso_cfdi_to_table({})
+ get_uso_cfdi_to_table()
if(values.tipo_persona == 1){
query = table_usocfdi.chain().find({fisica: true}).data()
}else if(values.tipo_persona == 2){
@@ -339,6 +339,6 @@ function rfc_lost_focus(prev_view){
function multi_partners_change(prevID, nextID){
- webix.message(prevID)
- webix.message(nextID)
+ //~ webix.message(prevID)
+ //~ webix.message(nextID)
}
diff --git a/source/static/js/ui/partners.js b/source/static/js/ui/partners.js
index e1613e7..96c925e 100644
--- a/source/static/js/ui/partners.js
+++ b/source/static/js/ui/partners.js
@@ -18,6 +18,8 @@ var grid_partners_cols = [
sort: 'string', footer: {text: 'Clientes y Proveedores', colspan: 2}},
{id: 'nombre', header: ['Razón Social', {content: 'textFilter'}],
fillspace:true, sort: 'string'},
+ {id: 'saldo_cliente', header: ['Saldo Cliente', {content: 'numberFilter'}],
+ width: 150, sort: 'int', format: webix.i18n.priceFormat, css: 'right'},
]