forked from elmau/empresa-libre
Merge branch 'develop'
Envío de nómina por correo Actualización de catalogos del SAT
This commit is contained in:
commit
abbb4cc608
|
@ -1,3 +1,9 @@
|
||||||
|
v 1.31.0 [23-abr-2019]
|
||||||
|
----------------------
|
||||||
|
- Error: Validar cantidad o valor unitario cero en tickets
|
||||||
|
- Mejora: Envío de nómina por correo al empleado
|
||||||
|
|
||||||
|
|
||||||
v 1.30.0 [24-mar-2019]
|
v 1.30.0 [24-mar-2019]
|
||||||
----------------------
|
----------------------
|
||||||
- Mejora: Se actualizan los catálogos de Nómina
|
- Mejora: Se actualizan los catálogos de Nómina
|
||||||
|
|
|
@ -498,7 +498,8 @@ class AppNomina(object):
|
||||||
|
|
||||||
def on_post(self, req, resp):
|
def on_post(self, req, resp):
|
||||||
values = req.params
|
values = req.params
|
||||||
req.context['result'] = self._db.nomina(values)
|
session = req.env['beaker.session']
|
||||||
|
req.context['result'] = self._db.nomina(values, session['userobj'])
|
||||||
resp.status = falcon.HTTP_200
|
resp.status = falcon.HTTP_200
|
||||||
|
|
||||||
def on_delete(self, req, resp):
|
def on_delete(self, req, resp):
|
||||||
|
|
|
@ -32,6 +32,9 @@ def get_template(req, resp, resource):
|
||||||
|
|
||||||
class AuthMiddleware(object):
|
class AuthMiddleware(object):
|
||||||
|
|
||||||
|
def process_response(self, req, resp, resource):
|
||||||
|
pass
|
||||||
|
|
||||||
def process_resource(self, req, resp, resource, params):
|
def process_resource(self, req, resp, resource, params):
|
||||||
session = req.env['beaker.session']
|
session = req.env['beaker.session']
|
||||||
user = session.get('userobj', None)
|
user = session.get('userobj', None)
|
||||||
|
|
|
@ -33,11 +33,6 @@ class StorageEngine(object):
|
||||||
def get_nomina(self, values):
|
def get_nomina(self, values):
|
||||||
return main.CfdiNomina.get_by(values)
|
return main.CfdiNomina.get_by(values)
|
||||||
|
|
||||||
def nomina(self, values):
|
|
||||||
opt = values.pop('opt')
|
|
||||||
if opt == 'cancel':
|
|
||||||
return main.CfdiNomina.cancel(int(values['id']))
|
|
||||||
|
|
||||||
def empresa_agregar(self, values):
|
def empresa_agregar(self, values):
|
||||||
return main.empresa_agregar(values['alta_rfc'], False)
|
return main.empresa_agregar(values['alta_rfc'], False)
|
||||||
|
|
||||||
|
@ -461,3 +456,7 @@ class StorageEngine(object):
|
||||||
|
|
||||||
def partners_accounts_bank(self, values):
|
def partners_accounts_bank(self, values):
|
||||||
return main.SociosCuentasBanco.post(values)
|
return main.SociosCuentasBanco.post(values)
|
||||||
|
|
||||||
|
def nomina(self, values, user):
|
||||||
|
return main.CfdiNomina.post(values, user)
|
||||||
|
|
||||||
|
|
|
@ -7593,6 +7593,94 @@ class CfdiNomina(BaseModel):
|
||||||
class Meta:
|
class Meta:
|
||||||
order_by = ('fecha',)
|
order_by = ('fecha',)
|
||||||
|
|
||||||
|
def _cancel(self, values, user):
|
||||||
|
id = int(values['id'])
|
||||||
|
msg = 'Recibo cancelado correctamente'
|
||||||
|
auth = Emisor.get_auth()
|
||||||
|
certificado = Certificado.select()[0]
|
||||||
|
obj = CfdiNomina.get(CfdiNomina.id==id)
|
||||||
|
|
||||||
|
if obj.uuid is None:
|
||||||
|
msg = 'Solo se pueden cancelar recibos timbrados'
|
||||||
|
return {'ok': False, 'msg': msg}
|
||||||
|
|
||||||
|
data, result = util.cancel_xml(auth, obj.uuid, certificado)
|
||||||
|
|
||||||
|
if data['ok']:
|
||||||
|
data['msg'] = 'Recibo cancelado correctamente'
|
||||||
|
data['row']['estatus'] = 'Cancelado'
|
||||||
|
obj.estatus = data['row']['estatus']
|
||||||
|
obj.error = ''
|
||||||
|
obj.cancelada = True
|
||||||
|
obj.fecha_cancelacion = result['Fecha']
|
||||||
|
obj.acuse = result['Acuse'] or ''
|
||||||
|
else:
|
||||||
|
obj.error = data['msg']
|
||||||
|
obj.save()
|
||||||
|
return data
|
||||||
|
|
||||||
|
def _send_mail(self, values, user):
|
||||||
|
id = int(values['id'])
|
||||||
|
msg = 'Recibo de Nómina enviado correctamente'
|
||||||
|
result = {'ok': True, 'msg': msg}
|
||||||
|
|
||||||
|
config = Configuracion.get_({'fields': 'correo'})
|
||||||
|
contra = Configuracion.get_('correo_contra')
|
||||||
|
if not config:
|
||||||
|
msg = 'Envío de correo no configurado.'
|
||||||
|
result['ok'] = False
|
||||||
|
result['msg'] = msg
|
||||||
|
return result
|
||||||
|
|
||||||
|
emisor = Emisor.select()[0]
|
||||||
|
obj = CfdiNomina.get(CfdiNomina.id==id)
|
||||||
|
to = obj.empleado.correo
|
||||||
|
if not to:
|
||||||
|
msg = 'El empleado no tiene correo.'
|
||||||
|
result['ok'] = False
|
||||||
|
result['msg'] = msg
|
||||||
|
return result
|
||||||
|
|
||||||
|
name = '{}{}_{}'.format(obj.serie, obj.folio, obj.empleado.rfc)
|
||||||
|
values = self._get_not_in_xml(self, obj, emisor)
|
||||||
|
data = util.get_data_from_xml(obj, values)
|
||||||
|
doc = util.to_pdf(data, emisor.rfc)
|
||||||
|
files = (
|
||||||
|
(obj.xml, f'{name}.xml'),
|
||||||
|
(doc, f'{name}.pdf'),
|
||||||
|
)
|
||||||
|
|
||||||
|
message = subject = f"Enviamos tu recibo de nómina"
|
||||||
|
server = {
|
||||||
|
'server': config['correo_servidor'],
|
||||||
|
'port': config['correo_puerto'],
|
||||||
|
'ssl': utils.to_bool(config['correo_ssl']),
|
||||||
|
'user': config['correo_usuario'],
|
||||||
|
'pass': utils.decrypt(contra, emisor.rfc),
|
||||||
|
}
|
||||||
|
mail = {
|
||||||
|
'to': to,
|
||||||
|
'copy': config.get('correo_copia', ''),
|
||||||
|
'subject': subject,
|
||||||
|
'message': message,
|
||||||
|
'files': files,
|
||||||
|
}
|
||||||
|
data= {
|
||||||
|
'server': server,
|
||||||
|
'mail': mail,
|
||||||
|
}
|
||||||
|
r = utils.send_mail(data)
|
||||||
|
if not r['ok']:
|
||||||
|
result['ok'] = False
|
||||||
|
result['msg'] = r['msg']
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def post(cls, values, user):
|
||||||
|
opt = values.pop('opt')
|
||||||
|
return getattr(cls, '_{}'.format(opt))(cls, values, user)
|
||||||
|
|
||||||
def _get_serie(self):
|
def _get_serie(self):
|
||||||
serie = Configuracion.get_('txt_config_nomina_serie')
|
serie = Configuracion.get_('txt_config_nomina_serie')
|
||||||
if not serie:
|
if not serie:
|
||||||
|
@ -8029,6 +8117,7 @@ class CfdiNomina(BaseModel):
|
||||||
CfdiNomina.id,
|
CfdiNomina.id,
|
||||||
CfdiNomina.serie,
|
CfdiNomina.serie,
|
||||||
CfdiNomina.folio,
|
CfdiNomina.folio,
|
||||||
|
CfdiNomina.uuid,
|
||||||
CfdiNomina.fecha,
|
CfdiNomina.fecha,
|
||||||
CfdiNomina.estatus,
|
CfdiNomina.estatus,
|
||||||
CfdiNomina.fecha_pago,
|
CfdiNomina.fecha_pago,
|
||||||
|
@ -8509,32 +8598,6 @@ class CfdiNomina(BaseModel):
|
||||||
data += [{'id': int(r.year), 'value': int(r.year)} for r in rows]
|
data += [{'id': int(r.year), 'value': int(r.year)} for r in rows]
|
||||||
return tuple(data)
|
return tuple(data)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def cancel(cls, id):
|
|
||||||
msg = 'Recibo cancelado correctamente'
|
|
||||||
auth = Emisor.get_auth()
|
|
||||||
certificado = Certificado.select()[0]
|
|
||||||
obj = CfdiNomina.get(CfdiNomina.id==id)
|
|
||||||
|
|
||||||
if obj.uuid is None:
|
|
||||||
msg = 'Solo se pueden cancelar recibos timbrados'
|
|
||||||
return {'ok': False, 'msg': msg}
|
|
||||||
|
|
||||||
data, result = util.cancel_xml(auth, obj.uuid, certificado)
|
|
||||||
|
|
||||||
if data['ok']:
|
|
||||||
data['msg'] = 'Recibo cancelado correctamente'
|
|
||||||
data['row']['estatus'] = 'Cancelado'
|
|
||||||
obj.estatus = data['row']['estatus']
|
|
||||||
obj.error = ''
|
|
||||||
obj.cancelada = True
|
|
||||||
obj.fecha_cancelacion = result['Fecha']
|
|
||||||
obj.acuse = result['Acuse'] or ''
|
|
||||||
else:
|
|
||||||
obj.error = data['msg']
|
|
||||||
obj.save()
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
class CfdiNominaDetalle(BaseModel):
|
class CfdiNominaDetalle(BaseModel):
|
||||||
cfdi = ForeignKeyField(CfdiNomina)
|
cfdi = ForeignKeyField(CfdiNomina)
|
||||||
|
|
|
@ -47,7 +47,7 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
DEBUG = DEBUG
|
DEBUG = DEBUG
|
||||||
VERSION = '1.30.0'
|
VERSION = '1.31.0'
|
||||||
EMAIL_SUPPORT = ('soporte@empresalibre.mx',)
|
EMAIL_SUPPORT = ('soporte@empresalibre.mx',)
|
||||||
TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION)
|
TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION)
|
||||||
|
|
||||||
|
|
|
@ -390,6 +390,42 @@ function timbrar_nomina(){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function send_mail(row){
|
||||||
|
if(!row.uuid){
|
||||||
|
msg_error('La nómina no esta timbrada')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var data = {'opt': 'send_mail', 'id': row.id}
|
||||||
|
|
||||||
|
msg = '¿Estás seguro de enviar por correo este Recibo de Nómina?'
|
||||||
|
webix.confirm({
|
||||||
|
title: 'Enviar Recibo de Nómina',
|
||||||
|
ok: 'Si',
|
||||||
|
cancel: 'No',
|
||||||
|
type: 'confirm-error',
|
||||||
|
text: msg,
|
||||||
|
callback:function(result){
|
||||||
|
if(result){
|
||||||
|
webix.ajax().post('/nomina', 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){
|
||||||
|
msg_ok(values.msg)
|
||||||
|
}else{
|
||||||
|
msg_error(values.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function grid_nomina_click(id, e, node){
|
function grid_nomina_click(id, e, node){
|
||||||
var row = this.getItem(id)
|
var row = this.getItem(id)
|
||||||
|
|
||||||
|
@ -397,8 +433,8 @@ function grid_nomina_click(id, e, node){
|
||||||
location = '/doc/nomxml/' + row.id
|
location = '/doc/nomxml/' + row.id
|
||||||
}else if(id.column == 'pdf'){
|
}else if(id.column == 'pdf'){
|
||||||
window.open('/doc/nompdf/' + row.id, '_blank')
|
window.open('/doc/nompdf/' + row.id, '_blank')
|
||||||
//~ }else if(id.column == 'email'){
|
}else if(id.column == 'email'){
|
||||||
//~ enviar_correo(row)
|
send_mail(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -408,6 +408,14 @@ function grid_tickets_details_before_edit_stop(state, editor){
|
||||||
grid.editCancel()
|
grid.editCancel()
|
||||||
grid.unblockEvent()
|
grid.unblockEvent()
|
||||||
return true
|
return true
|
||||||
|
}else if(cantidad <= 0){
|
||||||
|
msg = 'La cantidad no puede cero o menor'
|
||||||
|
msg_error(msg)
|
||||||
|
grid.blockEvent()
|
||||||
|
state.value = state.old
|
||||||
|
grid.editCancel()
|
||||||
|
grid.unblockEvent()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
var valor_unitario = parseFloat(row['valor_unitario'])
|
var valor_unitario = parseFloat(row['valor_unitario'])
|
||||||
var descuento = parseFloat(row['descuento'])
|
var descuento = parseFloat(row['descuento'])
|
||||||
|
@ -423,6 +431,14 @@ function grid_tickets_details_before_edit_stop(state, editor){
|
||||||
grid.editCancel()
|
grid.editCancel()
|
||||||
grid.unblockEvent()
|
grid.unblockEvent()
|
||||||
return true
|
return true
|
||||||
|
}else if(valor_unitario <= 0){
|
||||||
|
msg = 'El valor unitario no puede cero o menor'
|
||||||
|
msg_error(msg)
|
||||||
|
grid.blockEvent()
|
||||||
|
state.value = state.old
|
||||||
|
grid.editCancel()
|
||||||
|
grid.unblockEvent()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
var cantidad = parseFloat(row['cantidad'])
|
var cantidad = parseFloat(row['cantidad'])
|
||||||
var descuento = parseFloat(row['descuento'])
|
var descuento = parseFloat(row['descuento'])
|
||||||
|
|
|
@ -518,7 +518,7 @@ var emisor_correo = [
|
||||||
{view: 'button', id: 'cmd_guardar_correo', label: 'Guardar Configuración',
|
{view: 'button', id: 'cmd_guardar_correo', label: 'Guardar Configuración',
|
||||||
autowidth: true, type: 'form'},
|
autowidth: true, type: 'form'},
|
||||||
{maxWidth: 50},
|
{maxWidth: 50},
|
||||||
{view: 'button', id: 'cmd_clean_email', label: 'Limpiar Configuración',
|
{view: 'button', id: 'cmd_clean_email', label: 'Borrar Configuración',
|
||||||
autowidth: true, type: 'form'},
|
autowidth: true, type: 'form'},
|
||||||
{}]}
|
{}]}
|
||||||
]
|
]
|
||||||
|
|
|
@ -273,7 +273,7 @@ var grid_invoices_cols = [
|
||||||
{id: 'html', header: 'HTML', adjust: 'data', template: get_icon('html')},
|
{id: 'html', header: 'HTML', adjust: 'data', template: get_icon('html')},
|
||||||
{id: 'ods', header: 'ODS', adjust: 'data', template: get_icon('table')},
|
{id: 'ods', header: 'ODS', adjust: 'data', template: get_icon('table')},
|
||||||
{id: 'zip', header: 'ZIP', adjust: 'data', template: get_icon('zip')},
|
{id: 'zip', header: 'ZIP', adjust: 'data', template: get_icon('zip')},
|
||||||
{id: 'email', header: '', adjust: 'data', template: get_icon('email')}
|
{id: 'email', header: '@', adjust: 'data', template: get_icon('email')}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ var grid_cols_nomina = [
|
||||||
{id: "serie", header: ["Serie"], adjust: "header"},
|
{id: "serie", header: ["Serie"], adjust: "header"},
|
||||||
{id: 'folio', header: ['Folio', {content: 'numberFilter'}], adjust: 'header',
|
{id: 'folio', header: ['Folio', {content: 'numberFilter'}], adjust: 'header',
|
||||||
sort: 'int', css: 'right', footer: {text: 'Recibos', colspan: 3}},
|
sort: 'int', css: 'right', footer: {text: 'Recibos', colspan: 3}},
|
||||||
|
{id: "uuid", header: ["UUID", {content: "textFilter"}], adjust: "data",
|
||||||
|
sort:"string", hidden:true},
|
||||||
{id: "fecha", header: ["Fecha y Hora"], adjust: "data", sort: "string"},
|
{id: "fecha", header: ["Fecha y Hora"], adjust: "data", sort: "string"},
|
||||||
{id: "estatus", header: ["Estatus", {content: "selectFilter"}],
|
{id: "estatus", header: ["Estatus", {content: "selectFilter"}],
|
||||||
adjust: "data", sort:"string"},
|
adjust: "data", sort:"string"},
|
||||||
|
@ -60,6 +62,7 @@ var grid_cols_nomina = [
|
||||||
fillspace:true, sort:"string"},
|
fillspace:true, sort:"string"},
|
||||||
{id: 'xml', header: 'XML', adjust: 'data', template: get_icon('xml')},
|
{id: 'xml', header: 'XML', adjust: 'data', template: get_icon('xml')},
|
||||||
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
|
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
|
||||||
|
{id: 'email', header: '@', adjust: 'data', template: get_icon('email')}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue