diff --git a/source/app/models/main.py b/source/app/models/main.py index 774bcf1..34bdcf5 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -1858,6 +1858,12 @@ class MovimientosBanco(BaseModel): @classmethod def add(cls, 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'] @@ -3220,6 +3226,17 @@ class Facturas(BaseModel): class Meta: order_by = ('fecha',) + @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 + @classmethod def cancel(cls, id): obj = Facturas.get(Facturas.id==id) @@ -5279,6 +5296,7 @@ class CfdiPagos(BaseModel): notas = TextField(default='') error = TextField(default='') cancelada = BooleanField(default=False) + fecha_cancelacion = DateTimeField(null=True) class Meta: order_by = ('movimiento',) @@ -5288,6 +5306,46 @@ class CfdiPagos(BaseModel): opt = values.pop('opt') return getattr(cls, '_{}'.format(opt))(cls, values) + def _cancel(self, values): + id_mov = int(values['id_mov']) + + filters = ( + (CfdiPagos.movimiento==id_mov) & + (CfdiPagos.cancelada==False) + ) + last = CfdiPagos.select().where(filters) + if not last: + msg = 'El depósito no tiene facturas de pago activas' + data = {'ok': False, 'msg': msg} + return data + + if len(last) > 1: + msg = 'Hay más de una factura activa para este depósito' + data = {'ok': False, 'msg': msg} + return data + + last = last[0] + if not last.uuid: + msg = 'La factura no esta timbrada' + data = {'ok': False, 'msg': msg} + return data + + auth = Emisor.get_auth() + cert = Certificado.get_cert() + + data, result = util.cancel_xml(auth, last.uuid, cert) + if data['ok']: + last.estatus = 'Cancelada' + last.error = '' + last.cancelada = True + last.fecha_cancelacion = result['Fecha'] + msg = 'Factura cancelada correctamente' + else: + last.error = msg = data['msg'] + last.save() + + return {'ok': data['ok'], 'msg': msg, 'id': last.id} + def _get_folio(self, serie): folio = int(Configuracion.get_('txt_config_cfdipay_folio') or '0') start = (CfdiPagos @@ -5341,9 +5399,19 @@ class CfdiPagos(BaseModel): data = {'ok': True, 'new': False} return data + fields = {} + filters = ( + (CfdiPagos.movimiento==id_mov) & + (CfdiPagos.cancelada==True) + ) + previous = CfdiPagos.select().where(filters).order_by(CfdiPagos.id.desc()) + if previous: + previous = previous[0] + fields['tipo_relacion'] = DEFAULT_CFDIPAY['TYPE_RELATION'] + fields['uuid_relacionado'] = previous.uuid + emisor = Emisor.select()[0] serie = Configuracion.get_('txt_config_cfdipay_serie') or DEFAULT_CFDIPAY['SERIE'] - fields = {} fields['movimiento'] = id_mov fields['socio'] = partner fields['serie'] = serie @@ -5417,7 +5485,7 @@ class CfdiPagos(BaseModel): if invoice.tipo_relacion: related = { 'tipo': invoice.tipo_relacion, - 'cfdis': (invoice.uuid_relacionado,), + 'cfdis': (str(invoice.uuid_relacionado),), } emisor = { @@ -7958,6 +8026,10 @@ def _migrate_tables(): migrations.append(migrator.drop_column('cfdipagos', 'cancelado')) migrations.append(migrator.add_column('cfdipagos', 'cancelada', cancelada)) + if not 'fecha_cancelacion' in columns: + fecha_cancelacion = DateTimeField(null=True) + migrations.append(migrator.add_column('cfdipagos', 'fecha_cancelacion', fecha_cancelacion)) + if migrations: with database_proxy.atomic() as txn: migrate(*migrations) diff --git a/source/app/settings.py b/source/app/settings.py index 3051e28..0c1d15c 100644 --- a/source/app/settings.py +++ b/source/app/settings.py @@ -164,6 +164,7 @@ DEFAULT_CFDIPAY = { 'KEYSAT': '84111506', 'UNITKEY': 'ACT', 'DESCRIPTION': 'Pago', + 'TYPE_RELATION': '04', } DIR_FACTURAS = 'facturas' USAR_TOKEN = False diff --git a/source/static/js/controller/bancos.js b/source/static/js/controller/bancos.js index 661a0ae..a460135 100644 --- a/source/static/js/controller/bancos.js +++ b/source/static/js/controller/bancos.js @@ -893,6 +893,43 @@ function cmd_pay_stamp_click(){ function cmd_pay_cancel_click(){ + var form = $$('form_bank_pay') + var values = form.getValues() + var data = {'opt': 'cancel', 'id_mov': values.id_mov} + + var grid = $$('grid_cfdi_pay') + if(grid.count() == 0){ + msg_error('El depósito no tiene facturas de pago activas') + return + } + + msg = '¿Estás seguro de cancelar esta factura?\n\nESTA ACCIÓN NO SE PUEDE DESHACER' + webix.confirm({ + title: 'Cancelar Factura', + ok: 'Si', + cancel: 'No', + type: 'confirm-error', + text: msg, + callback:function(result){ + if(result){ + webix.ajax().post('/cfdipay', data, { + error:function(text, data, XmlHttpRequest){ + msg = 'Ocurrio un error, consulta a soporte técnico' + msg_error(msg) + }, + success:function(text, data, XmlHttpRequest){ + values = data.json(); + if(values.ok){ + grid.updateItem(values.id, {'estatus': 'Cancelada'}) + msg_ok(values.msg) + }else{ + msg_error(values.msg) + } + } + }) + } + } + }) }