1069 lines
60 KiB
Plaintext
1069 lines
60 KiB
Plaintext
================================================================================
|
||
PLAN DE EVOLUCIÓN: BOT WHATSAPP → ERP MULTI-MÓDULO
|
||
Proyecto: Panel de Laboratorio + WhatsApp Bot Manager
|
||
Fecha: Abril 2026
|
||
================================================================================
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
1. ESTADO ACTUAL — QUÉ TENEMOS
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
MÓDULOS YA OPERATIVOS:
|
||
✔ WhatsApp Bot – respuestas automáticas, menús, plantillas Meta
|
||
✔ Conversaciones – bandeja de entrada, operadores asignados
|
||
✔ Mensajes Programados – campañas por fecha/hora
|
||
✔ Pacientes – ficha clínica, historial
|
||
✔ Domicilios – agenda de servicios a domicilio con flujo de estados
|
||
✔ Enfermeras/Personal – portal propio, agenda diaria
|
||
✔ Órdenes Médicas – PDF adjunto, autorización
|
||
✔ Formularios – builder drag-drop, firma digital, enlace público
|
||
✔ Reportes – ingresos, rendimiento de enfermeros, pagos
|
||
✔ Actividad/Auditoría – log de cambios por usuario
|
||
✔ Usuarios & Roles – RBAC completo (roles + role_modules)
|
||
✔ Configuración – tarifas, laboratorio, WhatsApp
|
||
|
||
ARQUITECTURA ACTUAL:
|
||
• Todos los archivos PHP en la raíz del proyecto (lab_*.php, index.php…)
|
||
• API separada en /api/ y /api/lab/
|
||
• Clases en /classes/ y /services/
|
||
• Base de datos: 34 tablas, una sola BD "usite_whatsapp_bot"
|
||
• RBAC: tabla roles + role_modules + SYSTEM_MODULES en config.php
|
||
• Sesiones PHP nativas (login en admin_users)
|
||
|
||
PROBLEMA PRINCIPAL PARA CRECER:
|
||
• Sin sistema de enrutamiento → cada módulo es un archivo suelto en raíz
|
||
• SYSTEM_MODULES hardcodeado en config.php (hay que editarlo cada vez)
|
||
• No hay separación de carpetas por módulo (todo mezclado)
|
||
• Navegación duplicada en cada .php del módulo lab
|
||
• Sin un punto de entrada único (todo camino directo al .php)
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
2. VISIÓN TARGET — ERP MULTI-MÓDULO
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
CONCEPTO:
|
||
Un sistema central con un panel unificado donde cada "módulo" es un paquete
|
||
autocontenido. El core gestiona: autenticación, routing, menú lateral,
|
||
RBAC, notificaciones y eventos. Los módulos se enchufan al core sin
|
||
modificar archivos existentes.
|
||
|
||
MÓDULOS PLANIFICADOS (oleadas):
|
||
|
||
OLEADA 0 – Ya en producción (refactorizar para que usen la nueva estructura)
|
||
- whatsapp_bot → Bot + Conversaciones + Plantillas
|
||
- lab_domicilios → Agenda de domicilios
|
||
- lab_pacientes → Pacientes y fichas
|
||
- lab_formularios → Builder de formularios
|
||
- lab_reportes → Reportes e indicadores
|
||
- lab_ordenes → Órdenes médicas
|
||
- lab_enfermeras → Gestión de personal clínico
|
||
- sistema → Usuarios, Roles, Configuración
|
||
|
||
OLEADA 1 – Nuevos módulos solicitados
|
||
- turnero → Sistema de turnos presenciales en recepción
|
||
|
||
OLEADA 2 – Módulos futuros probables
|
||
- registro_exams → Registro directo de exámenes de laboratorio
|
||
(sin domicilio: paciente llega a la sede)
|
||
- facturacion → Facturación electrónica / DIAN (Colombia)
|
||
- inventario → Reactivos, insumos, stock mínimo
|
||
- citas → Agenda de citas con calendario visual
|
||
- resultados → Entrega digital de resultados (portal paciente)
|
||
- crm_pacientes → Campañas, seguimientos, cohortes
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
3. NUEVA ESTRUCTURA DE CARPETAS
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
/
|
||
├── core/ ← Núcleo del ERP (NO tocar por módulos)
|
||
│ ├── App.php ← Bootstrap, registro de módulos
|
||
│ ├── Router.php ← Enrutador simple (mapea URL→módulo/acción)
|
||
│ ├── Auth.php ← Login/logout/sesión (extraído de config.php)
|
||
│ ├── Rbac.php ← hasModule(), requireModule(), permisos
|
||
│ ├── ModuleRegistry.php ← Catálogo dinámico de módulos instalados
|
||
│ ├── Layout.php ← Renderiza sidebar, navbar, footer
|
||
│ └── Helpers.php ← Funciones globales (esc, jsonOk, etc.)
|
||
│
|
||
├── modules/ ← Un subdirectorio por módulo
|
||
│ ├── whatsapp_bot/
|
||
│ │ ├── module.php ← Descriptor: nombre, slug, icono, permisos
|
||
│ │ ├── views/ ← Las páginas (ex lab_*.php migradas)
|
||
│ │ └── api/ ← Endpoints REST propios del módulo
|
||
│ │
|
||
│ ├── domicilios/
|
||
│ │ ├── module.php
|
||
│ │ ├── views/
|
||
│ │ └── api/
|
||
│ │
|
||
│ ├── turnero/ ← NUEVO ★ (Oleada 1)
|
||
│ │ ├── module.php
|
||
│ │ ├── views/
|
||
│ │ │ ├── dashboard.php ← Panel administrador (resumen del día)
|
||
│ │ │ ├── kiosko.php ← Pantalla táctil tomar turno (sin login)
|
||
│ │ │ ├── display.php ← Pantalla TV cola general (sin login)
|
||
│ │ │ ├── recepcion.php ← Puesto recepcionista (llamar, solicitud, lugar)
|
||
│ │ │ ├── lugar.php ← Puesto de servicio: llama turno, firma, atiende
|
||
│ │ │ └── configuracion.php ← Lugares, exámenes, prioridades, sesiones
|
||
│ │ └── api/
|
||
│ │ ├── create_turno.php ← Genera nuevo turno (kiosko)
|
||
│ │ ├── llamar_turno.php ← Llama siguiente de una cola
|
||
│ │ ├── create_solicitud.php ← Crea solicitud con exámenes, pago y lugar destino
|
||
│ │ ├── cambiar_estado.php ← Avanza estado del turno
|
||
│ │ ├── get_cola.php ← Cola de un lugar o recepción
|
||
│ │ ├── sse_turno.php ← Server-Sent Events para pantallas TV
|
||
│ │ ├── send_consentimiento.php ← Envía enlace de consentimiento por WhatsApp
|
||
│ │ └── get_consentimientos.php ← Estado de firmas del turno
|
||
│ │
|
||
│ ├── registro_exams/ ← PENDIENTE — Oleada 2
|
||
│ │ ├── module.php
|
||
│ │ ├── views/
|
||
│ │ │ ├── registrar.php
|
||
│ │ │ ├── lista.php
|
||
│ │ │ └── detalle.php
|
||
│ │ └── api/
|
||
│ │ ├── save_examen.php
|
||
│ │ ├── get_examenes.php
|
||
│ │ ├── cambiar_estado.php
|
||
│ │ └── imprimir_etiqueta.php
|
||
│ │
|
||
│ └── sistema/
|
||
│ ├── module.php
|
||
│ ├── views/
|
||
│ │ ├── usuarios.php ← lab_usuarios.php migrado
|
||
│ │ └── configuracion.php
|
||
│ └── api/
|
||
│
|
||
├── shared/ ← Componentes reutilizables entre módulos
|
||
│ ├── components/
|
||
│ │ ├── sidebar.php ← Menú lateral dinámico (según módulos del rol)
|
||
│ │ ├── navbar.php
|
||
│ │ ├── page_header.php
|
||
│ │ └── modal_confirm.php
|
||
│ └── js/
|
||
│ ├── erp-core.js ← fetch wrapper, toasts, eventos globales
|
||
│ └── erp-table.js ← Tablas con filtro, paginación, export
|
||
│
|
||
├── classes/ ← (ya existe, mantener)
|
||
├── services/ ← (ya existe, mantener)
|
||
├── api/ ← API global (ya existe, mantener para bot)
|
||
├── config/
|
||
│ └── config.php ← Simplificado: SOLO BD y constantes base
|
||
│
|
||
├── public/ ← (opcional futuro) assets compilados
|
||
│ └── assets/
|
||
│
|
||
└── index.php ← Punto de entrada único → instancia App.php
|
||
|
||
|
||
NOTA SOBRE MIGRACIÓN SIN ROMPER NADA:
|
||
Los archivos lab_*.php actuales permanecen en raíz mientras se migran.
|
||
Se crea un alias: cada modules/X/views/Y.php incluye el legacy si aún no
|
||
se ha reescrito. No hay "big bang rewrite".
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
4. SISTEMA DE ROLES Y PERMISOS (RBAC EXPANDIDO)
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
MODELO ACTUAL:
|
||
roles (id, name, slug, color, is_system)
|
||
└── role_modules (role_id, module_slug) ← solo read/write implícito
|
||
|
||
MODELO PROPUESTO — RBAC con acciones:
|
||
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ roles │
|
||
│ id | name | slug | description | color | is_system │
|
||
└──────────────────┬──────────────────────────────────────────┘
|
||
│ 1:N
|
||
┌──────────────────▼──────────────────────────────────────────┐
|
||
│ role_permissions (reemplaza role_modules con más granularidad)
|
||
│ id | role_id | module_slug | can_view | can_create │
|
||
│ can_edit | can_delete | can_export | extra_json │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
|
||
extra_json ejemplos:
|
||
turnero → {"puede_llamar": true, "puede_reasignar": false}
|
||
reportes → {"rango_max_dias": 90}
|
||
whatsapp → {"puede_broadcast": true}
|
||
|
||
ROLES DEL SISTEMA A DEFINIR:
|
||
|
||
Slug Nombre Descripción
|
||
─────────────────────────────────────────────────────────────────
|
||
superadmin Super Admin Acceso total, configura el sistema
|
||
admin Administrador Acceso total sin configuración técnica
|
||
recepcionista Recepcionista Turnero + Pacientes (Oleada 1)
|
||
bacteriologo Bacteriólogo Registro exámenes + Resultados (Oleada 2)
|
||
enfermero Enfermero Portal domicilios (ya existe)
|
||
supervisor Supervisor Reportes + sin acceso a config
|
||
operador_bot Operador WhatsApp Solo bandeja de conversaciones
|
||
readonly Solo lectura Ver dashboards sin editar
|
||
|
||
REGLA: is_system=1 en superadmin y admin → no se pueden borrar.
|
||
Los demás roles son personalizables por el cliente.
|
||
|
||
FLUJO DE VERIFICACIÓN EN UNA VISTA:
|
||
1. ¿Está logueado? → sino → login
|
||
2. ¿El rol tiene module_slug? → sino → 403 sin módulo
|
||
3. ¿La acción requiere can_edit? → verificar permiso específico
|
||
4. ¿Hay restricción extra_json? → verificar campo relevante
|
||
|
||
HELPER PROPUESTO (core/Rbac.php):
|
||
hasModule($slug) → bool (ya existe en helpers)
|
||
canDo($slug, $action) → bool (nuevo, $action = view/create/edit/delete/export)
|
||
requireAction($slug, $action) → lanza 403 si no tiene permiso
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
5. MÓDULO TURNERO — DISEÑO DETALLADO
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
PROPÓSITO:
|
||
Diseñar, desarrollar e implementar un Sistema de Turnero Inteligente
|
||
integrado con gestión de pacientes, clasificación por prioridades,
|
||
flujo de atención por áreas (Recepción y Toma de Muestras) y envío
|
||
automatizado de consentimientos informados mediante WhatsApp.
|
||
|
||
El sistema optimiza la atención, mejora la trazabilidad del paciente
|
||
y garantiza el cumplimiento legal mediante la gestión digital de
|
||
consentimientos.
|
||
|
||
──── 5.1 PANTALLAS / INTERFACES ────────────────────────────────────────────
|
||
|
||
A) Kiosko (tablet/touch, sin login)
|
||
→ el paciente selecciona su tipo de prioridad y obtiene su turno
|
||
|
||
B) Pantalla TV / Display (pantalla grande, sin login, una por lugar)
|
||
→ muestra la cola del lugar y el turno siendo llamado en tiempo real
|
||
→ param ?lugar_id=X para que cada sala tenga su propia pantalla
|
||
|
||
C) Puesto Recepción (login requerido)
|
||
→ llama turnos de la cola general
|
||
→ vincula paciente, registra exámenes, recibe pago
|
||
→ crea la Solicitud Interna y asigna el turno a un Lugar
|
||
|
||
D) Puesto Lugar / Estación de Servicio (login requerido, genérico)
|
||
→ llama turnos de su propia cola (los asignados a él por recepción)
|
||
→ muestra exámenes requeridos y estado de consentimientos
|
||
• el paciente firma directamente en la pantalla del puesto (o en su celular)
|
||
→ realiza el servicio y finaliza el turno
|
||
→ La misma vista sirve para: Toma de Muestras 1, Toma de Muestras 2,
|
||
Rayos X, Ultrasonido, o cualquier área que se configure
|
||
|
||
E) Panel Admin Turnero (login requerido)
|
||
→ configura Lugares, exámenes, prioridades, sesiones
|
||
|
||
──── 5.2 SISTEMA DE PRIORIDADES ────────────────────────────────────────────
|
||
|
||
Código Tipo de paciente Orden motor de cola
|
||
──────────────────────────────────────────────────────
|
||
A Niños 1 (máxima prioridad)
|
||
B Embarazadas 2
|
||
C Adulto mayor 3
|
||
D Discapacidad 4
|
||
E Paciente general 5
|
||
F Muestras pendientes 6 (menor prioridad)
|
||
|
||
Regla: dentro del mismo código se respeta el orden de llegada (FIFO).
|
||
El motor de cola mezcla todas las filas usando el peso de prioridad + timestamp.
|
||
|
||
──── 5.3 FLUJO POR ÁREAS ────────────────────────────────────────────────────
|
||
|
||
ÁREA 1 — RECEPCIÓN
|
||
═══════════════════
|
||
Estados: espera → en_recepcion → finalizado_recepcion
|
||
|
||
1. Kiosko/recepcionista genera turno (código + prioridad)
|
||
2. Pantalla TV muestra la cola
|
||
3. Recepcionista llama siguiente turno → estado "en_recepcion"
|
||
→ (opcional) Mensaje WhatsApp al paciente con su código de turno
|
||
4. Se vincula el turno con un número de ventanilla
|
||
5. Se registran:
|
||
• Datos personales del paciente (buscar/crear en lab_pacientes)
|
||
• Exámenes requeridos (lista de exam_tipos)
|
||
6. Sistema consulta si los exámenes requieren consentimientos
|
||
7. Si hay consentimientos pendientes:
|
||
→ Se genera enlace único y seguro por paciente
|
||
→ Se envía por WhatsApp usando WhatsAppService + plantilla aprobada Meta
|
||
Si no se requieren → pasa directamente a área de muestras
|
||
8. Turno avanza → "esperando_consentimiento" o "en_espera_muestra"
|
||
|
||
ÁREA 2 — TOMA DE MUESTRAS
|
||
══════════════════════════
|
||
Estados: en_espera_muestra → en_muestra → finalizado
|
||
|
||
1. Bacteriólogo/auxiliar llama siguiente de la cola de muestras
|
||
2. Sistema BLOQUEA la atención si no existen consentimientos firmados
|
||
→ muestra alerta visual; no permite avanzar el estado
|
||
3. Si todos los consentimientos están firmados:
|
||
→ Estado "en_muestra"
|
||
→ Se validan los exámenes registrados en recepción
|
||
4. Al terminar la toma: estado "finalizado"
|
||
|
||
──── 5.4 CONSENTIMIENTOS INFORMADOS ─────────────────────────────────────────
|
||
|
||
INTEGRACIÓN CON MÓDULO FORMULARIOS (REUTILIZAR lo que ya existe):
|
||
• Los consentimientos son Formularios del módulo lab_formularios/
|
||
• Se marca en la configuración del formulario si es de tipo "consentimiento"
|
||
usando un campo nuevo: tipo ENUM(formulario, consentimiento)
|
||
• Enlace público ya existe en el módulo → se reutiliza tal cual
|
||
• Firma digital ya implementada → se reutiliza (canvas + checkbox legal)
|
||
|
||
CATÁLOGO DE TIPOS DE EXAMEN (exam_tipos):
|
||
• Listado maestro de exámenes que ofrece el laboratorio (código + nombre)
|
||
• Se crea en FASE 3 (Oleada 1) para dar soporte al turnero
|
||
• La misma tabla se usa en Oleada 2 (registro_exams) sin cambios
|
||
• Administrado desde la vista Configuración > Exámenes y Consentimientos
|
||
|
||
RELACIÓN EXAMEN ↔ CONSENTIMIENTO (exam_tipo_consentimientos):
|
||
• Un consentimiento (formulario) puede cubrir VARIOS tipos de examen
|
||
• Un examen puede estar en un solo consentimiento o en ninguno
|
||
• Se configura UNA VEZ en el panel de administración, no en cada turno
|
||
• Ejemplo:
|
||
"Toma de muestra de sangre" → consentimiento id=3 ("Consentimiento hemograma")
|
||
"Glucosa en ayunas" → consentimiento id=3
|
||
"Cultivo de orina" → consentimiento id=5 ("Consentimiento urocultivo")
|
||
"Presión arterial" → (sin consentimiento)
|
||
|
||
FLUJO DE CONSENTIMIENTOS:
|
||
1. Recepción selecciona exámenes del turno (de la lista exam_tipos)
|
||
2. Sistema busca en exam_tipo_consentimientos qué formularios aplican
|
||
para los exámenes seleccionados → deduplica si varios exámenes
|
||
comparten el mismo consentimiento → lista mínima de consentimientos
|
||
3. Por cada consentimiento pendiente:
|
||
• Se genera un token único (UUID) → link = /ver_formulario.php?token=XXX
|
||
• Se registra en turnero_consentimientos con estado "pendiente"
|
||
4. (Opcional) Recepción envía enlace por WhatsApp para pre-firma
|
||
mientras el paciente espera en cola del Lugar
|
||
5. En el Lugar (segunda llamada), el paciente puede firmar:
|
||
OPCIÓN A: Hace clic en el enlace de WhatsApp en su celular
|
||
OPCIÓN B: El auxiliar muestra la pantalla del puesto al paciente
|
||
y firma directamente ahí (mismo ver_formulario_enviado.php)
|
||
6. Al firmar → estado "firmado" en turnero_consentimientos
|
||
7. Vista del Lugar muestra ✓ verde / ✗ rojo en tiempo real (polling 5s)
|
||
BLOQUEO total si alguno pendiente → no se puede iniciar el servicio
|
||
|
||
MOMENTO DE LA FIRMA:
|
||
• Preferiblemente antes de la segunda llamada (via WhatsApp, mientras espera)
|
||
• Alternativamente EN la estación del Lugar (tablet del puesto)
|
||
• NUNCA después de iniciado el servicio
|
||
|
||
EVIDENCIA REGISTRADA POR FIRMA:
|
||
• Fecha y hora exacta
|
||
• IP del firmante
|
||
• User-Agent (dispositivo)
|
||
• Versión del formulario/consentimiento al momento de firmar
|
||
|
||
──── 5.5 TABLAS BD NUEVAS ────────────────────────────────────────────────────
|
||
|
||
exam_tipos ← catálogo maestro de exámenes del laboratorio
|
||
id, codigo VARCHAR(20), ← ej. "HEM", "GLU", "URIN"
|
||
nombre VARCHAR(150), ← ej. "Hemograma completo"
|
||
categoria VARCHAR(80), ← ej. "Hematología", "Química"
|
||
activo TINYINT(1)
|
||
NOTA: Esta tabla es compartida con Oleada 2 (registro_exams).
|
||
En Oleada 2 se le agregan columnas precio_base, requiere_ayunas, etc.
|
||
|
||
exam_tipo_consentimientos ← relación M:N examen ↔ consentimiento
|
||
id,
|
||
exam_tipo_id INT FK exam_tipos,
|
||
formulario_id INT FK lab_formularios, ← debe tener tipo='consentimiento'
|
||
UNIQUE KEY (exam_tipo_id, formulario_id)
|
||
NOTA: Si un examen no tiene registro aquí, no se exige consentimiento.
|
||
Si varios exámenes del mismo turno apuntan al mismo formulario_id,
|
||
se genera UN SOLO consentimiento (deduplicado en la lógica PHP).
|
||
|
||
turnero_lugares ← sub-módulo: estaciones/lugares de servicio
|
||
id, nombre VARCHAR(100), ← ej. "Toma de Muestras 1", "Rayos X"
|
||
descripcion TEXT,
|
||
activo TINYINT(1),
|
||
sort_order INT ← orden en la pantalla TV general
|
||
NOTA: Recepción NO es un lugar; es el primer paso implícito del flujo.
|
||
Cada lugar tiene su propia cola y su propia pantalla TV.
|
||
|
||
turnero_prioridades ← catálogo editable de códigos A-F
|
||
id, codigo CHAR(1) UNIQUE, nombre VARCHAR(100),
|
||
orden_peso INT, ← número menor = mayor prioridad
|
||
color VARCHAR(7),
|
||
activo TINYINT(1)
|
||
|
||
turnero_sesiones
|
||
id, fecha DATE,
|
||
abierto_por INT FK admin_users, cerrado_por INT FK admin_users,
|
||
inicio_at DATETIME, fin_at DATETIME
|
||
|
||
turnero_turnos
|
||
id, sesion_id FK turnero_sesiones,
|
||
numero INT, ← correlativo dentro de la sesión
|
||
codigo VARCHAR(10), ← "A001", "B012"
|
||
prioridad_id INT FK turnero_prioridades,
|
||
paciente_nombre VARCHAR(150), ← capturado en kiosko (opcional)
|
||
paciente_cel VARCHAR(20),
|
||
estado ENUM(
|
||
espera, ← código asignado, en cola general
|
||
en_recepcion, ← recepcionista lo está procesando
|
||
en_espera_lugar, ← solicitud creada, en cola del Lugar
|
||
en_servicio, ← siendo atendido en el Lugar
|
||
finalizado, ← proceso completo
|
||
ausente, ← no se presentó
|
||
cancelado
|
||
),
|
||
lugar_destino_id INT FK turnero_lugares NULL, ← asignado por recepción
|
||
creado_at DATETIME,
|
||
llamado_recepcion_at DATETIME,
|
||
inicio_recepcion_at DATETIME,
|
||
fin_recepcion_at DATETIME,
|
||
llamado_lugar_at DATETIME,
|
||
inicio_lugar_at DATETIME,
|
||
fin_lugar_at DATETIME,
|
||
atendido_recepcion_por INT FK admin_users NULL,
|
||
atendido_lugar_por INT FK admin_users NULL
|
||
|
||
turnero_solicitudes ← solicitud interna de agendamiento (crea recepción)
|
||
id,
|
||
turno_id INT FK turnero_turnos UNIQUE, ← 1 solicitud por turno
|
||
paciente_id INT FK lab_pacientes, ← vinculado en recepción
|
||
lugar_id INT FK turnero_lugares, ← lugar de destino
|
||
total_cobrado DECIMAL(10,2),
|
||
metodo_pago ENUM(efectivo, transferencia, tarjeta, eps, cortesia),
|
||
observaciones TEXT,
|
||
creado_por INT FK admin_users,
|
||
creado_at DATETIME
|
||
|
||
turnero_examen_items ← exámenes de la solicitud
|
||
id, solicitud_id FK turnero_solicitudes,
|
||
exam_tipo_id INT FK exam_tipos,
|
||
creado_at DATETIME
|
||
|
||
turnero_consentimientos ← consentimientos del turno (deduplicados)
|
||
id, turno_id FK turnero_turnos,
|
||
formulario_id INT FK lab_formularios,
|
||
token VARCHAR(64) UNIQUE, ← enlace único de firma
|
||
estado ENUM(pendiente, enviado, visto, firmado, rechazado),
|
||
enviado_at DATETIME,
|
||
firmado_at DATETIME,
|
||
ip_firma VARCHAR(45),
|
||
ua_firma VARCHAR(500),
|
||
version_formulario INT ← snapshot de la versión al momento de firma
|
||
|
||
formularios.tipo ← columna nueva en tabla existente lab_formularios
|
||
ALTER TABLE lab_formularios ADD COLUMN tipo
|
||
ENUM('formulario','consentimiento') DEFAULT 'formulario';
|
||
|
||
DIAGRAMA DE RELACIONES CLAVE:
|
||
|
||
lab_formularios (tipo='consentimiento')
|
||
│ 1
|
||
│
|
||
exam_tipo_consentimientos ─────── exam_tipos
|
||
(M:N) │ 1
|
||
│ N
|
||
turnero_examen_items
|
||
│ N
|
||
│ 1
|
||
turnero_solicitudes ───── turnero_lugares
|
||
│ 1
|
||
│ 1
|
||
turnero_turnos
|
||
│ 1
|
||
│ N
|
||
turnero_consentimientos
|
||
(un registro por formulario distinto requerido por el turno)
|
||
|
||
──── 5.6 INTEGRACIONES CON MÓDULOS EXISTENTES ──────────────────────────────
|
||
|
||
• lab_pacientes → buscar/crear paciente al crear la solicitud en recepción
|
||
• lab_formularios → los consentimientos SON formularios del sistema
|
||
• ver_formulario_enviado.php → página pública de firma (ya funcional)
|
||
se abre también desde la pantalla del Lugar
|
||
• WhatsAppService → envío del enlace de consentimiento (opcional, entre llamadas)
|
||
• Plantillas Meta → crear plantilla aprobada "consentimiento_turno"
|
||
• exam_tipos → catálogo compartido con Oleada 2 (registro_exams)
|
||
|
||
──── 5.7 PANTALLA TV / DISPLAY ─────────────────────────────────────────────
|
||
|
||
Hay VARIOS tipos de pantalla TV, todas sin login:
|
||
|
||
TV RECEPCIÓN (?display=recepcion)
|
||
• Cola general (turnos en estado 'espera' ordenados por prioridad)
|
||
• Turno actualmente en recepción (código grande + "DIRÍJASE A RECEPCIÓN")
|
||
|
||
TV POR LUGAR (?display=lugar&lugar_id=X)
|
||
• Cola del Lugar X (turnos en 'en_espera_lugar' con ese lugar_destino_id)
|
||
• Turno en servicio activo del Lugar X (código grande)
|
||
• Cadaestación tiene su propia TV configurada con su lugar_id
|
||
|
||
COMPORTAMIENTO COMÚN:
|
||
• Actualización por SSE en tiempo real sin reload
|
||
• Colores grandes por código de prioridad
|
||
• Animación + sonido corto al llamar un turno
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
6. MÓDULO REGISTRO DE EXÁMENES — DISEÑO DETALLADO [OLEADA 2 — pendiente]
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
CONCEPTO:
|
||
Registrar exámenes de análisis clínico cuando el paciente llega a la sede
|
||
(a diferencia de lab_domicilios que es a domicilio).
|
||
Incluye: recepción de muestra, trazabilidad, estado de procesamiento,
|
||
y eventualmente entrega de resultados.
|
||
|
||
TABLAS BD NUEVAS:
|
||
|
||
exam_tipos
|
||
id, codigo (ej. "HEM", "GLU"), nombre, categoria, precio_base,
|
||
requiere_ayunas TINYINT, instrucciones TEXT, activo
|
||
|
||
exam_ordenes (la "orden de trabajo" del laboratorio)
|
||
id, paciente_id FK lab_pacientes,
|
||
numero_orden VARCHAR(20) UNIQUE, ← ej. "ORD-2026-00123"
|
||
origen ENUM(presencial, domicilio, whatsapp, referido),
|
||
medico_remitente VARCHAR(150),
|
||
entidad_pagadora VARCHAR(150),
|
||
tipo_pago ENUM(particular, eps, convenio),
|
||
total_cobrado DECIMAL(10,2),
|
||
estado ENUM(pendiente, en_proceso, parcial, completado, entregado, anulado),
|
||
observaciones TEXT,
|
||
recibido_por INT FK admin_users,
|
||
creado_at, actualizado_at
|
||
|
||
exam_items (los exámenes individuales dentro de una orden)
|
||
id, orden_id FK exam_ordenes,
|
||
tipo_id FK exam_tipos,
|
||
estado ENUM(pendiente, muestra_tomada, en_analisis, resultado_listo, entregado),
|
||
muestra_tipo VARCHAR(50), ← sangre, orina, hisopado...
|
||
muestra_recibida_at,
|
||
resultado TEXT,
|
||
resultado_pdf VARCHAR(300),
|
||
procesado_por INT FK admin_users,
|
||
entregado_at
|
||
|
||
exam_etiquetas (para imprimir en los tubos)
|
||
id, item_id FK exam_items,
|
||
codigo_barras VARCHAR(50) UNIQUE,
|
||
impreso_at, impreso_por INT FK admin_users
|
||
|
||
FLUJO:
|
||
1. Recepcionista busca/crea paciente (reutiliza lab_pacientes)
|
||
2. Crea orden → agrega exámenes de la lista exam_tipos
|
||
3. Sistema genera número de orden y código de barras por tubo
|
||
4. Se imprime etiqueta (ZPL o PDF)
|
||
5. Bacteriólogo cambia estado → en_análisis → resultado_listo
|
||
6. Administrador entrega resultados (descarga PDF / enlace portal)
|
||
|
||
RELACIÓN CON MÓDULOS EXISTENTES:
|
||
• Paciente → usa lab_pacientes (ya existe)
|
||
• Si viene de un domicilio → exam_ordenes.origen = 'domicilio',
|
||
vincular con lab_domicilios (campo opcional domicilio_id)
|
||
• Si tiene orden médica adjunta → vincular con lab_ordenes_medicas
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
7. BASE DE DATOS — PLAN DE MIGRACIONES
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
REGLA: todas las migraciones son ADITIVAS (ALTER ADD, CREATE TABLE).
|
||
NUNCA DROP COLUMN ni RENAME en producción sin respaldo previo.
|
||
|
||
Migración 001 – RBAC expandido
|
||
ALTER TABLE role_modules ADD COLUMN can_view TINYINT(1) DEFAULT 1;
|
||
ALTER TABLE role_modules ADD COLUMN can_create TINYINT(1) DEFAULT 0;
|
||
ALTER TABLE role_modules ADD COLUMN can_edit TINYINT(1) DEFAULT 0;
|
||
ALTER TABLE role_modules ADD COLUMN can_delete TINYINT(1) DEFAULT 0;
|
||
ALTER TABLE role_modules ADD COLUMN can_export TINYINT(1) DEFAULT 0;
|
||
ALTER TABLE role_modules ADD COLUMN extra_json JSON NULL;
|
||
RENAME TABLE role_modules TO role_permissions; ← (o alias)
|
||
|
||
Migración 002 – Nuevos roles
|
||
INSERT INTO roles (name, slug, description, color, is_system) VALUES
|
||
('Super Admin', 'superadmin', 'Acceso total al sistema', '#dc3545', 1),
|
||
('Recepcionista', 'recepcionista', 'Turnero y recepción de muestras', '#198754', 0),
|
||
('Bacteriólogo', 'bacteriologo', 'Análisis y resultados', '#0dcaf0', 0),
|
||
('Supervisor', 'supervisor', 'Solo reportes y consultas', '#fd7e14', 0),
|
||
('Operador Bot', 'operador_bot', 'Gestión de conversaciones', '#6f42c1', 0);
|
||
|
||
Migración 003 – Turnero [Oleada 1]
|
||
CREATE TABLE exam_tipos (...) ← catálogo maestro compartido con Oleada 2
|
||
CREATE TABLE exam_tipo_consentimientos(...) ← M:N: examen ↔ formulario consentimiento
|
||
CREATE TABLE turnero_lugares (...) ← sub-módulo: estaciones configurables
|
||
CREATE TABLE turnero_prioridades (...) ← catálogo A-F configurable
|
||
CREATE TABLE turnero_sesiones (...) ← sesión diaria de atención
|
||
CREATE TABLE turnero_turnos (...) ← turno con lugar_destino_id
|
||
CREATE TABLE turnero_solicitudes (...) ← solicitud interna de agendamiento
|
||
CREATE TABLE turnero_examen_items (...) ← exámenes de la solicitud
|
||
CREATE TABLE turnero_consentimientos (...) ← firma digital por consentimiento
|
||
ALTER TABLE lab_formularios ADD COLUMN tipo ENUM('formulario','consentimiento') DEFAULT 'formulario'
|
||
|
||
Migración 004 – SYSTEM_MODULES dinámica (mover de config.php a BD) [Oleada 1]
|
||
CREATE TABLE system_modules (
|
||
slug VARCHAR(100) PK,
|
||
name VARCHAR(150),
|
||
icon VARCHAR(50), ← "fas fa-vials"
|
||
category VARCHAR(50), ← "lab", "bot", "sistema", "clinico"
|
||
route VARCHAR(200), ← URL base del módulo
|
||
is_active TINYINT(1),
|
||
sort_order INT,
|
||
created_at TIMESTAMP
|
||
)
|
||
|
||
Poblar con los módulos actuales + turnero.
|
||
registro_exams se agrega en Migración 005 (Oleada 2).
|
||
config.php mantiene el array como fallback hasta que la BD esté lista.
|
||
|
||
Migración 005 – Registro de exámenes [Oleada 2]
|
||
-- exam_tipos ya existe desde Migración 003; solo agregar columnas:
|
||
ALTER TABLE exam_tipos ADD COLUMN precio_base DECIMAL(10,2) NULL;
|
||
ALTER TABLE exam_tipos ADD COLUMN requiere_ayunas TINYINT(1) DEFAULT 0;
|
||
ALTER TABLE exam_tipos ADD COLUMN instrucciones TEXT NULL;
|
||
CREATE TABLE exam_ordenes (...)
|
||
CREATE TABLE exam_items (...)
|
||
CREATE TABLE exam_etiquetas(...)
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
8. ROUTER Y PUNTO DE ENTRADA
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
OPCIÓN RECOMENDADA (sin framework, compatible con estructura actual):
|
||
|
||
index.php → incluye core/App.php
|
||
App.php → lee $_GET['m'] (módulo) y $_GET['v'] (vista)
|
||
→ verifica sesión + permisos via Rbac.php
|
||
→ incluye modules/{m}/views/{v}.php
|
||
→ si no existe → 404 amigable
|
||
|
||
URLS LIMPIAS con .htaccess:
|
||
/turnero/dashboard → ?m=turnero&v=dashboard
|
||
/turnero/display → ?m=turnero&v=display (sin login)
|
||
/lab/domicilios → ?m=domicilios&v=index
|
||
/lab/pacientes → ?m=lab_pacientes&v=index
|
||
|
||
.htaccess ya existe en el proyecto → solo agregar RewriteRules.
|
||
|
||
COMPATIBILIDAD:
|
||
Los lab_*.php en raíz siguen funcionando directamente.
|
||
El router añade una capa adicional, no reemplaza lo existente.
|
||
Migración gradual: mover módulos uno a uno al nuevo sistema.
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
9. LAYOUT Y NAVEGACIÓN UNIFICADA
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
PROBLEMA ACTUAL:
|
||
Cada lab_*.php repite el mismo sidebar a mano (>50 líneas duplicadas).
|
||
Si se agrega un módulo hay que editar todos los archivos.
|
||
|
||
SOLUCIÓN:
|
||
shared/components/sidebar.php → se genera dinámicamente desde:
|
||
1. La tabla system_modules (activos)
|
||
2. Filtrado por los módulos que tiene el rol del usuario logueado
|
||
3. Agrupados por "category" (Bot, Laboratorio, Clínico, Sistema)
|
||
|
||
Cada layout nueva vista incluye:
|
||
<?php include APP_ROOT . '/shared/components/sidebar.php'; ?>
|
||
|
||
El sidebar detecta la URL activa y resalta el elemento correspondiente.
|
||
|
||
GRUPOS DEL MENÚ LATERAL:
|
||
🤖 WhatsApp
|
||
Conversaciones | Bot & Menús | Plantillas | Programados
|
||
🏥 Laboratorio
|
||
Dashboard | Domicilios | Pacientes | Enfermeras | Órdenes
|
||
🧪 Clínico (Oleada 2)
|
||
Registro Exámenes | Resultados
|
||
🎟️ Turnero (Oleada 1)
|
||
Dashboard | Recepción | Toma de Muestras | Kiosko | Configuración
|
||
📊 Reportes
|
||
Ingresos | Rendimiento | Exportar
|
||
⚙️ Sistema
|
||
Usuarios & Roles | Configuración | Actividad
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
10. PLAN DE IMPLEMENTACIÓN — FASES
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
── BASE DEL SISTEMA ─────────────────────────────────────────────────────────
|
||
|
||
FASE 0 – Preparación (1-2 días) [SIN impacto en producción] ✅ COMPLETADA
|
||
✓ Crear carpetas: core/, modules/, shared/
|
||
✓ Extraer Auth.php y Rbac.php desde config.php y _helpers.php
|
||
✓ Crear shared/components/sidebar.php unificado
|
||
✓ Migración 001: expandir role_permissions (columnas can_*)
|
||
✓ Migración 002: insertar nuevos roles
|
||
✓ Agregar nuevos slugs a SYSTEM_MODULES en config.php
|
||
|
||
FASE 1 – Core: Router y estructura modular (1 semana) ✅ COMPLETADA
|
||
✓ Crear core/Router.php y core/App.php
|
||
✓ Crear core/Layout.php, core/Helpers.php (core/Rbac.php ya existía de FASE 0)
|
||
✓ Punto de entrada erp.php (coexiste con index.php legacy)
|
||
✓ Activar .htaccess con URLs limpias (/modulo/vista → erp.php?m=&v=)
|
||
✓ Mover módulos existentes a modules/ (module.php + views/index.php stubs para 11 módulos)
|
||
|
||
FASE 2 – SYSTEM_MODULES dinámica (2 días) ✅ COMPLETADA
|
||
✓ Migración 004: tabla system_modules (con INSERT IGNORE, oleada, sort_order)
|
||
✓ core/ModuleRegistry.php: lee BD → module.php → SYSTEM_MODULES (fallback en cascada)
|
||
✓ Sidebar lee desde ModuleRegistry en lugar de config.php (dinámico por categoría)
|
||
✓ Interfaz /erp.php?m=usuarios&v=modulos (toggle activo + sort_order)
|
||
|
||
── MÓDULOS NUEVOS ────────────────────────────────────────────────────────────
|
||
|
||
FASE 3 – Turnero MVP — Oleada 1
|
||
|
||
FASE 3.1 – Base de datos y configuración (1 día) ✅ COMPLETADA
|
||
──────────────────────────────────────────────────
|
||
✓ Migración 003: crear tablas
|
||
CREATE exam_tipos ← catálogo maestro (compartido con Oleada 2)
|
||
CREATE exam_tipo_consentimientos ← M:N: examen↔formulario
|
||
CREATE turnero_lugares ← estaciones de servicio configurables
|
||
CREATE turnero_prioridades (insertar datos A-F por defecto)
|
||
CREATE turnero_sesiones
|
||
CREATE turnero_turnos ← con lugar_destino_id
|
||
CREATE turnero_solicitudes ← solicitud interna de agendamiento
|
||
CREATE turnero_examen_items ← FK solicitud_id
|
||
CREATE turnero_consentimientos
|
||
ALTER lab_formularios ADD tipo ENUM(formulario, consentimiento)
|
||
✓ modules/turnero/module.php (descriptor)
|
||
✓ Registrar slug 'turnero' en system_modules
|
||
✓ Asignar módulo turnero a roles recepcionista y bacteriologo
|
||
|
||
✅ FASE 3.2 – Motor de cola y API core (1 día) [COMPLETADA]
|
||
──────────────────────────────────────────────
|
||
✓ api/create_turno.php
|
||
• Crea/abre sesión del día si no existe
|
||
• Genera número correlativo + código (ej. "A001") con FOR UPDATE
|
||
• Admite paciente_nombre + paciente_cel (opcional)
|
||
• Retorna código, número y posición en cola
|
||
✓ api/llamar_turno.php
|
||
• Recibe area (recepcion|lugar) + lugar_id
|
||
• Motor de prioridades: SELECT menor orden_peso → menor creado_at
|
||
• Área lugar: solo turnos en estado en_espera_lugar para ese lugar
|
||
• Retorna turno llamado o null si cola vacía
|
||
✓ api/cambiar_estado.php
|
||
• Avanza estado con mapa de transiciones explícito
|
||
• Bloquea en_espera_lugar→en_servicio si hay consentimientos pendientes (422)
|
||
• Registra timestamps llamado_at / inicio_at / fin_at por área
|
||
✓ api/get_cola.php
|
||
• Cola actual por área (recepcion | lugar + lugar_id)
|
||
• Turno activo + listado + estadísticas de sesión
|
||
✓ api/sse_turno.php
|
||
• SSE: emite 'cola_update' cuando cambia sse_ping_at en la sesión
|
||
• ALTER TABLE IF NOT EXISTS para sse_ping_at (idempotente)
|
||
• Keep-alive ": ping" cada 15 s, forzar refresh cada 30 s
|
||
• Compatible con pantalla TV sin necesidad de polling activo
|
||
|
||
✅ FASE 3.3 – Pantallas sin login (1 día) [COMPLETADA]
|
||
────────────────────────────────────────
|
||
✓ views/kiosko.php
|
||
• Pantalla táctil fullscreen 3 pasos: prioridad → datos → ticket
|
||
• Botones A-F cargados de BD (icono + nombre + descripción + color)
|
||
• Campo opcional: nombre y celular con validación de formato
|
||
• Muestra código + posición en cola; auto-reinicio tras 30 s
|
||
• Sin login; fetch POST a create_turno.php
|
||
✓ views/display.php
|
||
• Pantalla TV fullscreen, sin login (HTML puro, sin <?php)
|
||
• ?display=recepcion → cola general
|
||
• ?display=lugar&lugar_id=X → cola del Lugar X
|
||
• SSE EventSource a sse_turno.php con reconexión exponencial
|
||
• Código activo gigante con color de prioridad + lista de espera
|
||
• Web Audio API para beep al llamar — sin archivos externos
|
||
• Stats footer: en espera / atendidos / total / tiempo promedio
|
||
|
||
✅ FASE 3.4 – Puesto de Recepción (1 día) [COMPLETADA]
|
||
────────────────────────────────────────
|
||
✓ views/recepcion.php
|
||
• Requiere login + módulo turnero; layout 2 columnas: cola | ficha
|
||
• Cola izquierda: turnos 'espera' con color de prioridad, polling 8 s
|
||
• Botón "Llamar siguiente" → llama_turno.php area=recepcion
|
||
• Ficha derecha al llamar:
|
||
- Nombre del kiosko pre-cargado en buscador
|
||
- Buscador de paciente: GET /api/lab/get_pacientes.php?busqueda=
|
||
- Selector de lugar destino + checkboxes de exámenes por categoría
|
||
- Campo cobro + forma de pago + observaciones
|
||
- Sección consentimientos (aparece tras guardar si aplican)
|
||
- Botón "Pasar a lugar" → cambiar_estado en_espera_lugar
|
||
- Botón "Ausente"
|
||
✓ api/create_solicitud.php
|
||
• POST, requireTurnero(); validaciones completas
|
||
• DELETE + INSERT (permite re-guardar para correcciones)
|
||
• Inserta turnero_solicitudes + N turnero_examen_items en transacción
|
||
• Devuelve solicitud + consentimientos_requeridos (estado actual de c/u)
|
||
✓ api/send_consentimiento.php
|
||
• Deduplica formularios: N exámenes → M formularios distintos (M ≤ N)
|
||
• Genera UUID por cada formulario; INSERT IGNORE para no duplicar
|
||
• No reenvía consentimientos ya firmados o rechazados
|
||
• Intenta sendTemplateMessage('consentimiento_turno'); fallback texto plano
|
||
• Normaliza celular (+57 por defecto Colombia)
|
||
• Registra enviado_at; retorna lista con enlace_firma por c/u
|
||
• Retorna lista de consentimientos enviados
|
||
|
||
✅ FASE 3.5 – Puesto Lugar / Estación de Servicio (1 día) [COMPLETADA]
|
||
────────────────────────────────────────────────────────
|
||
✓ views/lugar.php (?lugar_id=X)
|
||
• Genérica: funciona para cualquier lugar (Muestras, Rayos X, etc.)
|
||
• Overlay selector si no viene lugar_id en URL; botón "Cambiar lugar"
|
||
• Requiere login (isUserLoggedIn)
|
||
• Cola izquierda: turnos 'en_espera_lugar' del lugar, polling 7 s
|
||
• Botón "Llamar siguiente" → llamar_turno.php area=lugar
|
||
• Ficha derecha al llamar (carga vía get_consentimientos.php?incluir_solicitud=1):
|
||
- Datos del paciente (nombre, doc, fecha nac, celular)
|
||
- Exámenes como pills coloreadas
|
||
- Consentimientos con estado visual (firmado/enviado/visto/pendiente)
|
||
- BLOQUEO: "Iniciar atención" disabled + banner rojo si hay pendientes
|
||
- Botón "Reenviar WhatsApp" → send_consentimiento.php
|
||
- Botón "Firmar aquí" → abre ver_formulario_enviado.php en modal/iframe
|
||
- "Iniciar atención" → cambiar_estado en_servicio (validado en API)
|
||
- "Finalizar" → estado finalizado
|
||
- "Regresar a cola" → estado en_espera_lugar
|
||
- "Ausente" → estado ausente
|
||
• Polling de consentimientos cada 5 s mientras hay turno activo
|
||
✓ api/get_consentimientos.php
|
||
• GET público dentro del módulo (ruta protegida por la vista)
|
||
• ?turno_id=X → retorna arreglo de consentimientos con nombre del formulario
|
||
• ?incluir_solicitud=1 → también retorna solicitud + paciente + exámenes
|
||
|
||
FASE 3.6 – Firma digital (reutilizar formularios) (0.5 días) ✅ COMPLETADA
|
||
──────────────────────────────────────────────────────────────
|
||
✅ Marcar formularios de consentimiento en la interfaz de admin:
|
||
lab_formularios → campo tipo = 'consentimiento'
|
||
✅ Al firmar ver_formulario_enviado.php:
|
||
• Detectar si el token corresponde a un turno (turnero_consentimientos)
|
||
• Actualizar turnero_consentimientos.estado = 'firmado'
|
||
• Registrar ip_firma, ua_firma, firmado_at, version_formulario
|
||
• Guardar firma_svg (base64 PNG) en turnero_consentimientos
|
||
• Notificar SSE → lugar.php/recepcion.php actualizan en tiempo real
|
||
✅ Vista lugar.php tiene botón "Firmar aquí" → abre el mismo
|
||
ver_formulario_enviado.php en un modal (iframe), con canvas de firma
|
||
para firma física en la tablet del puesto
|
||
✅ lugar.php detecta la firma en tiempo real (polling 5s) +
|
||
postMessage instantáneo desde el iframe al firmarse
|
||
|
||
FASE 3.7 – Panel Admin Turnero + configuración (0.5 días) ✅ COMPLETADA
|
||
───────────────────────────────────────────────────────────
|
||
✅ views/configuracion.php — 4 pestañas:
|
||
|
||
TAB 1: Lugares ✅
|
||
• CRUD de turnero_lugares (nombre, descripción, activo, orden)
|
||
• Cada lugar muestra su URL de display → botón copia rápida
|
||
• URLs de recepción y kiosko también accesibles
|
||
• API: save_lugar.php (GET/POST crear/actualizar/eliminar con guardia FK)
|
||
|
||
TAB 2: Exámenes y Consentimientos ✅
|
||
• CRUD de exam_tipos (código, nombre, categoría, activo)
|
||
• Por cada exam_tipo: selector de consentimiento (formularios tipo='consentimiento')
|
||
→ Guarda/actualiza en exam_tipo_consentimientos (deduplicado)
|
||
• Vista inversa: por consentimiento → lista de exámenes vinculados
|
||
• API: save_ex_tipo.php (GET/POST; eliminación bloqueada si hay solicitudes)
|
||
|
||
TAB 3: Prioridades ✅
|
||
• Edición de nombre, color, orden, activo (sin eliminación)
|
||
• Picker de color sincronizado con campo hexadecimal
|
||
• API: save_prioridad.php (validación de formato #RRGGBB)
|
||
|
||
TAB 4: Sesión y WhatsApp ✅
|
||
• Abrir / cerrar / reabrir sesión del día con un clic
|
||
• Historial de sesiones (últimas 30)
|
||
• Configuración de plantilla WhatsApp (nombre + código idioma)
|
||
• API: sesion_turno.php (acciones: abrir, cerrar, reabrir, config_wa)
|
||
|
||
✅ views/dashboard.php (admin)
|
||
• Resumen del día: turnos atendidos, tiempo promedio, pendientes
|
||
• KPI cards + barras por prioridad + tarjetas por lugar
|
||
• Tabla detalle de todos los turnos con búsqueda local
|
||
• Consentimientos del día (desglose por estado)
|
||
• Selector de fecha (consulta histórica)
|
||
• Auto-refresh cada 30s (solo si fecha = hoy)
|
||
• API: get_dashboard.php (consultas agregadas por sesión)
|
||
• Exportar CSV: export_csv.php (BOM UTF-8, 24 columnas, listo para Excel)
|
||
|
||
FASE 4 – Oleada 2 (Registro de Exámenes + futuros)
|
||
|
||
FASE 4.1 – Base de datos (migration 005) ✅ COMPLETADA
|
||
─────────────────────────────────────────────────────
|
||
✓ migrations/005_registro_exams.sql
|
||
ALTER exam_tipos → precio_base, requiere_ayuno, horas_ayuno, instrucciones
|
||
CREATE exam_ordenes (código EX-YYYYMMDD-NNNN, prioridad, estado, FK paciente)
|
||
CREATE exam_items (estado por ítem, notas_tecnico)
|
||
CREATE exam_muestras (trazabilidad: tipo, código_barras, estado)
|
||
CREATE exam_resultados (campo, valor, unidad, referencia, es_anormal)
|
||
UPDATE system_modules SET is_active=1 WHERE slug='registro_exams'
|
||
INSERT role_module_access para bacteriólogo y recepcionista
|
||
✓ run_005_registro_exams.php (runner idempotente)
|
||
|
||
FASE 4.2 – Módulo descriptor y helpers ✅ COMPLETADA
|
||
─────────────────────────────────────────────────────
|
||
✓ modules/registro_exams/module.php
|
||
✓ modules/registro_exams/api/_helpers.php
|
||
requireExams(), generarCodigoOrden(), jsonOk(), jsonError(), db()
|
||
|
||
FASE 4.3 – Lista del día ✅ COMPLETADA
|
||
─────────────────────────────────────────────────────
|
||
✓ modules/registro_exams/views/lista.php
|
||
KPI cards (total/pendientes/en_proceso/completas)
|
||
Filtros: fecha + estado + búsqueda libre
|
||
Auto-refresh 45 s; paginación
|
||
✓ modules/registro_exams/api/get_ordenes.php
|
||
GET ?fecha=&estado=&busqueda=&page=&limit=
|
||
Incluye edad calculada, contadores de ítems y muestras
|
||
|
||
FASE 4.4 – Nueva orden ✅ COMPLETADA
|
||
─────────────────────────────────────────────────────
|
||
✓ modules/registro_exams/views/nueva_orden.php
|
||
Buscador de paciente (reutiliza GET /api/lab/get_pacientes.php)
|
||
Catálogo de exámenes en checkbox agrupados por categoría
|
||
Filtro de búsqueda en catálogo; badge de ayuno y precio
|
||
Pre-carga paciente si viene ?solicitud_id= del turnero
|
||
✓ modules/registro_exams/api/save_orden.php
|
||
POST crear/editar; genera código EX-YYYYMMDD-NNNN
|
||
Sync de ítems: inserta nuevos, elimina pendientes removidos
|
||
Redirige a orden creada al guardar
|
||
|
||
FASE 4.5 – Detalle de orden + resultados ✅ COMPLETADA
|
||
─────────────────────────────────────────────────────
|
||
✓ modules/registro_exams/views/orden.php
|
||
Cards: paciente, datos médicos (prioridad + estado badges)
|
||
Tabla de muestras + modal "Registrar muestra" (tipo + barcode + estado)
|
||
Lista de ítems con estado individual + dropdown cambio de estado
|
||
Modal de resultados: tabla editable (campo/valor/unidad/referencia/anormal)
|
||
Botón "Marcar entregada"; auto-cierre de orden cuando todos listos
|
||
✓ modules/registro_exams/api/get_orden.php
|
||
GET ?id= → orden + ítems + resultados + muestras
|
||
✓ modules/registro_exams/api/save_resultado.php
|
||
POST reemplaza resultados de un ítem; auto-marca resultado_listo
|
||
Auto-cierra orden a 'completa' si todos los ítems tienen resultado
|
||
✓ modules/registro_exams/api/cambiar_estado_item.php
|
||
POST tipo=item|muestra|orden; crea muestras nuevas (tipo=muestra, id=null)
|
||
Al crear muestra: pasa ítems pendientes a muestra_tomada + orden a en_proceso
|
||
|
||
FASE 4.6 – Etiqueta imprimible ✅ COMPLETADA
|
||
─────────────────────────────────────────────────────
|
||
✓ modules/registro_exams/views/etiqueta.php
|
||
Página autónoma A6 landscape (sin sidebar, sin Layout::open)
|
||
Código de barras visual (fuente Libre Barcode 128 via Google Fonts)
|
||
Datos: paciente, doc, edad, EPS, prioridad, lista de exámenes
|
||
Aviso de ayuno si algún ítem lo requiere
|
||
window.print() automático al cargar (delay 800 ms para fuente)
|
||
|
||
□ Facturación, Inventario, CRM, Portal Paciente…
|
||
□ API pública con tokens (para integraciones)
|
||
□ App móvil (portal enfermero actual → Progressive Web App)
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
11. CONVENCIONES TÉCNICAS A SEGUIR
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
NOMENCLATURA:
|
||
• Tablas BD: snake_case, prefijadas por módulo (turnero_, exam_, lab_)
|
||
• Archivos PHP: snake_case (save_turno.php, get_examenes.php)
|
||
• Clases PHP: PascalCase (TurneroService.php, ExamOrder.php)
|
||
• Slugs: siempre lowercase con guiones (turnero, registro-exams)
|
||
• API endpoints: REST-ish, verbos en el nombre (get_, save_, delete_)
|
||
|
||
SEGURIDAD:
|
||
• Toda API: requireMethod() + verificar sesión + verificar permiso
|
||
• Parámetros: siempre sanitizar y tipificar antes de usar en SQL
|
||
• Queries: siempre PDO preparado (ya implementado en Database.php)
|
||
• Pantallas sin login (kiosko, display): NUNCA exponer datos sensibles,
|
||
solo número de turno y servicio.
|
||
• Subida de archivos: misma lógica de /upload.php (validar MIME + ext)
|
||
• CSRF: para formularios de mutación, incluir token en sesión
|
||
|
||
ESTILO DE CÓDIGO:
|
||
• Frontend: Bootstrap 5 + Font Awesome 6 (ya en uso, mantener)
|
||
• Sin jQuery nuevo; usar fetch() nativo (ya en uso)
|
||
• Toasts de notificación: usar patrón ya existente en index.php
|
||
• Responsive: mobile-first (portal enfermero se usa desde celular)
|
||
|
||
API RESPONSE FORMAT (ya establecido, mantener):
|
||
Éxito: { "ok": true, "data": {...}, "message": "..." }
|
||
Error: { "ok": false, "error": "...", "code": 4XX }
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
12. DECISIONES CONFIRMADAS
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
✔ 1. Sede única — No se requiere sede_id en las tablas.
|
||
|
||
✔ 2. Facturación electrónica DIAN — No se maneja en esta fase.
|
||
Queda pendiente para una oleada futura.
|
||
|
||
✔ 3. Portal de resultados para pacientes — No se requiere aún.
|
||
La entrega de resultados es solo gestión interna por ahora.
|
||
|
||
✔ 4. App móvil / PWA — No se usará PWA.
|
||
Solo se aplica diseño responsive a: pantalla TV (display) y kiosko.
|
||
El resto del sistema funciona como web normal desde PC.
|
||
|
||
✔ 5. Multi-tenant — Instalación para un solo cliente.
|
||
Sin aislamiento multi-tenant en la BD.
|
||
|
||
✔ 6. Consentimientos por examen — Se configura UNA VEZ en el panel admin.
|
||
Relación M:N: exam_tipos ↔ lab_formularios (exam_tipo_consentimientos).
|
||
El recepcionista no los marca manualmente; el sistema los calcula
|
||
automáticamente según los exámenes del turno.
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
12B. DECISIONES PENDIENTES DE CONFIRMAR
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
1. ¿Los exámenes integran con algún analizador automático (interfaz LIS)
|
||
o el resultado se digita manual?
|
||
(Impacta diseño de Oleada 2 — registro_exams)
|
||
|
||
2. ¿El turno se puede tomar ANTES de llegar (turno virtual por WhatsApp)?
|
||
(Conectaría el módulo Turnero con el Bot de WhatsApp)
|
||
|
||
3. ¿Cuántas ventanillas de Recepción y cuántas estaciones de servicio
|
||
(Toma de Muestras, Rayos X, etc.) se configurarán inicialmente?
|
||
(Ayuda a diseñar la pantalla TV y el layout de recepción)
|
||
|
||
4. ¿Debe bloquearse TOTALMENTE la atención si hay un consentimiento pendiente,
|
||
o solo mostrar advertencia y dejar que el auxiliar decida continuar?
|
||
|
||
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
13. RESUMEN EJECUTIVO
|
||
────────────────────────────────────────────────────────────────────────────────
|
||
|
||
Lo que TENEMOS es una base sólida:
|
||
✓ BD bien estructurada con 34 tablas
|
||
✓ RBAC funcional (roles + módulos)
|
||
✓ API consistente con helpers reutilizables
|
||
✓ Autenticación robusta con bcrypt
|
||
✓ Integración WhatsApp activa
|
||
✓ Módulos de laboratorio maduros
|
||
|
||
Lo que HAY QUE CONSTRUIR para el ERP:
|
||
→ Estructura de carpetas por módulo (core/ + modules/) ✓ hecho
|
||
→ Router centralizado y sidebar dinámico ✓ hecho
|
||
→ RBAC con granularidad de acciones (can_view/create/edit/delete/export)
|
||
→ Módulo Turnero — Oleada 1 (5-7 días)
|
||
FASE 3.1 – BD y configuración (turnero_lugares + solicitudes + exam_tipos)
|
||
FASE 3.2 – Motor de cola + API core (create_solicitud, llamar, SSE)
|
||
FASE 3.3 – Pantallas sin login (kiosko + display TV por lugar)
|
||
FASE 3.4 – Puesto de Recepción (solicitud + asignar lugar)
|
||
FASE 3.5 – Puesto Lugar/Estación genérico (consentimientos + servicio)
|
||
FASE 3.6 – Firma digital (reutilizar formularios, firmar en tablet)
|
||
FASE 3.7 – Panel Admin + configuración (4 tabs)
|
||
→ SYSTEM_MODULES en BD (en lugar de hardcoded en config.php) ✓ hecho
|
||
→ Módulo Registro de Exámenes — Oleada 2 (5-7 días, pendiente)
|
||
|
||
Estrategia: EVOLUCIÓN INCREMENTAL, no reescritura.
|
||
El sistema sigue funcionando en producción mientras se construyen
|
||
los nuevos módulos en paralelo. Solo se migra lo viejo al nuevo
|
||
sistema cuando el nuevo está validado y estable.
|
||
|
||
================================================================================
|
||
Documento preparado por GitHub Copilot — Abril 2026
|
||
Próxima revisión: tras confirmar decisiones de la sección 12
|
||
================================================================================
|