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]
----------------------
- Error #295
- Mejora: Cuentas de banco para clientes
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar la rama principal.
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar.
v 1.19.1 [03-oct-2018]

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
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.
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)

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
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.
* **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**.
* 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.
* 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)
@ -185,8 +188,8 @@ reciente.
### Generar Factura de Pago
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
de Pago***, solicita a un administrador que lo active.
dentro de administración. Si no ves en ***Bancos*** el botón de comando ***Generar
Factura de Pago***, solicita a un administrador que lo active.
![Factura de pago](img/03/bancos_018.png)
@ -198,8 +201,9 @@ de Pago***, solicita a un administrador que lo active.
<BR>
* Solo puedes generar ***Facturas de pago*** de movimientos de depósito que tengan facturas relacionadas.
* Selecciona el depósito correcto y presiona el botón de comando ***Factura de Pago***.
* Solo puedes generar ***Facturas de pago*** de movimientos de depósito que tengan
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 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)
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
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
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 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, si no es correcto, puedes editarlo libremente. Este valor se usa para la ***Factura de pago***.
* **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 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í:

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
[software libre][1].
### Índice
### Contenido
1. [Instalación y configuración](instalacion.md)
1. [Administración del sistema](administracion.md)
1. [Guía de usuario](guiadeusuario.md)
1. [Bancos](bancos.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)
<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>
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**.
### 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]
- 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.
* IMPORTANTE: Es necesario realizar una migración, despues de actualizar.
### 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
[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
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**.
@ -73,8 +73,18 @@ acceso al sistema de pruebas son:
* **Usuario**: admin
* **Contraseña**: salgueiro3.3
Toma en cuenta que este sitio esta en constante actualización, los datos generados
se limpian de forma regular.
Toma en cuenta que este sitio esta en constante actualización y desarrollo, los
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>
@ -92,3 +102,4 @@ tu pantalla, en la mayoría de los navegadores con la combinación de teclas
[4]: https://gitlab.com/mauriciobaeza/empresa-libre/issues
[5]:
[6]: https://universolibre.org/hacemos/
[7]: https://doc.elmau.net/d/dbb11c9186684457beb6/

View File

@ -552,12 +552,28 @@ class AppSATBancos(object):
def on_get(self, req, resp):
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
def on_post(self, req, resp):
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

View File

@ -17,7 +17,8 @@ from controllers.main import (AppEmpresas,
AppMain, AppValues, AppPartners, AppProducts, AppInvoices, AppFolios,
AppDocumentos, AppFiles, AppPreInvoices, AppCuentasBanco,
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('/cfdipay', AppCfdiPay(db))
api.add_route('/satbancos', AppSATBancos(db))
api.add_route('/satformapago', AppSATFormaPago(db))
api.add_route('/socioscb', AppSociosCuentasBanco(db))

View File

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

View File

@ -45,6 +45,7 @@ FORMAT6 = '{0:.6f}'
FORMAT_TAX = FORMAT4
FORMAT_PRECIO = FORMAT4
RFC_PUBLICO = 'XAXX010101000'
RFC_EXTRANJERO = 'XEXX010101000'
database_proxy = Proxy()
@ -241,7 +242,8 @@ def config_main():
'nomina': nomina,
'timbres': 0,
'decimales_precios': DECIMALES,
'pagos': Configuracion.get_bool('chk_config_pagos')
'pagos': Configuracion.get_bool('chk_config_pagos'),
'pays_data_bank': Configuracion.get_bool('chk_cfg_pays_data_bank')
}
dp = Configuracion.get_bool('chk_config_decimales_precios')
if dp:
@ -320,6 +322,28 @@ class Configuracion(BaseModel):
values = {r.clave: util.get_bool(r.valor) for r in data}
return values
def _get_complements(self):
fields = (
'chk_config_ine',
'chk_config_edu',
'chk_config_pagos',
'chk_cfg_pays_data_bank',
)
data = (Configuracion
.select()
.where(Configuracion.clave.in_(fields))
)
values = {r.clave: util.get_bool(r.valor) for r in data}
fields = (
'txt_config_cfdipay_serie',
'txt_config_cfdipay_folio',
)
for f in fields:
values[f] = Configuracion.get_(f)
return values
@classmethod
def get_(cls, keys):
if isinstance(keys, str):
@ -331,7 +355,7 @@ class Configuracion(BaseModel):
return data[0].valor
return ''
options = ('partners',)
options = ('partners', 'complements')
opt = keys['fields']
if opt in options:
return getattr(cls, '_get_{}'.format(opt))(cls)
@ -388,9 +412,6 @@ class Configuracion(BaseModel):
'chk_config_codigo_barras',
'chk_config_precio_con_impuestos',
'chk_llevar_inventario',
'chk_config_ine',
'chk_config_edu',
'chk_config_pagos',
'chk_usar_punto_de_venta',
'chk_ticket_pdf_show',
'chk_ticket_direct_print',
@ -1244,6 +1265,31 @@ class SATFormaPago(BaseModel):
def __str__(self):
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
def get_(self):
rows = SATFormaPago.select().dicts()
@ -1878,218 +1924,6 @@ class CuentasBanco(BaseModel):
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):
key = TextField(index=True, unique=True)
name = TextField(default='', index=True)
@ -2655,6 +2489,7 @@ class Socios(BaseModel):
@classmethod
def add(cls, values):
accounts = util.loads(values.pop('accounts', '[]'))
fields = cls._clean(cls, values)
try:
obj = Socios.create(**fields)
@ -2665,6 +2500,19 @@ class Socios(BaseModel):
#~ 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 = {
'id': obj.id,
'rfc': obj.rfc,
@ -2704,15 +2552,11 @@ class Socios(BaseModel):
if count:
return False
q = SociosCuentasBanco.delete().where(SociosCuentasBanco.socio==id)
q.execute()
q = Socios.delete().where(Socios.id==id)
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
def opt(cls, args):
opt = args.get('opt', '')
@ -2724,6 +2568,7 @@ class Socios(BaseModel):
class SociosCuentasBanco(BaseModel):
socio = ForeignKeyField(Socios)
activa = BooleanField(default=True)
banco = ForeignKeyField(SATBancos)
cuenta = TextField(default='')
clabe = TextField(default='')
@ -2738,10 +2583,15 @@ class SociosCuentasBanco(BaseModel):
def __str__(self):
return '{} ({})'.format(self.banco.name, self.cuenta[-4:])
@classmethod
def get_values(cls, values):
opt = values.pop('opt')
return getattr(cls, '_get_{}'.format(opt))(cls, values)
def _get_by_name(self, values):
name = values['name']
query = (SociosCuentasBanco
.select()
.where(SociosCuentasBanco.activa==True, Socios.nombre==name)
.join(Socios).switch(SociosCuentasBanco)
)
rows = tuple([{'id': q.id, 'value': str(q)} for q in query])
return {'ok': True, 'values': rows}
def _get_by_partner(self, values):
id = int(values['id_partner'])
@ -2756,6 +2606,11 @@ class SociosCuentasBanco(BaseModel):
.dicts())
return tuple(rows)
@classmethod
def get_values(cls, values):
opt = values.pop('opt')
return getattr(cls, '_get_{}'.format(opt))(cls, values)
@classmethod
def post(cls, values):
opt = values.pop('opt')
@ -2789,6 +2644,13 @@ class SociosCuentasBanco(BaseModel):
msg = 'Cuenta borrada correctamente'
return {'ok': result, 'msg': msg}
@classmethod
def validate_partner_account(cls, id, invoices):
id_invoice = int(tuple(invoices.keys())[0])
account = SociosCuentasBanco.get(SociosCuentasBanco.id==id)
invoice = Facturas.get(Facturas.id==id_invoice)
return account.socio == invoice.cliente
class Contactos(BaseModel):
socio = ForeignKeyField(Socios)
@ -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):
rfc = TextField(null=True)
curp = TextField(index=True, unique=True)
@ -3424,13 +3506,6 @@ class Facturas(BaseModel):
@classmethod
def validate_count_partners(cls, ids):
filters = (Facturas.id.in_(tuple(ids.keys())))
# ~ partners = (Facturas.select(fn.COUNT(Facturas.cliente))
# ~ .where(filters)
# ~ .group_by(Facturas.cliente)
# ~ .order_by(Facturas.cliente).tuples())
# ~ if len(partners) > 1:
# ~ return False
# ~ return True
partners = (Facturas.select(fn.COUNT(Socios.rfc))
.where(filters)
.join(Socios).switch(Facturas)
@ -5763,6 +5838,7 @@ class CfdiPagos(BaseModel):
def _generate_xml(self, invoice, auth):
emisor = Emisor.select()[0]
cert = Certificado.get_cert()
used_data_bank = Configuracion.get_bool('chk_cfg_pays_data_bank')
cfdi = {}
related = {}
@ -5812,7 +5888,6 @@ class CfdiPagos(BaseModel):
impuestos = {}
mov = invoice.movimiento
# ~ currency = mov.cuenta.moneda.key
currency = mov.moneda
related_docs = self._get_related_xml(self, invoice.movimiento, currency)
pagos = {
@ -5822,6 +5897,20 @@ class CfdiPagos(BaseModel):
'Monto': FORMAT.format(mov.deposito),
'relacionados': related_docs,
}
if mov.numero_operacion:
pagos['NumOperacion'] = mov.numero_operacion
if used_data_bank and mov.cuenta_socio:
if mov.cuenta_socio.banco.rfc:
pagos['RfcEmisorCtaOrd'] = mov.cuenta_socio.banco.rfc
if mov.cuenta_socio.banco.rfc == RFC_EXTRANJERO:
pagos['NomBancoOrdExt'] = mov.cuenta_socio.banco.name
pagos['CtaOrdenante'] = mov.cuenta_socio.cuenta
if mov.cuenta.banco.rfc:
pagos['RfcEmisorCtaBen'] = mov.cuenta.banco.rfc
pagos['CtaBeneficiario'] = mov.cuenta.cuenta
if currency != CURRENCY_MN:
pagos['TipoCambioP'] = FORMAT_TAX.format(mov.tipo_cambio)
@ -8382,6 +8471,23 @@ def _migrate_tables(rfc=''):
fecha_cancelacion = DateTimeField(null=True)
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:
with database_proxy.atomic() as txn:
migrate(*migrations)

View File

@ -47,7 +47,7 @@ except ImportError:
DEBUG = DEBUG
VERSION = '1.20.0'
VERSION = '1.21.0'
EMAIL_SUPPORT = ('soporte@empresalibre.net',)
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_edu').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_pagos').attachEvent('onItemClick', chk_config_item_click)
$$('chk_cfg_pays_data_bank').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_cuenta_predial').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_codigo_barras').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_precio_con_impuestos').attachEvent('onItemClick', chk_config_item_click)
@ -1133,6 +1134,7 @@ function tab_options_change(nv, ov){
var cv = {
tab_admin_templates: 'templates',
tab_admin_partners: 'partners',
tab_admin_complements: 'complements',
tab_admin_otros: 'configotros',
}
get_config_values(cv[nv])

View File

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

View File

@ -78,6 +78,8 @@ function get_condicion_pago(){
function cmd_new_partner_click(id, e, node){
$$('form_partner').clearValidation()
$$('form_partner_account_bank').clearValidation()
$$('form_partner').setValues({
id: 0, pais: 'México', tipo_persona: 1, es_activo: true,
partner_balance: 0.00})
@ -106,6 +108,8 @@ function cmd_edit_partner_click(){
var msg = ''
var row = $$('grid_partners').getSelectedItem()
$$('form_partner_account_bank').clearValidation()
if (row == undefined){
msg = 'Selecciona un Socio de Negocio'
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, {
error:function(text, data, XmlHttpRequest){
msg = 'Ocurrio un error, consulta a soporte técnico';
@ -482,7 +488,7 @@ function cmd_partner_add_account_bank_click(){
return
}
if(account.cuenta.length < 9){
if(account.cuenta.length < 10){
msg = 'Longitud incorrecta de la cuenta'
msg_error(msg)
return
@ -570,6 +576,8 @@ function grid_partner_account_bank_click(id, e, node){
if(id.column != 'delete'){
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>'
msg += 'ESTA ACCION NO SE PUEDE DESHACER'
@ -581,7 +589,11 @@ function grid_partner_account_bank_click(id, e, node){
text: msg,
callback:function(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){
if(value == '0'){
value = false
@ -502,7 +507,7 @@ function get_forma_pago(control){
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()
table_waypayment.clear()
table_waypayment.insert(values)
@ -510,9 +515,16 @@ function get_way_payment(){
}
function set_way_payment(control){
var values = table_waypayment.chain().data()
function set_way_payment(control, filter99=false, current_way_payment=''){
if(filter99){
var values = table_waypayment.chain().find({'value': { '$ne' : 'Por definir' }}).data()
}else{
var values = table_waypayment.chain().data()
}
$$(control).getList().parse(values)
if(current_way_payment){
$$(control).setValue(current_way_payment)
}
}
@ -553,5 +565,16 @@ function pause(milliseconds) {
}
//~ Revisado
function lst_clear(lst){
lst.setValue('')
lst.define('options', [])
lst.refresh()
}
function lst_parse(lst, values){
lst.getList().parse(values)
}

View File

@ -667,22 +667,6 @@ var options_admin_otros = [
labelRight: 'Mostrar inventario'},
]},
{maxHeight: 20},
{template: 'Complementos', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_ine', labelWidth: 0,
labelRight: 'Usar el complemento INE'},
{view: 'checkbox', id: 'chk_config_edu', labelWidth: 0,
labelRight: 'Usar el complemento EDU'},
{}]},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_pagos', labelWidth: 0,
labelRight: 'Usar complemento de pagos'},
{view: 'text', id: 'txt_config_cfdipay_serie', name: 'txt_config_cfdipay_serie',
label: 'Serie', labelWidth: 50, labelAlign: 'right'},
{view: 'text', id: 'txt_config_cfdipay_folio', name: 'txt_config_cfdipay_serie',
label: 'Folio', labelWidth: 50, labelAlign: 'right'},
{}]},
{maxHeight: 20},
{template: 'Punto de venta', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_usar_punto_de_venta', labelWidth: 0,
@ -723,6 +707,29 @@ var options_admin_partners = [
]
var options_admin_complements = [
{maxHeight: 20},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_ine', labelWidth: 0,
labelRight: 'Usar el complemento INE'},
{view: 'checkbox', id: 'chk_config_edu', labelWidth: 0,
labelRight: 'Usar el complemento EDU'},
{}]},
{maxHeight: 20},
{template: 'Complemento de Pagos', type: 'section'},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_pagos', labelWidth: 0,
labelRight: 'Usar complemento de pagos'},
{view: 'checkbox', id: 'chk_cfg_pays_data_bank', labelWidth: 0,
labelRight: 'Usar datos bancarios'},
{view: 'text', id: 'txt_config_cfdipay_serie', name: 'txt_config_cfdipay_serie',
label: 'Serie', labelWidth: 50, labelAlign: 'right'},
{view: 'text', id: 'txt_config_cfdipay_folio', name: 'txt_config_cfdipay_serie',
label: 'Folio', labelWidth: 50, labelAlign: 'right'},
{maxWidth: 15}]},
]
var tab_options = {
view: 'tabview',
id: 'tab_options',
@ -732,6 +739,8 @@ var tab_options = {
rows: options_templates}},
{header: 'Clientes y Proveedores', body: {id: 'tab_admin_partners',
view: 'scrollview', body: {rows: options_admin_partners}}},
{header: 'Complementos', body: {id: 'tab_admin_complements',
view: 'scrollview', body: {rows: options_admin_complements}}},
{header: 'Otros', body: {id: 'tab_admin_otros', view: 'scrollview',
body: {rows: options_admin_otros}}},
],

View File

@ -64,7 +64,7 @@ var grid_cuentabanco_cols = [
width: 125, format: webix.i18n.priceFormat, css: 'right'},
{id: 'saldo', header: ['Saldo'],
width: 125, format: webix.i18n.priceFormat, css: 'right'},
{id: 'invoice', header: ['FP'], width: 40, css: 'center'},
{id: 'invoice', header: ['FP'], width: 40, css: 'center', hidden: true},
]
@ -438,6 +438,10 @@ var controls_banco_deposito = [
]},
{cols: [
{view: 'label', label: '<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',
type: 'iconButton', autowidth: true, icon: 'check-circle',
tooltip: 'No afecta a saldos'},