CoolFace
Apppublic

fmatituy/selectospromanager

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
novedades.py80 linesDownload Raw Back to personal
1from nicegui import ui
2from modules.personal.services_personal import registrar_novedad, get_empleados, db_query
3from services.auth import require_auth, get_current_user
4from modules.layout import SelectosLayout
5from datetime import datetime
6
7@ui.page('/personal/novedades')
8@require_auth
9def novedades_page():
10    user = get_current_user()
11    if user.get('rol') not in ["Administrador", "Gerente", "Supervisor", "SST"]:
12        return ui.navigate.to('/')
13
14    empleados = {e['id']: e['nombre'] for e in get_empleados(activos_only=True)}
15    tipos = ['Incapacidad', 'Permiso', 'Ausencia', 'Retraso', 'Llamado de atención']
16
17    def open_modal():
18        with ui.dialog() as diag, ui.card().classes('w-[500px] p-8 rounded-3xl'):
19            ui.label('Registrar Novedad').classes('text-2xl font-black mb-6')
20            
21            with ui.column().classes('w-full gap-4'):
22                emp = ui.select(empleados, label='Empleado').props('outlined rounded-xl').classes('w-full')
23                tip = ui.select(tipos, label='Tipo de Novedad').props('outlined rounded-xl').classes('w-full')
24                des = ui.textarea('Detalles / Justificación').props('outlined rounded-xl').classes('w-full')
25                with ui.row().classes('w-full gap-4'):
26                    f_i = ui.input('Desde', value=datetime.now().strftime('%Y-%m-%d')).props('type=date outlined rounded-xl').classes('flex-1')
27                    f_f = ui.input('Hasta', value=datetime.now().strftime('%Y-%m-%d')).props('type=date outlined rounded-xl').classes('flex-1')
28
29            async def salvar():
30                if not emp.value or not tip.value:
31                    return ui.notify('Seleccione empleado y tipo', type='warning')
32                
33                payload = {
34                    'empleado_id': emp.value,
35                    'tipo': tip.value,
36                    'descripcion': des.value,
37                    'fecha_inicio': f_i.value,
38                    'fecha_fin': f_f.value,
39                    'registrada_por': user['username']
40                }
41                registrar_novedad(payload)
42                ui.notify('Novedad registrada exitosamente', type='positive')
43                diag.close()
44                refresh_history()
45
46            ui.button('Confirmar Registro', on_click=salvar).props('unelevated color=rose-600 rounded-xl').classes('w-full mt-4 py-3 font-bold')
47        diag.open()
48
49    def refresh_history():
50        grid.clear()
51        with grid:
52            novs = db_query("SELECT n.*, e.nombre as empleado_nombre FROM novedades n JOIN empleados e ON n.empleado_id = e.id ORDER BY n.id DESC")
53            if not novs:
54                ui.label('No hay novedades registradas.').classes('text-slate-400 italic mt-4')
55            else:
56                for n in novs:
57                    with ui.card().classes('w-full p-6 rounded-2xl border border-slate-100 shadow-sm bg-white mb-4'):
58                        with ui.row().classes('w-full items-center justify-between'):
59                            with ui.column().classes('gap-0'):
60                                ui.label(n['empleado_nombre']).classes('text-base font-black text-slate-800')
61                                ui.label(f"Registrado por: {n['registrada_por']}").classes('text-[10px] text-slate-400 uppercase font-bold tracking-widest')
62                            
63                            ui.chip(n['tipo'], color='rose-100', text_color='rose-700').classes('font-bold text-[10px] rounded-pill')
64                        
65                        ui.label(n['descripcion']).classes('text-sm text-slate-600 mt-4 bg-slate-50 p-3 rounded-xl border border-dotted border-slate-200 w-full')
66                        
67                        with ui.row().classes('w-full mt-4 items-center gap-2 text-slate-400'):
68                            ui.icon('event', size='xs')
69                            ui.label(f"Válido del {n['fecha_inicio']} al {n['fecha_fin']}").classes('text-xs font-bold')
70
71    with SelectosLayout('Gestión de Novedades'):
72        with ui.row().classes('w-full justify-between items-center mb-10'):
73            with ui.column().classes('gap-1'):
74                ui.label('Novedades e Incidencias').classes('text-3xl font-black text-slate-800')
75                ui.label('Incapacidades, permisos y llamados de atención centralizados.').classes('text-sm text-slate-400 font-bold')
76            ui.button('Nueva Novedad', icon='add_alert', on_click=open_modal).props('unelevated color=rose-600 rounded-xl').classes('font-bold shadow-lg shadow-rose-200')
77
78        grid = ui.column().classes('w-full')
79        refresh_history()
80