diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py index eb871c5..6852863 100644 --- a/source/app/controllers/util.py +++ b/source/app/controllers/util.py @@ -2960,6 +2960,6 @@ def log_file(name, msg='', kill=False): return with open(path, 'a') as fh: - line = '{} : {}'.format(str(now()), msg) + line = '{} : {}\n'.format(str(now()), msg) fh.write(line) return diff --git a/source/app/models/main.py b/source/app/models/main.py index 646308f..f87501d 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -5469,8 +5469,11 @@ class Empleados(BaseModel): @classmethod def remove(cls, id): - q = Empleados.delete().where(Empleados.id==id) - return bool(q.execute()) + try: + q = Empleados.delete().where(Empleados.id==id) + return bool(q.execute()) + except IntegrityError: + return False class CfdiNomina(BaseModel): @@ -5591,8 +5594,13 @@ class CfdiNomina(BaseModel): data = [] for i, key in enumerate(headers[::2]): - gravado = round(row[i * 2], DECIMALES) - exento = round(row[i * 2 + 1], DECIMALES) + gravado = 0.0 + exento = 0.0 + if isinstance(row[i * 2], float): + gravado = round(row[i * 2], DECIMALES) + if isinstance(row[i * 2 + 1], float): + exento = round(row[i * 2 + 1], DECIMALES) + if not gravado and not exento: continue tp = SATTipoPercepcion.get_by_key(key) @@ -5632,7 +5640,10 @@ class CfdiNomina(BaseModel): data = [] for i, value in enumerate(row): key = headers[0][i] - importe = round(value, DECIMALES) + importe = 0.0 + if isinstance(value, float): + importe = round(value, DECIMALES) + if not importe: continue @@ -5670,7 +5681,10 @@ class CfdiNomina(BaseModel): continue key = headers[0][i] - importe = round(value, DECIMALES) + importe = 0.0 + if isinstance(value, float): + importe = round(value, DECIMALES) + if not importe: continue @@ -5695,14 +5709,20 @@ class CfdiNomina(BaseModel): def _validate_horas_extras(self, row): data = [] for i, key in enumerate(row[::4]): - days = int(row[i * 4]) + days = 0 + if isinstance(row[i * 4], float): + days = int(row[i * 4]) key = row[i * 4 + 1] the = SATTipoHoras.get_by_key(key) if the is None: continue - hours = int(row[i * 4 + 2]) - importe = round(row[i * 4 + 3], DECIMALES) + hours = 0 + if isinstance(row[i * 4 + 2], float): + hours = int(row[i * 4 + 2]) + importe = 0.0 + if isinstance(row[i * 4 + 3], float): + importe = round(row[i * 4 + 3], DECIMALES) if not hours or not importe: continue @@ -5724,8 +5744,12 @@ class CfdiNomina(BaseModel): if ti is None: continue - days = int(row[i * 4 + 1]) - importe = round(row[i * 4 + 2], DECIMALES) + days = 0 + if isinstance(row[i * 3 + 1], float): + days = int(row[i * 3 + 1]) + importe = 0.0 + if isinstance(row[i * 3 + 2], float): + importe = round(row[i * 3 + 2], DECIMALES) if not days or not importe: continue @@ -5738,6 +5762,18 @@ class CfdiNomina(BaseModel): return data, '' + def _validate_exists(self, values): + result = (CfdiNomina + .select() + .where( + (CfdiNomina.empleado==values['empleado']) & + (CfdiNomina.fecha_pago==values['fecha_pago']) & + (CfdiNomina.fecha_inicial_pago==values['fecha_inicial_pago']) & + (CfdiNomina.fecha_final_pago==values['fecha_final_pago']) & + (CfdiNomina.total==values['total'])) + .exists()) + return result + def _import(self): util.log_file('nomina', kill=True) emisor = Emisor.select()[0] @@ -5805,34 +5841,46 @@ class CfdiNomina(BaseModel): new_nomina['total'] = totals['total'] new_nomina['total_mn'] = totals['total'] - with database_proxy.transaction(): - obj = CfdiNomina.create(**new_nomina) - for row in new_percepciones: - row['cfdi'] = obj - CfdiNominaPercepciones.create(**row) - for row in new_deducciones: - row['cfdi'] = obj - CfdiNominaDeducciones.create(**row) - for row in new_otros_pagos: - row['cfdi'] = obj - CfdiNominaOtroPago.create(**row) - for row in new_horas_extras: - row['cfdi'] = obj - CfdiNominaHorasExtra.create(**row) - for row in new_incapacidades: - row['cfdi'] = obj - CfdiNominaIncapacidad.create(**row) + if self._validate_exists(self, new_nomina): + info = '{}'.format(new_nomina['empleado'].nombre_completo) + msg = 'Nomina existente: {}'.format(info) + util.log_file('nomina', msg) + continue - concepto = { - 'cfdi': obj, - 'valor_unitario': totals['subtotal'], - 'importe': totals['subtotal'], - 'descuento': totals['total_deducciones'], - } - CfdiNominaDetalle.create(**concepto) + try: + with database_proxy.transaction(): + obj = CfdiNomina.create(**new_nomina) + for row in new_percepciones: + row['cfdi'] = obj + CfdiNominaPercepciones.create(**row) + for row in new_deducciones: + row['cfdi'] = obj + CfdiNominaDeducciones.create(**row) + for row in new_otros_pagos: + row['cfdi'] = obj + CfdiNominaOtroPago.create(**row) + for row in new_horas_extras: + row['cfdi'] = obj + CfdiNominaHorasExtra.create(**row) + for row in new_incapacidades: + row['cfdi'] = obj + CfdiNominaIncapacidad.create(**row) - totals['cfdi'] = obj - CfdiNominaTotales.create(**totals) + concepto = { + 'cfdi': obj, + 'valor_unitario': totals['subtotal'], + 'importe': totals['subtotal'], + 'descuento': totals['total_deducciones'], + } + CfdiNominaDetalle.create(**concepto) + + totals['cfdi'] = obj + CfdiNominaTotales.create(**totals) + except Exception as e: + msg = 'ERROR: {}-{}'.format(new_nomina['serie'], new_nomina['folio']) + util.log_file('nomina', msg) + util.log_file('nomina', str(e)) + continue msg = 'NĂ³mina importada correctamente' return {'ok': True, 'msg': msg} @@ -5854,6 +5902,7 @@ class CfdiNomina(BaseModel): .where(where) .join(Empleados) .switch(CfdiNomina) + .order_by(CfdiNomina.id) .dicts() ) return {'ok': True, 'rows': tuple(rows)} @@ -6018,8 +6067,11 @@ class CfdiNomina(BaseModel): deducciones = { 'TotalOtrasDeducciones': FORMAT.format(totals.total_otras_deducciones), - 'TotalImpuestosRetenidos': FORMAT.format(totals.total_retenciones), } + if totals.total_retenciones: + deducciones['TotalImpuestosRetenidos'] = \ + FORMAT.format(totals.total_retenciones) + rows = CfdiNominaDeducciones.select().where(CfdiNominaDeducciones.cfdi==cfdi) details = [] for row in rows: @@ -6109,8 +6161,9 @@ class CfdiNomina(BaseModel): return result['ok'], obj.error def _stamp(self): + msg = '' where = ((CfdiNomina.uuid.is_null(True)) & (CfdiNomina.cancelada==False)) - rows = CfdiNomina.select().where(where) + rows = CfdiNomina.select().where(where).order_by(CfdiNomina.id) util.log_file('nomina', kill=True) msg_error = '' ok_stamp = 0 @@ -6121,7 +6174,10 @@ class CfdiNomina(BaseModel): if result: msg = 'Recibo: {}-{}, timbrado correctamente'.format(row.serie, row.folio) ok_stamp += 1 + util.log_file('nomina', msg) else: + msg = 'Error la timbrar: {}-{}, {}'.format(row.serie, row.folio, msg) + util.log_file('nomina', msg) msg_error = msg break @@ -6129,6 +6185,7 @@ class CfdiNomina(BaseModel): if ok_stamp: msg = 'Se timbraron {} recibos'.format(ok_stamp) ok = True + error = False if msg_error: error = True diff --git a/source/static/js/controller/nomina.js b/source/static/js/controller/nomina.js index 2416f75..753ff10 100644 --- a/source/static/js/controller/nomina.js +++ b/source/static/js/controller/nomina.js @@ -255,7 +255,7 @@ function delete_empleado(id){ $$('grid_employees').remove(id); msg_ok(msg) } else { - msg = 'No se pudo eliminar.' + msg = 'El Empleado tiene recibos timbrados' msg_error(msg) } })