fmatituy/selectospromanager
0
1import sqlite3
2import hashlib
3import os
4from datetime import datetime
5def get_db_path():
6 # Priority 0: Environment variable
7 env_db = os.getenv("DB_NAME", "pro_manager.db")
8 if not env_db.endswith('.db'): env_db += '.db'
9
10 # Priority 1: Root directory (standard for HF persistent storage or Docker mounts)
11 root_db = os.path.join(os.getcwd(), env_db)
12 if os.path.exists(root_db):
13 return root_db
14
15 # Priority 2: Source directory (development default)
16 src_db = os.path.join(os.path.dirname(os.path.abspath(__file__)), env_db)
17 return src_db
18
19DB_PATH = get_db_path()
20
21def hash_password(password: str) -> str:
22 return hashlib.sha256(password.encode()).hexdigest()
23
24def init_db():
25 conn = sqlite3.connect(DB_PATH)
26 # Optimizaciones de velocidad para SQLite
27 conn.execute('PRAGMA journal_mode = WAL')
28 conn.execute('PRAGMA synchronous = NORMAL')
29 conn.execute('PRAGMA cache_size = -10000') # 10MB approx
30 c = conn.cursor()
31
32 # Roles y Usuarios
33 c.execute('''
34 CREATE TABLE IF NOT EXISTS roles (
35 id INTEGER PRIMARY KEY AUTOINCREMENT,
36 nombre TEXT UNIQUE
37 )
38 ''')
39
40 c.execute('''
41 CREATE TABLE IF NOT EXISTS usuarios (
42 id INTEGER PRIMARY KEY AUTOINCREMENT,
43 username TEXT UNIQUE,
44 password TEXT,
45 rol_id INTEGER,
46 nombre TEXT,
47 FOREIGN KEY (rol_id) REFERENCES roles(id)
48 )
49 ''')
50
51 # Migraciones seguras para usuarios (NUEVO: empleado_id, activo, fecha_creacion)
52 for col, ctype in [('empleado_id', 'INTEGER'), ('activo', 'INTEGER DEFAULT 1'), ('fecha_creacion', 'TEXT')]:
53 try: c.execute(f"ALTER TABLE usuarios ADD COLUMN {col} {ctype}")
54 except: pass
55
56 # Proyectos y módulos básicos
57 c.execute('''
58 CREATE TABLE IF NOT EXISTS proyectos (
59 id INTEGER PRIMARY KEY AUTOINCREMENT,
60 nombre TEXT,
61 descripcion TEXT,
62 estado TEXT,
63 avance INTEGER DEFAULT 0,
64 fecha_inicio TEXT,
65 fecha_fin TEXT,
66 cliente_id INTEGER,
67 cliente_nombre TEXT,
68 tipo_proyecto TEXT,
69 ubicacion TEXT,
70
71 -- Responsables Detallados
72 director_id INTEGER,
73 residente_id INTEGER,
74 supervisor_id INTEGER,
75 sst_id INTEGER,
76 logistica_id INTEGER,
77
78 FOREIGN KEY (director_id) REFERENCES usuarios(id),
79 FOREIGN KEY (residente_id) REFERENCES usuarios(id),
80 FOREIGN KEY (supervisor_id) REFERENCES usuarios(id),
81 FOREIGN KEY (sst_id) REFERENCES usuarios(id),
82 FOREIGN KEY (logistica_id) REFERENCES usuarios(id),
83 FOREIGN KEY (cliente_id) REFERENCES usuarios(id)
84 )
85 ''')
86
87 # CRM y Relaciones Corporativas
88 c.execute('''
89 CREATE TABLE IF NOT EXISTS crm_clientes (
90 id INTEGER PRIMARY KEY AUTOINCREMENT,
91 nit TEXT,
92 nombre TEXT NOT NULL,
93 tipo TEXT,
94 industria TEXT,
95 contacto_principal TEXT,
96 telefono TEXT,
97 email TEXT,
98 direccion TEXT,
99 ciudad TEXT,
100 estado TEXT DEFAULT 'Activo',
101 notas TEXT,
102 fecha_creacion TEXT
103 )
104 ''')
105
106 c.execute('''
107 CREATE TABLE IF NOT EXISTS crm_oportunidades (
108 id INTEGER PRIMARY KEY AUTOINCREMENT,
109 cliente_id INTEGER,
110 titulo TEXT NOT NULL,
111 valor REAL DEFAULT 0,
112 etapa TEXT DEFAULT 'Prospección',
113 fecha_cierre TEXT,
114 probabilidad INTEGER DEFAULT 50,
115 responsable_id INTEGER,
116 notas TEXT,
117 fecha_creacion TEXT,
118 FOREIGN KEY (cliente_id) REFERENCES crm_clientes(id),
119 FOREIGN KEY (responsable_id) REFERENCES usuarios(id)
120 )
121 ''')
122
123 # Migraciones seguras para columnas faltantes en proyectos
124 for col, col_type in [
125 ('descripcion', 'TEXT'),
126 ('fecha_fin', 'TEXT'),
127 ('cliente_id', 'INTEGER'),
128 ('cliente_nombre', 'TEXT'),
129 ('tipo_proyecto', 'TEXT'),
130 ('ubicacion', 'TEXT'),
131 ('director_id', 'INTEGER'),
132 ('residente_id', 'INTEGER'),
133 ('supervisor_id', 'INTEGER'),
134 ('sst_id', 'INTEGER'),
135 ('logistica_id', 'INTEGER'),
136 ('token_cliente', 'TEXT')
137 ]:
138 try:
139 c.execute(f"ALTER TABLE proyectos ADD COLUMN {col} {col_type}")
140 except:
141 pass
142
143 # SST
144 c.execute('''
145 CREATE TABLE IF NOT EXISTS plantillas_formatos (
146 id INTEGER PRIMARY KEY AUTOINCREMENT,
147 nombre TEXT,
148 tipo_formato TEXT,
149 version INTEGER DEFAULT 1,
150 estructura_json TEXT,
151 activa BOOLEAN DEFAULT 1,
152 fecha_creacion TEXT,
153 creado_por TEXT
154 )
155 ''')
156 try:
157 c.execute("ALTER TABLE plantillas_formatos ADD COLUMN archivo_url TEXT")
158 except:
159 pass
160
161 c.execute('''
162 CREATE TABLE IF NOT EXISTS formatos_sst (
163 id INTEGER PRIMARY KEY AUTOINCREMENT,
164 tipo_formato TEXT,
165 id_plantilla INTEGER,
166 datos_completados_json TEXT,
167 proyecto_id INTEGER,
168 fecha TEXT,
169 creado_por TEXT,
170 archivo_url TEXT,
171 estado TEXT DEFAULT 'Pendiente',
172 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
173 FOREIGN KEY (id_plantilla) REFERENCES plantillas_formatos(id)
174 )
175 ''')
176
177 try:
178 c.execute("ALTER TABLE formatos_sst ADD COLUMN datos_completados_json TEXT")
179 c.execute("ALTER TABLE formatos_sst ADD COLUMN id_plantilla INTEGER")
180 c.execute("ALTER TABLE formatos_sst ADD COLUMN estado TEXT DEFAULT 'Pendiente'")
181 except:
182 pass
183
184 # --- MÓDULO SST INDUSTRIAL ELITE (SG-SST / ISO 45001) ---
185
186 # 1. Matriz Legal Dinámica (Decreto 1072)
187 c.execute('''
188 CREATE TABLE IF NOT EXISTS sst_matriz_legal (
189 id INTEGER PRIMARY KEY AUTOINCREMENT,
190 norma TEXT, -- Ej: Decreto 1072 de 2015
191 articulo TEXT,
192 descripcion TEXT,
193 evidencia_requerida TEXT,
194 estado_cumplimiento TEXT DEFAULT 'Pendiente', -- Cumple, No Cumple, Parcial
195 fecha_verificacion TEXT,
196 version_norma TEXT DEFAULT 'Original',
197 derogada BOOLEAN DEFAULT 0
198 )
199 ''')
200
201 # 2. Matriz de Peligros (IPVR - GTC 45)
202 c.execute('''
203 CREATE TABLE IF NOT EXISTS sst_matriz_peligros (
204 id INTEGER PRIMARY KEY AUTOINCREMENT,
205 proyecto_id INTEGER,
206 proceso TEXT,
207 subproceso TEXT,
208 zona TEXT,
209 actividad TEXT,
210 tarea TEXT,
211 peligro_descripcion TEXT,
212 clasificacion TEXT, -- Físico, Químico, Biológico, Biomecánico, etc.
213 efectos_posibles TEXT,
214 personas_expuestas INTEGER DEFAULT 1,
215 nivel_deficiencia INTEGER, -- ND
216 nivel_exposicion INTEGER, -- NE
217 nivel_probabilidad INTEGER, -- NP
218 nivel_consecuencia INTEGER, -- NC
219 nivel_riesgo_valor INTEGER, -- NR
220 interpretacion_riesgo TEXT, -- I, II, III, IV
221 controles_eliminacion TEXT,
222 controles_sustitucion TEXT,
223 controles_ingenieria TEXT,
224 controles_administrativos TEXT,
225 controles_epp TEXT,
226 controles_existentes TEXT, -- Legado
227 controles_propuestos TEXT, -- Legado
228 accion_requerida TEXT,
229 responsable TEXT,
230 estado TEXT DEFAULT 'Identificado',
231 fecha_evaluacion TEXT,
232 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id)
233 )
234 ''')
235
236 # Migraciones para GTC-45 profesional
237 for col, ctype in [
238 ('subproceso', 'TEXT'),
239 ('tarea', 'TEXT'),
240 ('personas_expuestas', 'INTEGER DEFAULT 1'),
241 ('nivel_probabilidad', 'INTEGER'),
242 ('controles_eliminacion', 'TEXT'),
243 ('controles_sustitucion', 'TEXT'),
244 ('controles_ingenieria', 'TEXT'),
245 ('controles_administrativos', 'TEXT'),
246 ('controles_epp', 'TEXT'),
247 ('accion_requerida', 'TEXT'),
248 ('responsable', 'TEXT'),
249 ('estado', "TEXT DEFAULT 'Identificado'"),
250 ('nivel_riesgo_inicial', 'INTEGER'),
251 ('nivel_riesgo_residual', 'INTEGER')
252 ]:
253 try: c.execute(f"ALTER TABLE sst_matriz_peligros ADD COLUMN {col} {ctype}")
254 except: pass
255
256 # Tablas para Gestión GTC-45 Profesional
257 c.execute('''
258 CREATE TABLE IF NOT EXISTS sst_riesgo_plan_accion (
259 id INTEGER PRIMARY KEY AUTOINCREMENT,
260 riesgo_id INTEGER,
261 accion_correctiva TEXT,
262 responsable TEXT,
263 fecha_inicio TEXT,
264 fecha_limite TEXT,
265 estado TEXT DEFAULT 'Pendiente',
266 prioridad TEXT DEFAULT 'Media',
267 evidencias_json TEXT,
268 FOREIGN KEY (riesgo_id) REFERENCES sst_matriz_peligros(id)
269 )
270 ''')
271
272 # Migración prioridad
273 try: c.execute("ALTER TABLE sst_riesgo_plan_accion ADD COLUMN prioridad TEXT DEFAULT 'Media'")
274 except: pass
275
276 c.execute('''
277 CREATE TABLE IF NOT EXISTS sst_riesgo_evidencias (
278 id INTEGER PRIMARY KEY AUTOINCREMENT,
279 riesgo_id INTEGER,
280 archivo_nombre TEXT,
281 archivo_ruta TEXT,
282 tipo_evidencia TEXT,
283 fecha_carga TEXT,
284 usuario_id INTEGER,
285 FOREIGN KEY (riesgo_id) REFERENCES sst_matriz_peligros(id)
286 )
287 ''')
288
289 c.execute('''
290 CREATE TABLE IF NOT EXISTS sst_riesgo_historial (
291 id INTEGER PRIMARY KEY AUTOINCREMENT,
292 riesgo_id INTEGER,
293 fecha_cambio TEXT,
294 usuario_id INTEGER,
295 campo_modificado TEXT,
296 valor_anterior TEXT,
297 valor_nuevo TEXT,
298 FOREIGN KEY (riesgo_id) REFERENCES sst_matriz_peligros(id)
299 )
300 ''')
301
302 # 3. Plan Anual SG-SST (PHVA - Gestión Estratégica)
303 c.execute('''
304 CREATE TABLE IF NOT EXISTS sst_plan_anual (
305 id INTEGER PRIMARY KEY AUTOINCREMENT,
306 anio INTEGER DEFAULT 2026,
307 nombre_actividad TEXT,
308 descripcion TEXT, -- NUEVO
309 tipo_actividad TEXT, -- Inspección, Capacitación, Simulacro, Auditoría, Médica, Mantenimiento
310 fase_phva TEXT, -- Planear, Hacer, Verificar, Actuar
311 area_responsable TEXT,
312 responsable_id INTEGER,
313 frecuencia TEXT, -- Mensual, Trimestral, Semestral, Anual, Única
314 presupuesto_estimado REAL DEFAULT 0.0,
315 fecha_programada TEXT,
316 hora_programada TEXT, -- NUEVO
317 duracion_estimada TEXT, -- NUEVO (ej: 2h 30m)
318 fecha_ejecucion TEXT,
319 avance_porcentaje INTEGER DEFAULT 0,
320 estado TEXT DEFAULT 'Programada', -- Programada, En ejecución, Completada, Vencida, Borrador
321
322 -- Enfoque SST y Participantes
323 riesgo_id INTEGER, -- Link IPVR
324 tipo_capacitacion TEXT, -- Técnica, Normativa, Soft Skills, etc.
325 es_obligatoria BOOLEAN DEFAULT 1,
326 participantes_json TEXT, -- Lista de IDs de trabajadores asistentes
327
328 -- Seguimiento y Control
329 indicador_esperado TEXT,
330 metodo_verificacion TEXT,
331 evidencia_requerida TEXT,
332 evidencia_json TEXT, -- Lista de URLs de soportes (fotos, actas, PDFs)
333
334 FOREIGN KEY (responsable_id) REFERENCES usuarios(id),
335 FOREIGN KEY (riesgo_id) REFERENCES sst_matriz_peligros(id)
336 )
337 ''')
338
339 # Migraciones seguras para sst_plan_anual (campos profesionales)
340 for col, ctype in [
341 ('anio', 'INTEGER DEFAULT 2026'),
342 ('descripcion', 'TEXT'),
343 ('hora_programada', 'TEXT'),
344 ('duracion_estimada', 'TEXT'),
345 ('riesgo_id', 'INTEGER'),
346 ('tipo_capacitacion', 'TEXT'),
347 ('es_obligatoria', 'BOOLEAN DEFAULT 1'),
348 ('participantes_json', 'TEXT'),
349 ('indicador_esperado', 'TEXT'),
350 ('metodo_verificacion', 'TEXT'),
351 ('evidencia_requerida', 'TEXT')
352 ]:
353 try: c.execute(f"ALTER TABLE sst_plan_anual ADD COLUMN {col} {ctype}")
354 except: pass
355
356 # 4. Gestión Médica Ocupacional (Privada)
357 c.execute('''
358 CREATE TABLE IF NOT EXISTS sst_gestion_medica (
359 id INTEGER PRIMARY KEY AUTOINCREMENT,
360 usuario_id INTEGER,
361 tipo_examen TEXT, -- Ingreso, Periódico, Egreso
362 fecha_examen TEXT,
363 concepto_aptitud TEXT, -- Apto, Apto con restricciones, No Apto
364 recomendaciones TEXT, -- Enmascarado/Restringido según LOPD
365 vencimiento_examen TEXT,
366 entidad_medica TEXT,
367 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
368 )
369 ''')
370
371 # 5. Inspecciones de Campo (Checklists Dinámicos)
372 c.execute('''
373 CREATE TABLE IF NOT EXISTS sst_inspecciones (
374 id INTEGER PRIMARY KEY AUTOINCREMENT,
375 fecha TEXT,
376 area TEXT,
377 proceso TEXT,
378 tipo_inspeccion TEXT, -- Puestos de trabajo, EPP, Alturas, Eléctrica
379 inspector_id INTEGER,
380 ubicacion TEXT,
381 nivel_riesgo_estimado TEXT,
382 estado TEXT DEFAULT 'En proceso', -- En proceso, Finalizada, Cerrada
383
384 -- Legado / Adicionales
385 proyecto_id INTEGER,
386 entidad TEXT, -- Empresa o Contratista
387 datos_json TEXT, -- Estructura flexible para checklist respuestas
388 geolocalizacion TEXT,
389 foto_evidencia_url TEXT,
390 firma_inspector_url TEXT,
391 firma_auditado_url TEXT,
392 calificacion_final REAL DEFAULT 100.0,
393
394 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id) ON DELETE CASCADE,
395 FOREIGN KEY (inspector_id) REFERENCES usuarios(id) ON DELETE SET NULL
396 )
397 ''')
398
399 # Hallazgos de Inspección (Reporte de Hallazgos Pro)
400 c.execute('''
401 CREATE TABLE IF NOT EXISTS sst_hallazgos (
402 id INTEGER PRIMARY KEY AUTOINCREMENT,
403 inspeccion_id INTEGER,
404 tipo_hallazgo TEXT, -- Acto Inseguro, Condición Insegura, Auditoría, Reporte Externo
405 fecha_deteccion TEXT,
406 area_o_ubicacion TEXT,
407 proceso_o_actividad TEXT,
408 usuario_reporta_id INTEGER,
409 descripcion TEXT,
410 causa_probable TEXT,
411 categoria_hallazgo TEXT,
412 nivel_riesgo TEXT, -- Bajo, Medio, Alto, Crítico
413 evidencia_url TEXT,
414 documentos_adjuntos_json TEXT,
415 comentarios_json TEXT,
416 accion_correctiva_id INTEGER, -- Link a sst_plan_accion o sst_capa
417 estado TEXT DEFAULT 'Abierto', -- Abierto, En proceso, Pendiente verificación, Cerrado
418 FOREIGN KEY (inspeccion_id) REFERENCES sst_inspecciones(id),
419 FOREIGN KEY (usuario_reporta_id) REFERENCES usuarios(id),
420 FOREIGN KEY (accion_correctiva_id) REFERENCES sst_plan_accion(id)
421 )
422 ''')
423
424 # Migración segura para sst_hallazgos (campos profesionales)
425 for col, ctype in [
426 ('fecha_deteccion', 'TEXT'),
427 ('area_o_ubicacion', 'TEXT'),
428 ('proceso_o_actividad', 'TEXT'),
429 ('usuario_reporta_id', 'INTEGER'),
430 ('causa_probable', 'TEXT'),
431 ('categoria_hallazgo', 'TEXT'),
432 ('documentos_adjuntos_json', 'TEXT'),
433 ('comentarios_json', 'TEXT'),
434 ('responsable_id', 'INTEGER'),
435 ('item_id', 'INTEGER')
436 ]:
437 try: c.execute(f"ALTER TABLE sst_hallazgos ADD COLUMN {col} {ctype}")
438 except: pass
439
440 # 6. Acciónes Correctivas y Preventivas (CAPA / Planes de Acción)
441 c.execute('''
442 CREATE TABLE IF NOT EXISTS sst_capa (
443 id INTEGER PRIMARY KEY AUTOINCREMENT,
444 fuente_id INTEGER, -- ID de accidente, auditoría o inspección
445 fuente_tipo TEXT, -- 'Accidente', 'Inspección', 'Auditoría'
446 hallazgo TEXT,
447 analisis_causa TEXT,
448 accion_propuesta TEXT,
449 responsable_id INTEGER,
450 fecha_compromiso TEXT,
451 fecha_cierre TEXT,
452 estado TEXT DEFAULT 'Abierta',
453 reincidencia BOOLEAN DEFAULT 0,
454 FOREIGN KEY (responsable_id) REFERENCES usuarios(id)
455 )
456 ''')
457
458 # Tabla para gestionar plantillas de checklists reutilizables (SST Pro)
459 c.execute('''
460 CREATE TABLE IF NOT EXISTS sst_inspeccion_plantillas (
461 id INTEGER PRIMARY KEY AUTOINCREMENT,
462 nombre TEXT,
463 descripcion TEXT,
464 categoria TEXT, -- Seguridad General, Alturas, EPP, Maquinaria, etc.
465 area TEXT,
466 nivel_riesgo TEXT,
467 fecha_creacion TEXT,
468 estado TEXT DEFAULT 'Activo'
469 )
470 ''')
471
472 c.execute('''
473 CREATE TABLE IF NOT EXISTS sst_inspeccion_items (
474 id INTEGER PRIMARY KEY AUTOINCREMENT,
475 plantilla_id INTEGER,
476 item_texto TEXT,
477 categoria_item TEXT,
478 FOREIGN KEY (plantilla_id) REFERENCES sst_inspeccion_plantillas(id)
479 )
480 ''')
481
482 c.execute('''
483 CREATE TABLE IF NOT EXISTS sst_inspeccion_respuestas (
484 id INTEGER PRIMARY KEY AUTOINCREMENT,
485 inspeccion_id INTEGER,
486 item_id INTEGER,
487 cumple BOOLEAN, -- 1 o 0
488 observaciones TEXT,
489 evidencia_ruta TEXT,
490 hallazgo_id INTEGER,
491 serial_equipo TEXT,
492 FOREIGN KEY (inspeccion_id) REFERENCES sst_inspecciones(id),
493 FOREIGN KEY (item_id) REFERENCES sst_inspeccion_items(id),
494 FOREIGN KEY (hallazgo_id) REFERENCES sst_hallazgos(id)
495 )
496 ''')
497
498 c.execute('''
499 CREATE TABLE IF NOT EXISTS sst_acciones_correctivas (
500 id INTEGER PRIMARY KEY AUTOINCREMENT,
501 accidente_id INTEGER, -- Para accidentes
502 hallazgo_id INTEGER, -- Para hallazgos de inspección
503 accion_propuesta TEXT,
504 responsable_id INTEGER,
505 fecha_compromiso TEXT,
506 fecha_creacion TEXT,
507 prioridad TEXT DEFAULT 'Media',
508 estado TEXT DEFAULT 'Pendiente',
509 FOREIGN KEY (accidente_id) REFERENCES accidentes_laborales(id),
510 FOREIGN KEY (hallazgo_id) REFERENCES sst_hallazgos(id),
511 FOREIGN KEY (responsable_id) REFERENCES usuarios(id)
512 )
513 ''')
514
515
516 # Tabla espejo o alias para compatibilidad con servicios extendidos (sst_plan_accion)
517 c.execute('''
518 CREATE TABLE IF NOT EXISTS sst_plan_accion (
519 id INTEGER PRIMARY KEY AUTOINCREMENT,
520 descripcion TEXT,
521 prioridad TEXT,
522 estado TEXT DEFAULT 'Pendiente',
523 fecha_limite TEXT,
524 responsable_id INTEGER,
525 proyecto_id INTEGER,
526 FOREIGN KEY (responsable_id) REFERENCES usuarios(id),
527 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id)
528 )
529 ''')
530 for col, ctype in [('investigacion_id', 'INTEGER'), ('actividad', 'TEXT')]:
531 try: c.execute(f"ALTER TABLE sst_plan_accion ADD COLUMN {col} {ctype}")
532 except: pass
533
534 # --- MÓDULO SST CONTROL CENTER PRO (REESTRUCTURACIÓN) ---
535
536 # 5. Pipeline y Gestión de Eventos
537 for tbl in ['accidentes_laborales', 'sst_incidentes']:
538 for col, ctype in [('etapa_flujo', 'TEXT DEFAULT "Reportado"'), ('prioridad', 'TEXT DEFAULT "Media"'), ('riesgo_score', 'INTEGER DEFAULT 0')]:
539 try: c.execute(f"ALTER TABLE {tbl} ADD COLUMN {col} {ctype}")
540 except: pass
541
542 # 6. Consola de Investigación Avanzada
543 for col, ctype in [
544 ('metodologia_5_porques', 'TEXT'),
545 ('metodologia_ishikawa', 'TEXT'),
546 ('arbol_causas_json', 'TEXT'),
547 ('analisis_ia_sara', 'TEXT'),
548 ('severidad_dias_perdidos', 'INTEGER DEFAULT 0')
549 ]:
550 try: c.execute(f"ALTER TABLE sst_investigaciones ADD COLUMN {col} {ctype}")
551 except: pass
552
553 # 7. Motor de Planes de Acción Elite
554 for col, ctype in [
555 ('tipo_accion', 'TEXT DEFAULT "Correctiva"'),
556 ('prioridad', 'TEXT DEFAULT "Media"'),
557 ('costo_estimado', 'REAL DEFAULT 0'),
558 ('avance_progreso', 'INTEGER DEFAULT 0')
559 ]:
560 try: c.execute(f"ALTER TABLE sst_plan_accion ADD COLUMN {col} {ctype}")
561 except: pass
562
563 # 8. Metadatos de Seguridad (Para KPIs Dinámicos)
564 c.execute('''
565 CREATE TABLE IF NOT EXISTS sst_indicadores_mensuales (
566 id INTEGER PRIMARY KEY AUTOINCREMENT,
567 mes_anio TEXT UNIQUE, -- Ej: 2024-03
568 horas_hombre_trabajadas INTEGER,
569 num_trabajadores INTEGER,
570 tasa_frecuencia REAL,
571 indice_severidad REAL,
572 tasa_mortalidad REAL
573 )
574 ''')
575
576 # 9. Historial de Chat (SARA IA) - Memoria Persistente
577 c.execute('''
578 CREATE TABLE IF NOT EXISTS sst_chat_history (
579 id INTEGER PRIMARY KEY AUTOINCREMENT,
580 rol_nombre TEXT,
581 usuario_id INTEGER,
582 mensaje_usuario TEXT,
583 respuesta_ia TEXT,
584 timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
585 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
586 )
587 ''')
588
589 # Investigaciones Detalladas
590 c.execute('''
591 CREATE TABLE IF NOT EXISTS sst_investigaciones (
592 id INTEGER PRIMARY KEY AUTOINCREMENT,
593 relacion_tipo TEXT, -- 'Accidente' o 'Incidente'
594 relacion_id INTEGER,
595 metodo TEXT, -- 'Arbol de Causas', '5 Porques'
596 hallazgos TEXT,
597 conclusiones TEXT,
598 investigador_id INTEGER,
599 fecha_investigacion TEXT,
600 FOREIGN KEY (investigador_id) REFERENCES usuarios(id)
601 )
602 ''')
603
604 # 7. Auditoría Inmutable (Log de Cumplimiento)
605 c.execute('''
606 CREATE TABLE IF NOT EXISTS sst_audit_trail (
607 id INTEGER PRIMARY KEY AUTOINCREMENT,
608 usuario_id INTEGER,
609 timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
610 modulo TEXT,
611 accion TEXT,
612 valor_anterior TEXT,
613 valor_nuevo TEXT,
614 hash_integridad TEXT -- Firmado para inmutabilidad simulada
615 )
616 ''')
617
618 # 8. Auditoría Operativa (Usada por servicios_sst_ext)
619 c.execute('''
620 CREATE TABLE IF NOT EXISTS sst_auditoria (
621 id INTEGER PRIMARY KEY AUTOINCREMENT,
622 usuario_id INTEGER,
623 accion TEXT,
624 modulo TEXT,
625 referencia_id INTEGER,
626 detalles TEXT,
627 fecha TEXT,
628 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
629 )
630 ''')
631
632 # Tablas de Accidentes e Incidentes (Mejoradas)
633 c.execute('''
634 CREATE TABLE IF NOT EXISTS accidentes_laborales (
635 id INTEGER PRIMARY KEY AUTOINCREMENT,
636 usuario_id INTEGER,
637 proyecto_id INTEGER,
638 fecha_accidente TEXT,
639 lugar TEXT,
640 descripcion TEXT,
641 gravedad TEXT,
642 testigos TEXT,
643 fecha_reporte TEXT,
644 estado TEXT DEFAULT 'Reportado',
645 evidencia_url TEXT,
646 investigador_id INTEGER,
647 causa_raiz TEXT,
648 tipo_lesion TEXT,
649 parte_cuerpo TEXT,
650 incapacidad_dias INTEGER,
651 reporte_arl TEXT,
652 tipo_vinculacion TEXT,
653 cargo_afectado TEXT,
654 mecanismo_accidente TEXT,
655 agente_accidente TEXT,
656 jornada_suceso TEXT,
657 fecha_notificacion_arl TEXT,
658 FOREIGN KEY (usuario_id) REFERENCES usuarios(id),
659 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id)
660 )
661 ''')
662
663 # Safe fallback migration for FURAT Colombian standards
664 try:
665 c.execute("ALTER TABLE accidentes_laborales ADD COLUMN tipo_vinculacion TEXT")
666 c.execute("ALTER TABLE accidentes_laborales ADD COLUMN cargo_afectado TEXT")
667 c.execute("ALTER TABLE accidentes_laborales ADD COLUMN mecanismo_accidente TEXT")
668 c.execute("ALTER TABLE accidentes_laborales ADD COLUMN agente_accidente TEXT")
669 c.execute("ALTER TABLE accidentes_laborales ADD COLUMN jornada_suceso TEXT")
670 c.execute("ALTER TABLE accidentes_laborales ADD COLUMN fecha_notificacion_arl TEXT")
671 except:
672 pass
673
674 c.execute('''
675 CREATE TABLE IF NOT EXISTS sst_incidentes (
676 id INTEGER PRIMARY KEY AUTOINCREMENT,
677 usuario_id INTEGER,
678 proyecto_id INTEGER,
679 fecha_incidente TEXT,
680 lugar TEXT,
681 descripcion TEXT,
682 fecha_reporte TEXT,
683 estado TEXT DEFAULT 'Reportado',
684 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
685 )
686 ''')
687
688 c.execute('''
689 CREATE TABLE IF NOT EXISTS sst_permisos_trabajo (
690 id INTEGER PRIMARY KEY AUTOINCREMENT,
691 proyecto_id INTEGER,
692 solicitante_id INTEGER,
693 supervisor_id INTEGER,
694 estado TEXT DEFAULT 'Borrador', -- Borrador, Pendiente, Aprobado, Cerrado, Cancelado
695 tipo_trabajo TEXT, -- Alturas, Caliente, Eléctrico, Espacio Confinado, Izaje, etc.
696 fecha_emision TEXT,
697 fecha_vencimiento TEXT,
698 descripcion_tarea TEXT,
699 riesgos_json TEXT, -- Almacena lista de riesgos dinámicos
700 medidas_json TEXT, -- Almacena medidas de control
701 geolocalizacion TEXT,
702 firma_autorizado TEXT,
703 tenant_id TEXT DEFAULT 'default', -- Preparado para SaaS Enterprise
704 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
705 FOREIGN KEY (solicitante_id) REFERENCES usuarios(id),
706 FOREIGN KEY (supervisor_id) REFERENCES usuarios(id)
707 )
708 ''')
709
710 # Migraciones para Permisos de Trabajo Pro
711 for col, ctype in [
712 ('fecha_creacion', 'TEXT'),
713 ('description', 'TEXT'),
714 ('vigencia', 'TEXT'),
715 ('personal_operativo_json', 'TEXT'),
716 ('controles_verificados_json', 'TEXT'),
717 ('aro_id', 'INTEGER'),
718 ('jsa_id', 'INTEGER'),
719 ('avalado_por_she_id', 'INTEGER'),
720 ('fecha_aval_she', 'TEXT'),
721 ('comentarios_she', 'TEXT'),
722 ('usuario_id', 'INTEGER')
723 ]:
724 try: c.execute(f"ALTER TABLE sst_permisos_trabajo ADD COLUMN {col} {ctype}")
725 except: pass
726
727 c.execute('''
728 CREATE TABLE IF NOT EXISTS sst_solicitudes_permisos (
729 id INTEGER PRIMARY KEY AUTOINCREMENT,
730 proyecto_id INTEGER,
731 solicitante_id INTEGER,
732 responsable_sst_id INTEGER,
733 fecha_solicitud TEXT,
734 estado TEXT DEFAULT 'Pendiente',
735 detalles TEXT,
736 comentarios TEXT,
737 consecutivo TEXT,
738 actividad_id INTEGER,
739 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id)
740 )
741 ''')
742
743 # Migración segura para solicitudes
744 for col, ctype in [
745 ('consecutivo', 'TEXT'),
746 ('actividad_id', 'INTEGER'),
747 ('solicitante_id', 'INTEGER'),
748 ('fecha_solicitud', 'TEXT')
749 ]:
750 try: c.execute(f"ALTER TABLE sst_solicitudes_permisos ADD COLUMN {col} {ctype}")
751 except: pass
752
753 # --- MÓDULO DE GESTIÓN DE PERSONAL PRO ---
754 c.execute('''
755 CREATE TABLE IF NOT EXISTS empleados (
756 id INTEGER PRIMARY KEY AUTOINCREMENT,
757 nombre TEXT NOT NULL,
758 tipo_documento TEXT DEFAULT 'Cédula de Ciudadanía',
759 documento TEXT NOT NULL UNIQUE,
760 cargo TEXT,
761 area TEXT,
762 telefono TEXT,
763 correo TEXT,
764 fecha_ingreso TEXT,
765 estado TEXT DEFAULT 'Activo',
766 tipo_contrato TEXT,
767 hoja_vida TEXT,
768 eps TEXT,
769 arl TEXT,
770 fondo_pension TEXT,
771 nivel_riesgo TEXT,
772 ciudad TEXT,
773 centro_trabajo TEXT,
774 proyecto_id INTEGER,
775 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id)
776 )
777 ''')
778
779 for col, ctype in [
780 ('tipo_documento', 'TEXT DEFAULT "Cédula de Ciudadanía"'),
781 ('eps', 'TEXT'), ('arl', 'TEXT'), ('fondo_pension', 'TEXT'),
782 ('nivel_riesgo', 'TEXT'), ('ciudad', 'TEXT'), ('centro_trabajo', 'TEXT'),
783 ('proyecto_id', 'INTEGER'), ('firma_url', 'TEXT')
784 ]:
785 try: c.execute(f"ALTER TABLE empleados ADD COLUMN {col} {ctype}")
786 except: pass
787
788 c.execute('''
789 CREATE TABLE IF NOT EXISTS sst_cursos (
790 id INTEGER PRIMARY KEY AUTOINCREMENT,
791 nombre TEXT NOT NULL,
792 proyecto_id INTEGER,
793 fecha_sesion TEXT,
794 temas_tratados TEXT,
795 descripcion TEXT,
796 duracion TEXT, -- Ej: 40h
797 tipo TEXT, -- Inducción, Reinducción, SST Obligatorio, Técnico
798 periodicidad_reinduccion INTEGER DEFAULT 12, -- Meses para reinducción
799 obligatorio BOOLEAN DEFAULT 1,
800 entidad TEXT, -- SENA, ARL, o Empresa Propia
801 instructor_interno BOOLEAN DEFAULT 0,
802 personal_json TEXT, -- Lista de IDs de trabajadores asistentes
803 observaciones TEXT,
804 estado TEXT DEFAULT 'Activo',
805 fecha_registro TEXT,
806 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id)
807 )
808 ''')
809
810 # Migración segura para campos nuevos
811 for col, ctype in [('proyecto_id', 'INTEGER'), ('fecha_sesion', 'TEXT'), ('temas_tratados', 'TEXT'), ('observaciones', 'TEXT')]:
812 try: c.execute(f"ALTER TABLE sst_cursos ADD COLUMN {col} {ctype}")
813 except: pass
814
815 c.execute('''
816 CREATE TABLE IF NOT EXISTS sst_certificaciones (
817 id INTEGER PRIMARY KEY AUTOINCREMENT,
818 usuario_id INTEGER,
819 tipo TEXT,
820 fecha_emision TEXT,
821 fecha_vencimiento TEXT,
822 entidad TEXT,
823 archivo_url TEXT,
824 estado TEXT DEFAULT 'Vigente',
825 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
826 )
827 ''')
828
829 c.execute('''
830 CREATE TABLE IF NOT EXISTS activos_certificaciones (
831 id INTEGER PRIMARY KEY AUTOINCREMENT,
832 activo_id INTEGER,
833 tipo TEXT,
834 fecha_emision TEXT,
835 fecha_vencimiento TEXT,
836 entidad TEXT,
837 archivo_url TEXT,
838 estado TEXT DEFAULT 'Vigente'
839 )
840 ''')
841
842 c.execute('''
843 CREATE TABLE IF NOT EXISTS inventario_herramientas (
844 id INTEGER PRIMARY KEY AUTOINCREMENT,
845 nombre TEXT,
846 marca TEXT,
847 modelo TEXT,
848 serial TEXT,
849 estado TEXT DEFAULT 'Disponible',
850 responsable TEXT,
851 ubicacion TEXT,
852 fecha_compra TEXT,
853 garantia TEXT,
854 asignado_a_proyecto INTEGER,
855 FOREIGN KEY (asignado_a_proyecto) REFERENCES proyectos(id)
856 )
857 ''')
858
859 # Migraciones para inventario_herramientas
860 for col, ctype in [
861 ('marca', 'TEXT'), ('modelo', 'TEXT'), ('serial', 'TEXT'),
862 ('responsable', 'TEXT'), ('ubicacion', 'TEXT'),
863 ('fecha_compra', 'TEXT'), ('garantia', 'TEXT'),
864 ('categoria_id', 'INTEGER'), ('foto_url', 'TEXT')
865 ]:
866 try: c.execute(f"ALTER TABLE inventario_herramientas ADD COLUMN {col} {ctype}")
867 except: pass
868
869 c.execute('''
870 CREATE TABLE IF NOT EXISTS inventario_materiales (
871 id INTEGER PRIMARY KEY AUTOINCREMENT,
872 nombre TEXT,
873 cantidad REAL,
874 unidad TEXT
875 )
876 ''')
877
878 c.execute('''
879 CREATE TABLE IF NOT EXISTS actividades_proyecto (
880 id INTEGER PRIMARY KEY AUTOINCREMENT,
881 proyecto_id INTEGER,
882 nombre TEXT,
883 descripcion TEXT,
884 tipo_actividad TEXT,
885 prioridad TEXT DEFAULT 'Media', -- Baja, Media, Alta, Crítica
886 duracion_estimada TEXT,
887 requiere_aro BOOLEAN DEFAULT 0,
888 requiere_jsa BOOLEAN DEFAULT 0,
889 requiere_permiso BOOLEAN DEFAULT 0,
890 fecha_inicio TEXT,
891 fecha_fin TEXT,
892 estado TEXT DEFAULT 'Pendiente', -- Pendiente, En proceso, Completada, Retrasada
893 responsable_id INTEGER,
894 responsable_sst_id INTEGER,
895 personal_operativo_json TEXT,
896 tipos_permiso_json TEXT,
897 hora_inicio TEXT,
898 hora_fin TEXT,
899 evidencias_json TEXT,
900 documentos_legales_json TEXT,
901 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
902 FOREIGN KEY (responsable_id) REFERENCES usuarios(id),
903 FOREIGN KEY (responsable_sst_id) REFERENCES usuarios(id)
904 )
905 ''')
906
907 for col, col_type in [
908 ('nombre', 'TEXT'),
909 ('descripcion', 'TEXT'),
910 ('prioridad', "TEXT DEFAULT 'Media'"),
911 ('duracion_estimada', 'TEXT'),
912 ('tipo_actividad', 'TEXT'),
913 ('fecha_inicio', 'TEXT'),
914 ('fecha_fin', 'TEXT'),
915 ('estado', "TEXT DEFAULT 'Pendiente'"),
916 ('requiere_aro', 'BOOLEAN DEFAULT 0'),
917 ('requiere_jsa', 'BOOLEAN DEFAULT 0'),
918 ('requiere_permiso', 'BOOLEAN DEFAULT 0'),
919 ('responsable_sst_id', 'INTEGER'),
920 ('personal_operativo_json', 'TEXT'),
921 ('tipos_permiso_json', 'TEXT'),
922 ('hora_inicio', 'TEXT'),
923 ('hora_fin', 'TEXT')
924 ]:
925 try: c.execute(f"ALTER TABLE actividades_proyecto ADD COLUMN {col} {col_type}")
926 except: pass
927
928 c.execute('''
929 CREATE TABLE IF NOT EXISTS equipos_externos (
930 id INTEGER PRIMARY KEY AUTOINCREMENT,
931 nombre TEXT NOT NULL,
932 empresa_propietaria TEXT,
933 tipo TEXT,
934 contratista TEXT,
935 numero_contrato TEXT,
936 fecha_inicio TEXT,
937 fecha_fin TEXT,
938 valor REAL DEFAULT 0.0,
939 estado TEXT DEFAULT 'Disponible',
940 proyecto_actual_id INTEGER,
941 responsable_actual TEXT,
942 fecha_ingreso TEXT,
943 FOREIGN KEY (proyecto_actual_id) REFERENCES proyectos(id)
944 )
945 ''')
946
947 c.execute('''
948 CREATE TABLE IF NOT EXISTS movimientos_externos (
949 id INTEGER PRIMARY KEY AUTOINCREMENT,
950 equipo_id INTEGER,
951 tipo_movimiento TEXT,
952 proyecto_id INTEGER,
953 usuario_id INTEGER,
954 responsable TEXT,
955 estado_equipo TEXT,
956 notas TEXT,
957 tiene_dano BOOLEAN DEFAULT 0,
958 fecha_movimiento TEXT,
959 firma_datos TEXT,
960 FOREIGN KEY (equipo_id) REFERENCES equipos_externos(id),
961 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
962 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
963 )
964 ''')
965
966 # Seguimiento de Obras y Bitácora
967 c.execute('''
968 CREATE TABLE IF NOT EXISTS seguimiento_obras (
969 id INTEGER PRIMARY KEY AUTOINCREMENT,
970 usuario_id INTEGER,
971 proyecto_id INTEGER,
972 actividad_id INTEGER,
973 fecha TEXT,
974 actividades TEXT,
975 avance_registrado INTEGER,
976 imagen_url TEXT,
977 estado TEXT DEFAULT 'Pendiente', -- Pendiente, Aprobado, Rechazado
978 FOREIGN KEY (usuario_id) REFERENCES usuarios(id),
979 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
980 FOREIGN KEY (actividad_id) REFERENCES actividades_proyecto(id)
981 )
982 ''')
983
984 try: c.execute("ALTER TABLE seguimiento_obras ADD COLUMN estado TEXT DEFAULT 'Pendiente'")
985 except: pass
986 try: c.execute("ALTER TABLE seguimiento_obras ADD COLUMN actividad_id INTEGER")
987 except: pass
988 try: c.execute("ALTER TABLE actividades_proyecto ADD COLUMN avance_porcentaje INTEGER DEFAULT 0")
989 except: pass
990
991 c.execute('''
992 CREATE TABLE IF NOT EXISTS inv_consumo_seguimiento (
993 id INTEGER PRIMARY KEY AUTOINCREMENT,
994 seguimiento_id INTEGER,
995 material_id INTEGER,
996 cantidad REAL,
997 FOREIGN KEY (seguimiento_id) REFERENCES seguimiento_obras(id),
998 FOREIGN KEY (material_id) REFERENCES inv_materiales_pro(id)
999 )
1000 ''')
1001
1002 c.execute('''
1003 CREATE TABLE IF NOT EXISTS novedades_ejecucion (
1004 id INTEGER PRIMARY KEY AUTOINCREMENT,
1005 usuario_id INTEGER,
1006 proyecto_id INTEGER,
1007 tipo TEXT,
1008 descripcion TEXT,
1009 fecha TEXT,
1010 impacto_dias INTEGER,
1011 estado TEXT DEFAULT 'Pendiente',
1012 evidencia_url TEXT,
1013 respuesta_gestion TEXT,
1014 gestionado_por_id INTEGER,
1015 fecha_gestion TEXT,
1016 FOREIGN KEY (usuario_id) REFERENCES usuarios(id),
1017 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
1018 FOREIGN KEY (gestionado_por_id) REFERENCES usuarios(id)
1019 )
1020 ''')
1021
1022 c.execute('''
1023 CREATE TABLE IF NOT EXISTS material_requests (
1024 id INTEGER PRIMARY KEY AUTOINCREMENT,
1025 usuario_id INTEGER,
1026 proyecto_id INTEGER,
1027 prioridad TEXT,
1028 items_json TEXT,
1029 observaciones TEXT,
1030 estado TEXT DEFAULT 'Pendiente',
1031 respuesta_gestion TEXT,
1032 fecha_solicitud TEXT,
1033 FOREIGN KEY (usuario_id) REFERENCES usuarios(id),
1034 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id)
1035 )
1036 ''')
1037 try: c.execute("ALTER TABLE material_requests ADD COLUMN estado TEXT DEFAULT 'Pendiente'")
1038 except: pass
1039 try: c.execute("ALTER TABLE material_requests ADD COLUMN respuesta_gestion TEXT")
1040 except: pass
1041
1042 c.execute('''
1043 CREATE TABLE IF NOT EXISTS proyectos_personal (
1044 id INTEGER PRIMARY KEY AUTOINCREMENT,
1045 proyecto_id INTEGER,
1046 usuario_id INTEGER,
1047 rol_en_proyecto TEXT,
1048 fecha_asignacion TEXT,
1049 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
1050 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
1051 )
1052 ''')
1053 c.execute('''
1054 CREATE TABLE IF NOT EXISTS proyectos_bitacora (
1055 id INTEGER PRIMARY KEY AUTOINCREMENT,
1056 proyecto_id INTEGER,
1057 usuario_id INTEGER,
1058 fecha TEXT,
1059 actividades_realizadas TEXT,
1060 personal_json TEXT,
1061 materiales_json TEXT,
1062 herramientas_json TEXT,
1063 clima TEXT,
1064 incidentes TEXT,
1065 fotos_json TEXT,
1066 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
1067 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
1068 )
1069 ''')
1070
1071 c.execute('''
1072 CREATE TABLE IF NOT EXISTS proyectos_documentos (
1073 id INTEGER PRIMARY KEY AUTOINCREMENT,
1074 proyecto_id INTEGER,
1075 nombre TEXT,
1076 tipo TEXT, -- Plano, Contrato, Informe, Otro
1077 url TEXT,
1078 usuario_id INTEGER,
1079 fecha_subida TEXT,
1080 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
1081 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
1082 )
1083 ''')
1084
1085 # 1. Configuración de Inventario (Submenú 1)
1086 c.execute('''
1087 CREATE TABLE IF NOT EXISTS inv_categorias (
1088 id INTEGER PRIMARY KEY AUTOINCREMENT,
1089 nombre TEXT UNIQUE,
1090 descripcion TEXT,
1091 tipo_control TEXT DEFAULT 'Stock' -- Stock, Serial, Lote
1092 )
1093 ''')
1094
1095 c.execute('''
1096 CREATE TABLE IF NOT EXISTS inv_unidades (
1097 id INTEGER PRIMARY KEY AUTOINCREMENT,
1098 nombre TEXT UNIQUE, -- Unidad, Metro, Global, Kg, etc.
1099 abreviatura TEXT
1100 )
1101 ''')
1102
1103 # 2. Movimientos de Inventario (Kardex) (Submenú 5)
1104 c.execute('''
1105 CREATE TABLE IF NOT EXISTS inv_movimientos (
1106 id INTEGER PRIMARY KEY AUTOINCREMENT,
1107 item_id INTEGER,
1108 item_tipo TEXT, -- 'Herramienta', 'Material', 'Equipo_Externo'
1109 tipo_movimiento TEXT, -- 'Entrada', 'Salida', 'Ajuste', 'Transferencia'
1110 cantidad REAL,
1111 origen TEXT, -- Bodega, Proyecto ID, Proveedor
1112 destino TEXT, -- Bodega, Proyecto ID, Cliente
1113 referencia_factura TEXT,
1114 usuario_id INTEGER,
1115 fecha TEXT,
1116 notas TEXT,
1117 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
1118 )
1119 ''')
1120
1121 # 3. Hoja de Vida de Activos (Historial Profesional)
1122 c.execute('''
1123 CREATE TABLE IF NOT EXISTS inv_hoja_vida (
1124 id INTEGER PRIMARY KEY AUTOINCREMENT,
1125 item_id INTEGER,
1126 item_tipo TEXT, -- 'Herramienta', 'Material', 'Equipo_Externo'
1127 fecha TEXT,
1128 evento TEXT, -- Mantenimiento, Inspección, Traslado, Asignación, Incidente, Reparación
1129 descripcion TEXT,
1130 icon TEXT DEFAULT 'event',
1131 color TEXT DEFAULT 'blue',
1132 usuario_id INTEGER,
1133 FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
1134 )
1135 ''')
1136
1137 # 3. Órdenes de Trabajo (Conexión Operativa)
1138 c.execute('''
1139 CREATE TABLE IF NOT EXISTS inv_ordenes_trabajo (
1140 id INTEGER PRIMARY KEY AUTOINCREMENT,
1141 codigo_ot TEXT UNIQUE,
1142 proyecto_id INTEGER,
1143 tecnico_id INTEGER,
1144 estado TEXT DEFAULT 'Abierta', -- Abierta, Ejecución, Cerrada, Cancelada
1145 fecha_apertura TEXT,
1146 fecha_cierre TEXT,
1147 descripcion_trabajo TEXT,
1148 FOREIGN KEY (proyecto_id) REFERENCES proyectos(id),
1149 FOREIGN KEY (tecnico_id) REFERENCES usuarios(id)
1150 )
1151 ''')
1152
1153 # 4. Asignación de Recursos a OT (Submenú 6)
1154 c.execute('''
1155 CREATE TABLE IF NOT EXISTS inv_asignaciones_ot (
1156 id INTEGER PRIMARY KEY AUTOINCREMENT,
1157 ot_id INTEGER,
1158 item_id INTEGER,
1159 item_tipo TEXT,
1160 cantidad_solicitada REAL,
1161 cantidad_usada REAL DEFAULT 0,
1162 cantidad_devuelta REAL DEFAULT 0,
1163 fecha_asignacion TEXT,
1164 estado TEXT DEFAULT 'Entregado', -- Entregado, Consumido, Devuelto
1165 FOREIGN KEY (ot_id) REFERENCES inv_ordenes_trabajo(id)
1166 )
1167 ''')
1168
1169 # 5. Tipos de Material y Ubicaciones (Submenú 4 y 7)
1170 c.execute('''
1171 CREATE TABLE IF NOT EXISTS inv_tipos_material (
1172 id INTEGER PRIMARY KEY AUTOINCREMENT,
1173 nombre TEXT UNIQUE,
1174 estado TEXT DEFAULT 'Activo'
1175 )
1176 ''')
1177
1178 c.execute('''
1179 CREATE TABLE IF NOT EXISTS inv_ubicaciones (
1180 id INTEGER PRIMARY KEY AUTOINCREMENT,
1181 nombre TEXT UNIQUE,
1182 tipo TEXT, -- Bodega Principal, Vehículo Técnico, Almacén Obra
1183 responsable TEXT,
1184 descripcion TEXT
1185 )
1186 ''')
1187
1188 # 6. Catálogo de Materiales Pro
1189 c.execute('''
1190 CREATE TABLE IF NOT EXISTS inv_materiales_pro (
1191 id INTEGER PRIMARY KEY AUTOINCREMENT,
1192 codigo TEXT UNIQUE,
1193 nombre TEXT,
1194 tipo_id INTEGER,
1195 categoria_id INTEGER,
1196 unidad_id INTEGER,
1197 stock_actual REAL DEFAULT 0,
1198 stock_minimo REAL DEFAULT 0,
1199 ubicacion_id INTEGER,
1200 estado TEXT DEFAULT 'Activo',
