Merge branch 'develop'

Error #287
Mejora - Facturas de pago con datos bancarios
This commit is contained in:
Mauricio Baeza 2018-10-12 01:23:17 -05:00
commit 2090aa743d
22 changed files with 597 additions and 326 deletions

View File

@ -1,9 +1,17 @@
v 1.21.0 [12-oct-2018]
----------------------
- Error #287
- Mejora: Complemento de pago con datos de cuentas
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar.
v 1.20.0 [08-oct-2018] v 1.20.0 [08-oct-2018]
---------------------- ----------------------
- Error #295 - Error #295
- Mejora: Cuentas de banco para clientes - 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] v 1.19.1 [03-oct-2018]

View File

@ -1 +1 @@
1.20.0 1.21.0

View File

@ -19,6 +19,20 @@ a usar, esto se hace en ***Catalogos SAT***, pestaña ***Bancos***. Por default
veras primero los bancos ya seleccionados. Marca la casilla de verificación de veras primero los bancos ya seleccionados. Marca la casilla de verificación de
cada banco que deses tener disponible al agregar las cuentas bancarias. Usa la cada banco que deses tener disponible al agregar las cuentas bancarias. Usa la
barra de desplazamiento de la tabla o la rueda de tu ratón para ver más bancos. barra de desplazamiento de la tabla o la rueda de tu ratón para ver más bancos.
Cada banco que selecciones, también estará disponible en la sección ***Clientes
y Proveedores***.
<BR>
<div class="alert-box notice"><span>TIP: </span>
Si vas a agregar los datos bancarios en las ***Facturas de pago***, es
necesario capturar el RFC de cada banco seleccionado.
</div>
<BR>
Para editar el RFC, solo da clic en la celda correspondiente y captura
correctamente el RFC del banco, para guardar presionas ***Enter***. El sistema
solo válida que sea un RFC válido, por lo que **asegurate de que sea el RFC
correcto para cada banco**.
![Seleccionar bancos](img/02/admin_002.png) ![Seleccionar bancos](img/02/admin_002.png)

View File

@ -175,8 +175,11 @@ elimina un movimiento, no importa si es retiro o depósito, el saldo de la cuent
se actualiza a partir de la fecha del movimiento eliminado y hasta el más se actualiza a partir de la fecha del movimiento eliminado y hasta el más
reciente. reciente.
* Si es un depósito y tiene facturas relacionadas, las mismas estarán de nuevo marcadas como **Por pagar** y disponibles para relacionarse con otro depósito. * Si es un depósito y tiene facturas relacionadas, las mismas estarán de nuevo
* **No podrás eliminar** un depósito si este ya tiene generada una Factura de Pago. **Siempre, asegurate de que todo este correcto antes de generar una Factura de Pago**. marcadas como **Por pagar** y disponibles para relacionarse con otro depósito.
* Puedes eliminar un depósito aún si este tiene generada una Factura de Pago. La
misma quedará ***huerfana***, pero disponible desde el listado de Facturas de
Pago elaboradas.
![Cancelar movimiento](img/03/bancos_017.png) ![Cancelar movimiento](img/03/bancos_017.png)
@ -185,8 +188,8 @@ reciente.
### Generar Factura de Pago ### Generar Factura de Pago
Para usar esta herramienta, debe estar activado el uso del [complemento de pago][2] Para usar esta herramienta, debe estar activado el uso del [complemento de pago][2]
dentro de administración. Si no ves en ***Bancos*** el botón de comando ***Factura dentro de administración. Si no ves en ***Bancos*** el botón de comando ***Generar
de Pago***, solicita a un administrador que lo active. Factura de Pago***, solicita a un administrador que lo active.
![Factura de pago](img/03/bancos_018.png) ![Factura de pago](img/03/bancos_018.png)
@ -198,8 +201,9 @@ de Pago***, solicita a un administrador que lo active.
<BR> <BR>
* Solo puedes generar ***Facturas de pago*** de movimientos de depósito que tengan facturas relacionadas. * Solo puedes generar ***Facturas de pago*** de movimientos de depósito que tengan
* Selecciona el depósito correcto y presiona el botón de comando ***Factura de Pago***. facturas relacionadas.
* Selecciona el depósito correcto y presiona el botón de comando ***Generar Factura de Pago***.
En la siguiente pantalla, **verifica una vez más que todos los datos con correctos**. En la siguiente pantalla, **verifica una vez más que todos los datos con correctos**.
En este momento puedes cerrar e incluso cancelar el movimiento para hacer cualquier En este momento puedes cerrar e incluso cancelar el movimiento para hacer cualquier
@ -221,7 +225,7 @@ de Pago***.
![Factura de pago](img/03/bancos_021.png) ![Factura de pago](img/03/bancos_021.png)
Con un clic en el icono ***PDF***, puedes generarl el PDF respectivo de esta Con un clic en el icono ***PDF***, puedes generar el PDF respectivo de esta
***Factura de Pago***. Como con las plantillas de las facturas, puedes ***Factura de Pago***. Como con las plantillas de las facturas, puedes
personalizar completamente esta plantilla. personalizar completamente esta plantilla.
@ -243,9 +247,14 @@ documento.
Los siguientes pasos **son importantes y en este orden**, los campos que debes de modificar en la Los siguientes pasos **son importantes y en este orden**, los campos que debes de modificar en la
tabla ***Facturas a pagar en este depósito*** son: tabla ***Facturas a pagar en este depósito*** son:
* **Este pago**: Si el valor pagado es el total de la factura, no lo modifiques, si es parcial, captura el valor pagado **en la moneda del documento**, en este ejemplo, en UDS. Este valor se usa para el estado de cuenta de la factura. * **Este pago**: Si el valor pagado es el total de la factura, no lo modifiques,
* **Este Pago MXM**: Captura el valor pagado en moneda nacional de este documento. En este ejemplo, sería el valor **real** del depósito. Este valor se usará para la ***Factura de pago***, para el estado de cuenta y para el saldo del cliente. si es parcial, captura el valor pagado **en la moneda del documento**, en este
* **T.C.**: Al capturar correctamente los dos valores anteriores, el sistema te calculará el tipo de cambio (***T.C***) usado, si no es correcto, puedes editarlo libremente. Este valor se usa para la ***Factura de pago***. ejemplo, en UDS. Este valor se usa para el estado de cuenta de la factura.
* **Este Pago MXM**: Captura el valor pagado en moneda nacional de este documento.
En este ejemplo, sería el valor **real** del depósito. Este valor se usará para
la ***Factura de pago***, para el estado de cuenta y para el saldo del cliente.
* **T.C.**: Al capturar correctamente los dos valores anteriores, el sistema te
calculará el tipo de cambio (***T.C***) usado. Este valor se usa para la ***Factura de pago***.
Ahora, nuestros datos deben verse así: Ahora, nuestros datos deben verse así:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -13,11 +13,12 @@ existe una relación humana.</B>
diseñado para la legislación mexicana. **Empresa Libre** es totalmente diseñado para la legislación mexicana. **Empresa Libre** es totalmente
[software libre][1]. [software libre][1].
### Índice ### Contenido
1. [Instalación y configuración](instalacion.md) 1. [Instalación y configuración](instalacion.md)
1. [Administración del sistema](administracion.md) 1. [Administración del sistema](administracion.md)
1. [Guía de usuario](guiadeusuario.md) 1. [Guía de usuario](guiadeusuario.md)
1. [Bancos](bancos.md)
1. [Preguntas más frecuentes](preguntas.md) 1. [Preguntas más frecuentes](preguntas.md)

View File

@ -24,6 +24,12 @@ la brevedad.
![Versión del sistema](img/01/install_001.png) ![Versión del sistema](img/01/install_001.png)
<BR>
<div class="alert-box notice"><span>TIP: </span>
Para todas las instrucciones siguientes, se asume que son para nuestra
maquina virtual (MV), las rutas pueden cambiar si has personalizado tu
propia MV o estas ejecutando Empresa Libre en un servidor propio.
</div>
<BR> <BR>
Ya dentro del sistema, el proceso para actualizar es: Ya dentro del sistema, el proceso para actualizar es:

View File

@ -6,11 +6,18 @@ siempre actualizado.** Solo se da soporte sobre la ultima versión de **Empresa
Libre**. Libre**.
### 1.21.0 [12-oct-2018]
- Error [#287](https://gitlab.com/mauriciobaeza/empresa-libre/issues/287)
- Mejora: Complemento de pago con datos de cuentas
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar.
### 1.20.0 [08-oct-2018] ### 1.20.0 [08-oct-2018]
- Error [#295](https://gitlab.com/mauriciobaeza/empresa-libre/issues/295) - Error [#295](https://gitlab.com/mauriciobaeza/empresa-libre/issues/295)
- Mejora - Cuentas de banco para clientes - 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.
### 1.19.1 [03-oct-2018] ### 1.19.1 [03-oct-2018]

View File

@ -40,7 +40,7 @@ Finkok, el mejor PAC de México, puedes [timbrar gratuitamente en su página][2]
No, no se incluye ningún tipo de soporte técnico. Dado que **Empresa Libre** es No, no se incluye ningún tipo de soporte técnico. Dado que **Empresa Libre** es
[software libre][1] y se ofrece sin **ningún costo para todos**, el soporte técnico [software libre][1] y se ofrece sin **ningún costo para todos**, el soporte técnico
es parte de los ingresos indispensables para poder seguir desarrollando y es parte de los ingresos indispensables para poder seguir desarrollando y
manteniendo el sistema. Esto incluye cualquier tontería que se le ocurra al SAT. manteniendo el sistema. Esto incluye cualquier estulticia que se le ocurra al SAT.
Por eso, por favor, **no pidas soporte técnico gratis**. Por eso, por favor, **no pidas soporte técnico gratis**.
@ -73,8 +73,18 @@ acceso al sistema de pruebas son:
* **Usuario**: admin * **Usuario**: admin
* **Contraseña**: salgueiro3.3 * **Contraseña**: salgueiro3.3
Toma en cuenta que este sitio esta en constante actualización, los datos generados Toma en cuenta que este sitio esta en constante actualización y desarrollo, los
se limpian de forma regular. datos generados se limpian de forma regular.
<BR>
### ¿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]
<BR> <BR>
@ -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 [4]: https://gitlab.com/mauriciobaeza/empresa-libre/issues
[5]: [5]:
[6]: https://universolibre.org/hacemos/ [6]: https://universolibre.org/hacemos/
[7]: https://doc.elmau.net/d/dbb11c9186684457beb6/

View File

@ -552,12 +552,28 @@ class AppSATBancos(object):
def on_get(self, req, resp): def on_get(self, req, resp):
values = req.params values = req.params
req.context['result'] = self._db.get_satbancos(values) req.context['result'] = self._db.get_sat_bancos(values)
resp.status = falcon.HTTP_200 resp.status = falcon.HTTP_200
def on_post(self, req, resp): def on_post(self, req, resp):
values = req.params values = req.params
req.context['result'] = self._db.satbancos(values) req.context['result'] = self._db.sat_bancos(values)
resp.status = falcon.HTTP_200
class AppSATFormaPago(object):
def __init__(self, db):
self._db = db
def on_get(self, req, resp):
values = req.params
req.context['result'] = self._db.get_sat_forma_pago(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.sat_forma_pago(values)
resp.status = falcon.HTTP_200 resp.status = falcon.HTTP_200

View File

@ -17,7 +17,8 @@ from controllers.main import (AppEmpresas,
AppMain, AppValues, AppPartners, AppProducts, AppInvoices, AppFolios, AppMain, AppValues, AppPartners, AppProducts, AppInvoices, AppFolios,
AppDocumentos, AppFiles, AppPreInvoices, AppCuentasBanco, AppDocumentos, AppFiles, AppPreInvoices, AppCuentasBanco,
AppMovimientosBanco, AppTickets, AppStudents, AppEmployees, AppNomina, AppMovimientosBanco, AppTickets, AppStudents, AppEmployees, AppNomina,
AppInvoicePay, AppCfdiPay, AppSATBancos, AppSociosCuentasBanco AppInvoicePay, AppCfdiPay, AppSATBancos, AppSociosCuentasBanco,
AppSATFormaPago
) )
@ -59,6 +60,7 @@ api.add_route('/nomina', AppNomina(db))
api.add_route('/invoicepay', AppInvoicePay(db)) api.add_route('/invoicepay', AppInvoicePay(db))
api.add_route('/cfdipay', AppCfdiPay(db)) api.add_route('/cfdipay', AppCfdiPay(db))
api.add_route('/satbancos', AppSATBancos(db)) api.add_route('/satbancos', AppSATBancos(db))
api.add_route('/satformapago', AppSATFormaPago(db))
api.add_route('/socioscb', AppSociosCuentasBanco(db)) api.add_route('/socioscb', AppSociosCuentasBanco(db))

View File

@ -436,9 +436,12 @@ class StorageEngine(object):
def get_cfdipay(self, values): def get_cfdipay(self, values):
return main.CfdiPagos.get_values(values) return main.CfdiPagos.get_values(values)
def get_satbancos(self, values): def get_sat_bancos(self, values):
return main.SATBancos.get_values(values) return main.SATBancos.get_values(values)
def get_sat_forma_pago(self, values):
return main.SATFormaPago.get_values(values)
def get_partners_accounts_bank(self, values): def get_partners_accounts_bank(self, values):
return main.SociosCuentasBanco.get_values(values) return main.SociosCuentasBanco.get_values(values)
@ -448,8 +451,11 @@ class StorageEngine(object):
def bankmovement(self, values): def bankmovement(self, values):
return main.MovimientosBanco.post(values) return main.MovimientosBanco.post(values)
def satbancos(self, values): def sat_bancos(self, values):
return main.SATBancos.post(values) return main.SATBancos.post(values)
def sat_forma_pago(self, values):
return main.SATFormaPago.post(values)
def partners_accounts_bank(self, values): def partners_accounts_bank(self, values):
return main.SociosCuentasBanco.post(values) return main.SociosCuentasBanco.post(values)

View File

@ -45,6 +45,7 @@ FORMAT6 = '{0:.6f}'
FORMAT_TAX = FORMAT4 FORMAT_TAX = FORMAT4
FORMAT_PRECIO = FORMAT4 FORMAT_PRECIO = FORMAT4
RFC_PUBLICO = 'XAXX010101000' RFC_PUBLICO = 'XAXX010101000'
RFC_EXTRANJERO = 'XEXX010101000'
database_proxy = Proxy() database_proxy = Proxy()
@ -241,7 +242,8 @@ def config_main():
'nomina': nomina, 'nomina': nomina,
'timbres': 0, 'timbres': 0,
'decimales_precios': DECIMALES, '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') dp = Configuracion.get_bool('chk_config_decimales_precios')
if dp: if dp:
@ -320,6 +322,28 @@ class Configuracion(BaseModel):
values = {r.clave: util.get_bool(r.valor) for r in data} values = {r.clave: util.get_bool(r.valor) for r in data}
return values 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 @classmethod
def get_(cls, keys): def get_(cls, keys):
if isinstance(keys, str): if isinstance(keys, str):
@ -331,7 +355,7 @@ class Configuracion(BaseModel):
return data[0].valor return data[0].valor
return '' return ''
options = ('partners',) options = ('partners', 'complements')
opt = keys['fields'] opt = keys['fields']
if opt in options: if opt in options:
return getattr(cls, '_get_{}'.format(opt))(cls) return getattr(cls, '_get_{}'.format(opt))(cls)
@ -388,9 +412,6 @@ class Configuracion(BaseModel):
'chk_config_codigo_barras', 'chk_config_codigo_barras',
'chk_config_precio_con_impuestos', 'chk_config_precio_con_impuestos',
'chk_llevar_inventario', 'chk_llevar_inventario',
'chk_config_ine',
'chk_config_edu',
'chk_config_pagos',
'chk_usar_punto_de_venta', 'chk_usar_punto_de_venta',
'chk_ticket_pdf_show', 'chk_ticket_pdf_show',
'chk_ticket_direct_print', 'chk_ticket_direct_print',
@ -1244,6 +1265,31 @@ class SATFormaPago(BaseModel):
def __str__(self): def __str__(self):
return 'Forma de pago: ({}) {}'.format(self.key, self.name) return 'Forma de pago: ({}) {}'.format(self.key, self.name)
@classmethod
def get_values(cls, values):
opt = values.pop('opt')
return getattr(cls, '_get_{}'.format(opt))(cls, values)
def _get_active_by_id(self, values):
rows = (SATFormaPago
.select(
SATFormaPago.id,
SATFormaPago.name.alias('value'))
.where(SATFormaPago.activo==True)
.dicts()
)
return tuple(rows)
def _get_active_by_key(self, values):
rows = (SATFormaPago
.select(
SATFormaPago.key.alias('id'),
SATFormaPago.name.alias('value'))
.where(SATFormaPago.activo==True)
.dicts()
)
return tuple(rows)
@classmethod @classmethod
def get_(self): def get_(self):
rows = SATFormaPago.select().dicts() rows = SATFormaPago.select().dicts()
@ -1878,218 +1924,6 @@ class CuentasBanco(BaseModel):
return data return data
class MovimientosBanco(BaseModel):
cuenta = ForeignKeyField(CuentasBanco)
fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S'])
descripcion = TextField(default='')
forma_pago = ForeignKeyField(SATFormaPago)
retiro = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
deposito = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
saldo = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
cancelado = BooleanField(default=False)
conciliado = BooleanField(default=False)
moneda = TextField(default='MXN') # Complemento de pagos
tipo_cambio = DecimalField(default=1.0, max_digits=15, decimal_places=6,
auto_round=True)
numero_operacion = TextField(default='')
origen_rfc = TextField(default='')
origen_nombre = TextField(default='')
origen_cuenta = TextField(default='')
destino_rfc = TextField(default='')
destino_cuenta = TextField(default='')
tipo_cadena_pago = TextField(default='')
certificado_pago = TextField(default='')
cadena_pago = TextField(default='')
sello_pago = TextField(default='')
class Meta:
order_by = ('fecha', 'id')
def _ultimo_saldo(self, cuenta, fecha):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.fecha<=fecha) &
(MovimientosBanco.cancelado==False))[-1]
)
return round(float(query.saldo), DECIMALES)
def _movimiento_anterior(self, cuenta, fecha):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.fecha<fecha) &
(MovimientosBanco.cancelado==False))[-1]
)
return query
def _actualizar_saldos(self, row):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==row.cuenta) &
(MovimientosBanco.fecha>row.fecha) &
(MovimientosBanco.cancelado==False))
)
saldo = round(Decimal(row.saldo), DECIMALES)
for mov in query:
mov.saldo = saldo + mov.deposito - mov.retiro
mov.save()
saldo = mov.saldo
CuentasBanco.actualizar_saldo(row.cuenta, saldo)
return saldo
@classmethod
def post(cls, values):
opt = values.pop('opt')
return getattr(cls, '_{}'.format(opt))(cls, values)
def _add(self, values):
ids = values.pop('ids', '')
if ids and not Facturas.validate_count_partners(util.loads(ids)):
msg = 'Facturas relacionadas a diferentes clientes'
data = {'ok': False, 'msg': msg}
return data
actualizar = False
if 'saldo' in values:
saldo = values['saldo']
else:
actualizar = True
hora = values.pop('hora')
account = CuentasBanco.get(CuentasBanco.id==int(values['cuenta']))
values['fecha'] = '{}T{}'.format(values['fecha'][:10], hora)
values['cuenta'] = account
values['moneda'] = account.moneda.key
values['retiro'] = util.get_float(values['retiro'])
values['deposito'] = util.get_float(values['deposito'])
values['tipo_cambio'] = util.get_float(
values.get('tipo_cambio', 1.00), True)
values['forma_pago'] = int(values['forma_pago'])
ultimo_saldo = self._ultimo_saldo(
self, values['cuenta'], values['fecha'])
values['saldo'] = \
ultimo_saldo - values['retiro'] + values['deposito']
with database_proxy.transaction():
try:
obj = MovimientosBanco.create(**values)
except IntegrityError:
msg = 'Este movimiento ya existe'
return {'ok': False, 'msg': msg}
if actualizar:
saldo = self._actualizar_saldos(self, obj)
if ids:
FacturasPagos.add(obj, util.loads(ids))
return {'ok': True, 'saldo': saldo}
def _cancel(self, values):
id = int(values['id'])
try:
obj = MovimientosBanco.get(MovimientosBanco.id==id)
except MovimientosBanco.DoesNotExist:
msg = 'No se encontró el movimiento'
return {'ok': False, 'msg': msg}
if obj.cancelado:
msg = 'El movimiento ya esta cancelado'
return {'ok': False, 'msg': msg}
if obj.conciliado:
msg = 'El movimiento esta conciliado, no se puede cancelar'
return {'ok': False, 'msg': msg}
# ~ filters = (CfdiPagos.movimiento==obj)
# ~ cp = CfdiPagos.select().where(filters).count()
# ~ if cp > 0:
# ~ msg = 'El movimiento tiene Factura de Pago, no se puede cancelar'
# ~ return {'ok': False, 'msg': msg}
with database_proxy.transaction():
obj.cancelado = True
obj.save()
FacturasPagos.cancelar(obj)
obj = self._movimiento_anterior(self, obj.cuenta, obj.fecha)
self._actualizar_saldos(self, obj)
balance = CuentasBanco.get_saldo(obj.cuenta.id)
msg = 'Movimiento cancelado correctamente'
return {'ok': True, 'msg': msg, 'balance': balance}
@classmethod
def con(cls, id):
cant = (MovimientosBanco
.select(MovimientosBanco.id)
.where(MovimientosBanco.cuenta==id)
.count()
)
if cant > 2:
return {'ok': True}
return {'ok': False}
@classmethod
def get_(cls, values):
cuenta = int(values['cuenta'])
if 'fechas' in values:
rango = util.loads(values['fechas'])
fd = (MovimientosBanco.fecha.between(
util.get_date(rango['start']),
util.get_date(rango['end'], True)))
filtros = (fd &
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.cancelado==False)
)
else:
year = int(values['year'])
mes = int(values['mes'])
if year == -1:
fy = (MovimientosBanco.fecha.year > 0)
else:
fy = (MovimientosBanco.fecha.year == year)
if mes == -1:
fm = (MovimientosBanco.fecha.month > 0)
else:
fm = (MovimientosBanco.fecha.month == mes)
filtros = (fy & fm &
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.cancelado==False)
)
rows = tuple(MovimientosBanco.select(
MovimientosBanco.id,
MovimientosBanco.fecha,
MovimientosBanco.numero_operacion,
SATFormaPago.name.alias('way_payment'),
MovimientosBanco.descripcion,
MovimientosBanco.retiro,
MovimientosBanco.deposito,
MovimientosBanco.saldo,
fn.COUNT(CfdiPagos.id).alias('invoice')
)
.join(SATFormaPago).switch(MovimientosBanco)
.join(CfdiPagos, JOIN.LEFT_OUTER).switch(MovimientosBanco)
.where(filtros)
.group_by(MovimientosBanco.id, SATFormaPago.name)
.dicts()
)
return {'ok': True, 'rows': rows}
class SATUsoCfdi(BaseModel): class SATUsoCfdi(BaseModel):
key = TextField(index=True, unique=True) key = TextField(index=True, unique=True)
name = TextField(default='', index=True) name = TextField(default='', index=True)
@ -2655,6 +2489,7 @@ class Socios(BaseModel):
@classmethod @classmethod
def add(cls, values): def add(cls, values):
accounts = util.loads(values.pop('accounts', '[]'))
fields = cls._clean(cls, values) fields = cls._clean(cls, values)
try: try:
obj = Socios.create(**fields) obj = Socios.create(**fields)
@ -2665,6 +2500,19 @@ class Socios(BaseModel):
#~ ToDo Agregar tags #~ ToDo Agregar tags
for account in accounts:
try:
bank = SATBancos.get_by_name(account['banco'])
fields = {
'socio': obj,
'banco': bank,
'cuenta': account['cuenta'],
'clabe': account['clabe'],
}
o = SociosCuentasBanco.create(**fields)
except IntegrityError:
pass
row = { row = {
'id': obj.id, 'id': obj.id,
'rfc': obj.rfc, 'rfc': obj.rfc,
@ -2704,15 +2552,11 @@ class Socios(BaseModel):
if count: if count:
return False return False
q = SociosCuentasBanco.delete().where(SociosCuentasBanco.socio==id)
q.execute()
q = Socios.delete().where(Socios.id==id) q = Socios.delete().where(Socios.id==id)
return bool(q.execute()) return bool(q.execute())
# ~ def _reset_saldo(self, id):
# ~ obj = Socios.get(Socios.id==id)
# ~ obj.saldo_cliente = 0.0
# ~ obj.save()
# ~ return {'ok': True}
@classmethod @classmethod
def opt(cls, args): def opt(cls, args):
opt = args.get('opt', '') opt = args.get('opt', '')
@ -2724,6 +2568,7 @@ class Socios(BaseModel):
class SociosCuentasBanco(BaseModel): class SociosCuentasBanco(BaseModel):
socio = ForeignKeyField(Socios) socio = ForeignKeyField(Socios)
activa = BooleanField(default=True)
banco = ForeignKeyField(SATBancos) banco = ForeignKeyField(SATBancos)
cuenta = TextField(default='') cuenta = TextField(default='')
clabe = TextField(default='') clabe = TextField(default='')
@ -2738,10 +2583,15 @@ class SociosCuentasBanco(BaseModel):
def __str__(self): def __str__(self):
return '{} ({})'.format(self.banco.name, self.cuenta[-4:]) return '{} ({})'.format(self.banco.name, self.cuenta[-4:])
@classmethod def _get_by_name(self, values):
def get_values(cls, values): name = values['name']
opt = values.pop('opt') query = (SociosCuentasBanco
return getattr(cls, '_get_{}'.format(opt))(cls, values) .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): def _get_by_partner(self, values):
id = int(values['id_partner']) id = int(values['id_partner'])
@ -2756,6 +2606,11 @@ class SociosCuentasBanco(BaseModel):
.dicts()) .dicts())
return tuple(rows) return tuple(rows)
@classmethod
def get_values(cls, values):
opt = values.pop('opt')
return getattr(cls, '_get_{}'.format(opt))(cls, values)
@classmethod @classmethod
def post(cls, values): def post(cls, values):
opt = values.pop('opt') opt = values.pop('opt')
@ -2789,6 +2644,13 @@ class SociosCuentasBanco(BaseModel):
msg = 'Cuenta borrada correctamente' msg = 'Cuenta borrada correctamente'
return {'ok': result, 'msg': msg} 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): class Contactos(BaseModel):
socio = ForeignKeyField(Socios) socio = ForeignKeyField(Socios)
@ -2843,6 +2705,226 @@ class ContactoCorreos(BaseModel):
) )
class MovimientosBanco(BaseModel):
cuenta = ForeignKeyField(CuentasBanco)
fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S'])
descripcion = TextField(default='')
forma_pago = ForeignKeyField(SATFormaPago)
retiro = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
deposito = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
saldo = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
cancelado = BooleanField(default=False)
conciliado = BooleanField(default=False)
moneda = TextField(default='MXN') # Complemento de pagos
tipo_cambio = DecimalField(default=1.0, max_digits=15, decimal_places=6,
auto_round=True)
numero_operacion = TextField(default='')
cuenta_socio = ForeignKeyField(SociosCuentasBanco, null=True)
tipo_cadena_pago = TextField(default='')
certificado_pago = TextField(default='')
cadena_pago = TextField(default='')
sello_pago = TextField(default='')
class Meta:
order_by = ('fecha', 'id')
def _ultimo_saldo(self, cuenta, fecha):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.fecha<=fecha) &
(MovimientosBanco.cancelado==False))[-1]
)
return round(float(query.saldo), DECIMALES)
def _movimiento_anterior(self, cuenta, fecha):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.fecha<fecha) &
(MovimientosBanco.cancelado==False))[-1]
)
return query
def _actualizar_saldos(self, row):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==row.cuenta) &
(MovimientosBanco.fecha>row.fecha) &
(MovimientosBanco.cancelado==False))
)
saldo = round(Decimal(row.saldo), DECIMALES)
for mov in query:
mov.saldo = saldo + mov.deposito - mov.retiro
mov.save()
saldo = mov.saldo
CuentasBanco.actualizar_saldo(row.cuenta, saldo)
return saldo
@classmethod
def post(cls, values):
opt = values.pop('opt')
return getattr(cls, '_{}'.format(opt))(cls, values)
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}
return data
actualizar = False
if 'saldo' in values:
saldo = values['saldo']
else:
actualizar = True
hora = values.pop('hora')
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'])
values['tipo_cambio'] = util.get_float(
values.get('tipo_cambio', 1.00), True)
values['forma_pago'] = int(values['forma_pago'])
ultimo_saldo = self._ultimo_saldo(
self, values['cuenta'], values['fecha'])
values['saldo'] = \
ultimo_saldo - values['retiro'] + values['deposito']
with database_proxy.transaction():
try:
obj = MovimientosBanco.create(**values)
except IntegrityError:
msg = 'Error al agregar el movimiento'
return {'ok': False, 'msg': msg}
if actualizar:
saldo = self._actualizar_saldos(self, obj)
if ids:
FacturasPagos.add(obj, util.loads(ids))
return {'ok': True, 'saldo': saldo}
def _cancel(self, values):
id = int(values['id'])
try:
obj = MovimientosBanco.get(MovimientosBanco.id==id)
except MovimientosBanco.DoesNotExist:
msg = 'No se encontró el movimiento'
return {'ok': False, 'msg': msg}
if obj.cancelado:
msg = 'El movimiento ya esta cancelado'
return {'ok': False, 'msg': msg}
if obj.conciliado:
msg = 'El movimiento esta conciliado, no se puede cancelar'
return {'ok': False, 'msg': msg}
# ~ filters = (CfdiPagos.movimiento==obj)
# ~ cp = CfdiPagos.select().where(filters).count()
# ~ if cp > 0:
# ~ msg = 'El movimiento tiene Factura de Pago, no se puede cancelar'
# ~ return {'ok': False, 'msg': msg}
with database_proxy.transaction():
obj.cancelado = True
obj.save()
FacturasPagos.cancelar(obj)
obj = self._movimiento_anterior(self, obj.cuenta, obj.fecha)
self._actualizar_saldos(self, obj)
balance = CuentasBanco.get_saldo(obj.cuenta.id)
msg = 'Movimiento cancelado correctamente'
return {'ok': True, 'msg': msg, 'balance': balance}
@classmethod
def con(cls, id):
cant = (MovimientosBanco
.select(MovimientosBanco.id)
.where(MovimientosBanco.cuenta==id)
.count()
)
if cant > 2:
return {'ok': True}
return {'ok': False}
@classmethod
def get_(cls, values):
cuenta = int(values['cuenta'])
if 'fechas' in values:
rango = util.loads(values['fechas'])
fd = (MovimientosBanco.fecha.between(
util.get_date(rango['start']),
util.get_date(rango['end'], True)))
filtros = (fd &
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.cancelado==False)
)
else:
year = int(values['year'])
mes = int(values['mes'])
if year == -1:
fy = (MovimientosBanco.fecha.year > 0)
else:
fy = (MovimientosBanco.fecha.year == year)
if mes == -1:
fm = (MovimientosBanco.fecha.month > 0)
else:
fm = (MovimientosBanco.fecha.month == mes)
filtros = (fy & fm &
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.cancelado==False)
)
rows = tuple(MovimientosBanco.select(
MovimientosBanco.id,
MovimientosBanco.fecha,
MovimientosBanco.numero_operacion,
SATFormaPago.name.alias('way_payment'),
MovimientosBanco.descripcion,
MovimientosBanco.retiro,
MovimientosBanco.deposito,
MovimientosBanco.saldo,
fn.COUNT(CfdiPagos.id).alias('invoice')
)
.join(SATFormaPago).switch(MovimientosBanco)
.join(CfdiPagos, JOIN.LEFT_OUTER).switch(MovimientosBanco)
.where(filtros)
.group_by(MovimientosBanco.id, SATFormaPago.name)
.dicts()
)
return {'ok': True, 'rows': rows}
class Alumnos(BaseModel): class Alumnos(BaseModel):
rfc = TextField(null=True) rfc = TextField(null=True)
curp = TextField(index=True, unique=True) curp = TextField(index=True, unique=True)
@ -3424,13 +3506,6 @@ class Facturas(BaseModel):
@classmethod @classmethod
def validate_count_partners(cls, ids): def validate_count_partners(cls, ids):
filters = (Facturas.id.in_(tuple(ids.keys()))) 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)) partners = (Facturas.select(fn.COUNT(Socios.rfc))
.where(filters) .where(filters)
.join(Socios).switch(Facturas) .join(Socios).switch(Facturas)
@ -5763,6 +5838,7 @@ class CfdiPagos(BaseModel):
def _generate_xml(self, invoice, auth): def _generate_xml(self, invoice, auth):
emisor = Emisor.select()[0] emisor = Emisor.select()[0]
cert = Certificado.get_cert() cert = Certificado.get_cert()
used_data_bank = Configuracion.get_bool('chk_cfg_pays_data_bank')
cfdi = {} cfdi = {}
related = {} related = {}
@ -5812,7 +5888,6 @@ class CfdiPagos(BaseModel):
impuestos = {} impuestos = {}
mov = invoice.movimiento mov = invoice.movimiento
# ~ currency = mov.cuenta.moneda.key
currency = mov.moneda currency = mov.moneda
related_docs = self._get_related_xml(self, invoice.movimiento, currency) related_docs = self._get_related_xml(self, invoice.movimiento, currency)
pagos = { pagos = {
@ -5822,6 +5897,20 @@ class CfdiPagos(BaseModel):
'Monto': FORMAT.format(mov.deposito), 'Monto': FORMAT.format(mov.deposito),
'relacionados': related_docs, '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: if currency != CURRENCY_MN:
pagos['TipoCambioP'] = FORMAT_TAX.format(mov.tipo_cambio) pagos['TipoCambioP'] = FORMAT_TAX.format(mov.tipo_cambio)
@ -8382,6 +8471,23 @@ def _migrate_tables(rfc=''):
fecha_cancelacion = DateTimeField(null=True) fecha_cancelacion = DateTimeField(null=True)
migrations.append(migrator.add_column('cfdipagos', 'fecha_cancelacion', fecha_cancelacion)) migrations.append(migrator.add_column('cfdipagos', 'fecha_cancelacion', fecha_cancelacion))
table = 'movimientosbanco'
columns = [c.name for c in database_proxy.get_columns(table)]
if not 'cuenta_socio_id' in columns:
cuenta_socio = ForeignKeyField(SociosCuentasBanco, null=True, to_field=SociosCuentasBanco.id)
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: if migrations:
with database_proxy.atomic() as txn: with database_proxy.atomic() as txn:
migrate(*migrations) migrate(*migrations)

View File

@ -47,7 +47,7 @@ except ImportError:
DEBUG = DEBUG DEBUG = DEBUG
VERSION = '1.20.0' VERSION = '1.21.0'
EMAIL_SUPPORT = ('soporte@empresalibre.net',) EMAIL_SUPPORT = ('soporte@empresalibre.net',)
TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION) TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION)

View File

@ -92,6 +92,7 @@ var controllers = {
$$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click) $$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_edu').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_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_cuenta_predial').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_codigo_barras').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) $$('chk_config_precio_con_impuestos').attachEvent('onItemClick', chk_config_item_click)
@ -1133,6 +1134,7 @@ function tab_options_change(nv, ov){
var cv = { var cv = {
tab_admin_templates: 'templates', tab_admin_templates: 'templates',
tab_admin_partners: 'partners', tab_admin_partners: 'partners',
tab_admin_complements: 'complements',
tab_admin_otros: 'configotros', tab_admin_otros: 'configotros',
} }
get_config_values(cv[nv]) get_config_values(cv[nv])

View File

@ -37,8 +37,12 @@ function init_config_bank(){
g3.showColumn('total') g3.showColumn('total')
g3.showColumn('currency') g3.showColumn('currency')
} }
show('cmd_complemento_pago', get_config('used_cfdi_pays')) var used_cfdi_pays = get_config('used_cfdi_pays')
show('cmd_show_invoice_pay', 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() set_year_month()
} }
@ -69,6 +73,7 @@ var bancos_controllers = {
$$('cmd_pay_delete').attachEvent('onItemClick', cmd_pay_delete_click) $$('cmd_pay_delete').attachEvent('onItemClick', cmd_pay_delete_click)
$$('grid_cfdi_pay').attachEvent('onItemClick', grid_cfdi_pay_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('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) $$('grid_cfdi_este_deposito').attachEvent('onItemDblClick', grid_cfdi_este_deposito_double_click)
$$('cmd_show_invoice_pay').attachEvent('onItemClick', cmd_show_invoice_pay_click) $$('cmd_show_invoice_pay').attachEvent('onItemClick', cmd_show_invoice_pay_click)
$$('filter_invoice_pay_year').attachEvent('onChange', filter_invoice_pay_change) $$('filter_invoice_pay_year').attachEvent('onChange', filter_invoice_pay_change)
@ -206,18 +211,18 @@ function lst_cuentas_banco_change(nv, ov){
} }
function get_bancos_forma_pago(retiro){ //~ function get_bancos_forma_pago(retiro){
var values = table_waypayment.chain().find({'id': { '$ne' : '99' }}).data() //~ var values = table_waypayment.chain().find({'id': { '$ne' : '99' }}).data()
if(retiro){ //~ if(retiro){
lst = $$('lst_retiro_forma_pago') //~ lst = $$('lst_retiro_forma_pago')
}else{ //~ }else{
lst = $$('lst_deposito_forma_pago') //~ lst = $$('lst_deposito_forma_pago')
} //~ }
lst.getList().parse(values) //~ lst.getList().parse(values)
if(current_way_payment){ //~ if(current_way_payment){
lst.setValue(current_way_payment) //~ lst.setValue(current_way_payment)
} //~ }
} //~ }
function get_facturas_por_pagar(){ function get_facturas_por_pagar(){
@ -246,7 +251,7 @@ function get_facturas_por_pagar(){
function cmd_agregar_retiro_click(){ 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() var title = 'Agregar retiro de banco a la cuenta ' + $$('lst_cuentas_banco').getText() + ' en ' + $$('txt_cuenta_moneda').getValue()
$$('title_bank_retiro').setValue(title) $$('title_bank_retiro').setValue(title)
$$('multi_bancos').setValue('banco_retiro') $$('multi_bancos').setValue('banco_retiro')
@ -255,13 +260,17 @@ function cmd_agregar_retiro_click(){
function cmd_agregar_deposito_click(){ function cmd_agregar_deposito_click(){
msg_importe = '' msg_importe = ''
get_bancos_forma_pago(false)
get_facturas_por_pagar() get_facturas_por_pagar()
set_way_payment('lst_deposito_forma_pago', true, current_way_payment)
var g = $$('grid_cfdi_este_deposito') var g = $$('grid_cfdi_este_deposito')
g.config.columns[g.getColumnIndex('importe')].header = 'Este Pago ' + current_currency g.config.columns[g.getColumnIndex('importe')].header = 'Este Pago ' + current_currency
g.refreshColumns() g.refreshColumns()
show('deposit_type_change', current_currency!=CURRENCY_MN) 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() var title = 'Agregar depósito de banco a la cuenta ' + $$('lst_cuentas_banco').getText() + ' en ' + $$('txt_cuenta_moneda').getValue()
$$('title_bank_deposit').setValue(title) $$('title_bank_deposit').setValue(title)
@ -666,6 +675,7 @@ function guardar_deposito(values){
data['tipo_cambio'] = values.deposit_type_change.to_float4() data['tipo_cambio'] = values.deposit_type_change.to_float4()
data['retiro'] = 0.0 data['retiro'] = 0.0
data['descripcion'] = values.deposito_descripcion data['descripcion'] = values.deposito_descripcion
data['cuenta_socio'] = values.partner_account_bank
current_way_payment = data['forma_pago'] current_way_payment = data['forma_pago']
@ -716,41 +726,40 @@ function cmd_guardar_deposito_click(){
return return
} }
msg = 'Todos los datos son correctos.<br><br>'
if(!grid.count()){ if(!grid.count()){
msg = 'Todos los datos son correctos<br>br>' msg += 'El depósito no tiene facturas relacionadas<br>¿Estás '
msg = 'El depósito no tiene facturas relacionadas<br><br>¿Estás ' msg += ' seguro de guardar el depósito sin facturas relacionadas?<br><br>'
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)
}
}
})
}else{ }else{
if(!msg_importe){ if(!msg_importe){
msg_importe = 'Se van a relacionar ' + grid.count() + ' facturas.' if(grid.count()==1){
} msg += 'Se va a relacionar 1 factura.<br><br>'
msg = 'Todos los datos son correctos.<br><br>' + msg_importe + '<br><br>' }else{
msg += '¿Deseas agregar este depósito?' msg += 'Se van a relacionar ' + grid.count() + ' facturas.<br><br>'
webix.confirm({
title: 'Guardar depósito',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
guardar_deposito(values)
}
} }
}) }
} }
if(get_config('pays_data_bank') && grid.count() && !values.partner_account_bank){
msg += 'NO seleccionaste cuenta origen.<br><br>'
}
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)
}
}
})
} }
@ -1259,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)
}
}
})
}
}

View File

@ -39,6 +39,7 @@ function configuracion_inicial(){
add_config({'key': 'decimales_precios', 'value': values.decimales_precios}) add_config({'key': 'decimales_precios', 'value': values.decimales_precios})
add_config({'key': 'used_cfdi_pays', 'value': values.pagos}) add_config({'key': 'used_cfdi_pays', 'value': values.pagos})
add_config({'key': 'multi_currency', 'value': values.multi_currency}) add_config({'key': 'multi_currency', 'value': values.multi_currency})
add_config({'key': 'pays_data_bank', 'value': values.pays_data_bank})
}) })

View File

@ -78,6 +78,8 @@ function get_condicion_pago(){
function cmd_new_partner_click(id, e, node){ function cmd_new_partner_click(id, e, node){
$$('form_partner').clearValidation() $$('form_partner').clearValidation()
$$('form_partner_account_bank').clearValidation()
$$('form_partner').setValues({ $$('form_partner').setValues({
id: 0, pais: 'México', tipo_persona: 1, es_activo: true, id: 0, pais: 'México', tipo_persona: 1, es_activo: true,
partner_balance: 0.00}) partner_balance: 0.00})
@ -106,6 +108,8 @@ function cmd_edit_partner_click(){
var msg = '' var msg = ''
var row = $$('grid_partners').getSelectedItem() var row = $$('grid_partners').getSelectedItem()
$$('form_partner_account_bank').clearValidation()
if (row == undefined){ if (row == undefined){
msg = 'Selecciona un Socio de Negocio' msg = 'Selecciona un Socio de Negocio'
msg_error(msg) msg_error(msg)
@ -235,6 +239,8 @@ function cmd_save_partner_click(id, e, node){
} }
} }
values['accounts'] = $$('grid_partner_account_bank').data.getRange()
webix.ajax().post('/partners', values, { webix.ajax().post('/partners', values, {
error:function(text, data, XmlHttpRequest){ error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico'; msg = 'Ocurrio un error, consulta a soporte técnico';
@ -482,7 +488,7 @@ function cmd_partner_add_account_bank_click(){
return return
} }
if(account.cuenta.length < 9){ if(account.cuenta.length < 10){
msg = 'Longitud incorrecta de la cuenta' msg = 'Longitud incorrecta de la cuenta'
msg_error(msg) msg_error(msg)
return return
@ -570,6 +576,8 @@ function grid_partner_account_bank_click(id, e, node){
if(id.column != 'delete'){ if(id.column != 'delete'){
return return
} }
var id_partner = $$('form_partner').getValues().id
var grid = $$('grid_partner_account_bank')
var msg = '¿Estás seguro de eliminar la cuenta de banco seleccionada?<BR><BR>' var msg = '¿Estás seguro de eliminar la cuenta de banco seleccionada?<BR><BR>'
msg += 'ESTA ACCION NO SE PUEDE DESHACER' msg += 'ESTA ACCION NO SE PUEDE DESHACER'
@ -581,7 +589,11 @@ function grid_partner_account_bank_click(id, e, node){
text: msg, text: msg,
callback:function(result){ callback:function(result){
if (result){ if (result){
partner_delete_account_bank(id.row) if(id_partner){
partner_delete_account_bank(id.row)
}else{
grid.remove(id.row)
}
} }
} }
}) })

View File

@ -112,6 +112,11 @@ function show(nombre, value){
} }
function show_column(table, column){
$$(table).showColumn(column)
}
function enable(nombre, value){ function enable(nombre, value){
if(value == '0'){ if(value == '0'){
value = false value = false
@ -502,7 +507,7 @@ function get_forma_pago(control){
function get_way_payment(){ function get_way_payment(){
webix.ajax().get('/values/formapago', {key: true}, function(text, data){ webix.ajax().get('/satformapago', {opt: 'active_by_id'}, function(text, data){
var values = data.json() var values = data.json()
table_waypayment.clear() table_waypayment.clear()
table_waypayment.insert(values) table_waypayment.insert(values)
@ -510,9 +515,16 @@ function get_way_payment(){
} }
function set_way_payment(control){ function set_way_payment(control, filter99=false, current_way_payment=''){
var values = table_waypayment.chain().data() if(filter99){
var values = table_waypayment.chain().find({'value': { '$ne' : 'Por definir' }}).data()
}else{
var values = table_waypayment.chain().data()
}
$$(control).getList().parse(values) $$(control).getList().parse(values)
if(current_way_payment){
$$(control).setValue(current_way_payment)
}
} }
@ -553,5 +565,16 @@ function pause(milliseconds) {
} }
//~ Revisado //~ Revisado
function lst_clear(lst){
lst.setValue('')
lst.define('options', [])
lst.refresh()
}
function lst_parse(lst, values){
lst.getList().parse(values)
}

View File

@ -667,22 +667,6 @@ var options_admin_otros = [
labelRight: 'Mostrar inventario'}, labelRight: 'Mostrar inventario'},
]}, ]},
{maxHeight: 20}, {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'}, {template: 'Punto de venta', type: 'section'},
{cols: [{maxWidth: 15}, {cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_usar_punto_de_venta', labelWidth: 0, {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 = { var tab_options = {
view: 'tabview', view: 'tabview',
id: 'tab_options', id: 'tab_options',
@ -732,6 +739,8 @@ var tab_options = {
rows: options_templates}}, rows: options_templates}},
{header: 'Clientes y Proveedores', body: {id: 'tab_admin_partners', {header: 'Clientes y Proveedores', body: {id: 'tab_admin_partners',
view: 'scrollview', body: {rows: options_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', {header: 'Otros', body: {id: 'tab_admin_otros', view: 'scrollview',
body: {rows: options_admin_otros}}}, body: {rows: options_admin_otros}}},
], ],

View File

@ -64,7 +64,7 @@ var grid_cuentabanco_cols = [
width: 125, format: webix.i18n.priceFormat, css: 'right'}, width: 125, format: webix.i18n.priceFormat, css: 'right'},
{id: 'saldo', header: ['Saldo'], {id: 'saldo', header: ['Saldo'],
width: 125, format: webix.i18n.priceFormat, css: 'right'}, 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: [ {cols: [
{view: 'label', label: '<b>Facturas por pagar: </b>'}, {view: 'label', label: '<b>Facturas por pagar: </b>'},
{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', {view: 'button', id: 'cmd_invoice_payed', label: 'Solo marcar pagada',
type: 'iconButton', autowidth: true, icon: 'check-circle', type: 'iconButton', autowidth: true, icon: 'check-circle',
tooltip: 'No afecta a saldos'}, tooltip: 'No afecta a saldos'},