fmatituy/selectospromanager
0
1from database.queries import db_fetchall, db_fetchone, db_execute2from modules.sst.ai_assistant import PermisosAIAssistant3 4ai_asst = PermisosAIAssistant()5 6def get_ai_insights_sst():7 # Insights dinámicos basados en la base de datos8 proyectos = db_fetchall("SELECT nombre, avance FROM proyectos WHERE estado = 'Activo'")9 insights = []10 for p in proyectos:11 if p['avance'] < 20:12 insights.append({'insight': f"Proyecto {p['nombre']}: Bajo avance inicial, programar inducción SST para personal nuevo."})13 14 # Agregar mock si no hay suficientes datos15 if not insights:16 insights = [17 {'id': 1, 'insight': 'Riesgo elevado en Proyecto Redes por fatiga detectada en el personal.'},18 {'id': 2, 'insight': 'Optimización sugerida en la distribución de turnos para el próximo mes.'}19 ]20 return insights21 22def analyze_risk_factors(data):23 # Lógica de análisis de riesgo mejorada24 task_desc = data.get('descripcion', '')25 sugerencia = ai_asst.suggest_permit_data(task_desc, data.get('proyecto_id'))26 27 # Calculamos un score ficticio basado en la cantidad de riesgos28 num_riesgos = len(sugerencia['datos_formato']['riesgos'])29 level = "Low"30 if num_riesgos > 2: level = "Medium"31 if num_riesgos > 4: level = "High"32 33 return {34 'score': num_riesgos * 0.2, 35 'level': level,36 'ai_analysis': sugerencia['analisis_ia'],37 'suggested_fields': sugerencia['datos_formato']38 }39 40def get_suggested_permit(task_description, proyecto_id):41 """Retorna la sugerencia completa de la IA para un nuevo permiso."""42 return ai_asst.suggest_permit_data(task_description, proyecto_id)43 44def validate_permit_personnel(personal_ids, template_id):45 """Valida certificaciones del personal seleccionado contra el tipo de permiso."""46 return ai_asst.validate_personnel_for_task(personal_ids, template_id)47 48def get_employees_with_certifications():49 return db_fetchall("""50 SELECT u.id, u.nombre, r.nombre as rol, 51 GROUP_CONCAT(c.tipo || ' (' || c.estado || ')') as certificaciones,52 COUNT(c.id) as count_certs53 FROM usuarios u54 JOIN roles r ON u.rol_id = r.id55 LEFT JOIN sst_certificaciones c ON u.id = c.usuario_id56 WHERE r.nombre != 'Cliente'57 GROUP BY u.id58 """)59def get_plantillas_formatos():60 return db_fetchall("SELECT * FROM plantillas_formatos ORDER BY id ASC")61 62def save_plantilla_formato(nombre, tipo_formato, archivo_url, creado_por):63 from datetime import datetime64 db_execute("""65 UPDATE plantillas_formatos 66 SET nombre = ?, archivo_url = ?, creado_por = ?, fecha_creacion = ?, activa = 167 WHERE tipo_formato = ?68 """, (nombre, archivo_url, creado_por, datetime.now().strftime('%Y-%m-%d %H:%M'), tipo_formato))69 70def delete_plantilla_formato(id):71 # En lugar de desactivar la fila, limpiamos solo la URL y estructura técnica 72 # El nombre (descriptivo) debe permanecer para identificar la categoría73 db_execute("""74 UPDATE plantillas_formatos 75 SET archivo_url = NULL, estructura_json = NULL, creado_por = 'RESET'76 WHERE id = ?77 """, (id,))78 79def get_formato_sst_by_id(id):80 return db_fetchone("SELECT * FROM formatos_sst WHERE id = ?", (id,))81 82def update_formato_sst_json(id, json_data):83 db_execute("UPDATE formatos_sst SET datos_completados_json = ? WHERE id = ?", (json_data, id))84 85def save_formato_generado(tipo, url, usuario, estado='Generado', proyecto_id=None, datos_json=None, archivo_pdf_url=None, actividad_id=None, id_plantilla=None, doc_id=None):86 from datetime import datetime87 from database.queries import update_estado_solicitud_permiso88 89 # --- CASO 0: DETECCIÓN AUTOMÁTICA DE DUPLICIDAD ---90 # Si no nos pasan doc_id but nos pasan actividad_id y tipo, buscamos si ya existe uno oficial91 if not doc_id and actividad_id:92 existing = db_fetchone("SELECT id FROM formatos_sst WHERE actividad_id = ? AND tipo_formato = ? AND estado != 'Eliminado' LIMIT 1", (actividad_id, tipo))93 if existing:94 doc_id = existing['id']95 print(f"Detectada duplicidad lógica para ID {doc_id}. Actualizando documento existente.")96 97 # --- CASO 1: ACTUALIZACIÓN (UPDATE) PARA EVITAR DUPLICIDAD ---98 if doc_id:99 db_execute("""100 UPDATE formatos_sst 101 SET archivo_url = ?, creado_por = ?, fecha = ?, estado = ?, datos_json = ?, archivo_pdf_url = ?102 WHERE id = ?103 """, (url, usuario, datetime.now().strftime('%Y-%m-%d %H:%M'), estado, datos_json, archivo_pdf_url, doc_id))104 105 # Recuperar consecutivo existente para retorno106 res = db_fetchone("SELECT consecutivo FROM formatos_sst WHERE id = ?", (doc_id,))107 return res['consecutivo'] if res else "DOC-UPD"108 109 # --- CASO 2: NUEVO REGISTRO (INSERT) ---110 map_abbr = {111 'ARO': 'ARO', 'JSA': 'JSA', 'Alturas': 'ALT', 'Caliente': 'CAL', 112 'Excavación y Demolición': 'EXC', 'Espacios Confinados': 'ESC', 113 'Eléctrico': 'ELE', 'Excavaciones': 'EXC', 'Izaje': 'IZA', 114 'Energías Peligrosas': 'ENP', 'Limpieza y Desinfección': 'LIM'115 }116 abbr = map_abbr.get(tipo, 'PET') # PET = Permiso Especial de Trabajo (Fallback Profesional)117 if 'ALTURAS' in str(tipo).upper(): abbr = 'ALT'118 if 'CALIENTE' in str(tipo).upper(): abbr = 'CAL'119 if 'CONFINADO' in str(tipo).upper(): abbr = 'ESC'120 if 'ELECTRICO' in str(tipo).upper(): abbr = 'ELE'121 122 res = db_fetchone("SELECT MAX(id) as last_id FROM formatos_sst")123 next_id = (res['last_id'] or 0) + 1124 # ID Unificado con trazabilidad: TIPO-CORR-ID125 consecutivo = f"{abbr}-{next_id:04d}"126 127 db_execute("""128 INSERT INTO formatos_sst (tipo_formato, archivo_url, creado_por, fecha, estado, proyecto_id, consecutivo, datos_json, archivo_pdf_url, actividad_id, id_plantilla)129 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)130 """, (tipo, url, usuario, datetime.now().strftime('%Y-%m-%d %H:%M'), estado, proyecto_id, consecutivo, datos_json, archivo_pdf_url, actividad_id, id_plantilla))131 132 # CERRAR SOLICITUDES PENDIENTES SI EXISTEN PARA ESTA ACTIVIDAD133 if actividad_id:134 try:135 # Buscar si hay una solicitud pendiente para esta actividad136 sol = db_fetchone("SELECT id FROM sst_solicitudes_permisos WHERE actividad_id = ? AND estado = 'Pendiente'", (actividad_id,))137 if sol:138 update_estado_solicitud_permiso(139 sol_id=sol['id'],140 nuevo_estado='Completado',141 comentario=f"Emitido {tipo} con código {consecutivo}"142 )143 except Exception as e:144 print(f"Error cerrando solicitud vinculada: {e}")145 146 return consecutivo147 148def update_formato_status(id, estado):149 db_execute("UPDATE formatos_sst SET estado = ? WHERE id = ?", (estado, id))150 151def get_pendientes_aprobacion():152 return db_fetchall("""153 SELECT f.*, p.nombre as proyecto_nombre 154 FROM formatos_sst f 155 LEFT JOIN proyectos p ON f.proyecto_id = p.id 156 WHERE f.estado = 'Pendiente' 157 ORDER BY f.id DESC158 """)159 160def get_sara_drafts():161 return db_fetchall("""162 SELECT f.*, p.nombre as proyecto_nombre 163 FROM formatos_sst f 164 LEFT JOIN proyectos p ON f.proyecto_id = p.id 165 WHERE f.estado LIKE 'Borrador%' OR f.estado = 'Diseño' 166 ORDER BY f.id DESC167 """)168 169def delete_formato_sst(id):170 db_execute("DELETE FROM formatos_sst WHERE id = ?", (id,))171 172def get_formatos_generados():173 return db_fetchall("""174 SELECT f.*, p.nombre as proyecto_nombre 175 FROM formatos_sst f 176 LEFT JOIN proyectos p ON f.proyecto_id = p.id 177 ORDER BY f.id DESC178 """)179 