This commit is contained in:
Lizandro Guarnizo
2026-04-18 23:41:01 -05:00
parent 876e935a66
commit 318a1742cc
37 changed files with 8838 additions and 89 deletions
+575 -81
View File
@@ -101,14 +101,21 @@ MÓDULOS PLANIFICADOS (oleadas):
│ ├── turnero/ ← NUEVO ★ (Oleada 1)
│ │ ├── module.php
│ │ ├── views/
│ │ │ ├── dashboard.php ← Pantalla administrador
│ │ │ ├── display.php ← Pantalla TV/recepción (sin login)
│ │ │ ── kiosko.php ← Pantalla táctil toma de turno
│ │ │ ├── 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
│ │ ├── llamar_turno.php
│ │ ├── get_estado.php
│ │ ── sse_turno.php ← Server-Sent Events para la pantalla TV
│ │ ├── 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
@@ -215,54 +222,285 @@ HELPER PROPUESTO (core/Rbac.php):
5. MÓDULO TURNERO — DISEÑO DETALLADO
────────────────────────────────────────────────────────────────────────────────
CONCEPTO:
Sistema de turnos para pacientes que llegan presencialmente a la sede.
Tres pantallas distintas:
A) Kiosko (tablet/touch en recepción) → el paciente toma su turno
B) TV/Display (pantalla grande) → muestra turno actual + cola
C) Dashboard admin → el operador llama turnos, gestiona
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.
TABLAS BD NUEVAS:
El sistema optimiza la atención, mejora la trazabilidad del paciente
y garantiza el cumplimiento legal mediante la gestión digital de
consentimientos.
turnero_servicios
id, nombre, prefijo (ej. "A"), color, tiempo_estimado_min, activo
──── 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, abierto_por INT FK admin_users, cerrado_por, inicio_at, fin_at
(una sesión = un día de atención)
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,
numero INT, ← número correlativo de la sesión
codigo VARCHAR(10), ← "A001", "B012"
servicio_id,
paciente_nombre VARCHAR(150),
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, llamado, en_atencion, atendido, ausente, cancelado),
modulo_atencion INT, ← puesto/ventanilla que atiende
llamado_at, inicio_at, fin_at, creado_at
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_modulos
id, nombre (ej. "Ventanilla 1"), activo, usuario_actual INT FK admin_users
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
FLUJO:
1. Recepcionista / kiosko crea turno → estado "espera"
2. Operador en dashboard hace clic "Llamar siguiente"
→ estado "llamado", pantalla TV muestra "A-001 → Ventanilla 2"
→ (opcional) SMS/WhatsApp al paciente con su turno
3. El paciente llega → operador pasa a "en_atención"
4. Al terminar → "atendido"
5. Si no aparece → "ausente" (puede regresar al final de la cola)
turnero_examen_items ← exámenes de la solicitud
id, solicitud_id FK turnero_solicitudes,
exam_tipo_id INT FK exam_tipos,
creado_at DATETIME
PANTALLA TV (display.php):
• Sin login
• Se actualiza por SSE (Server-Sent Events) cada vez que se llama un turno
• Muestra: turno actual por cada ventanilla + próximos 5 en espera
• Diseño visual grande, colores por servicio
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
INTEGRACIÓN CON WHATSAPP (OPCIONAL):
Cuando se llama el turno → enviar mensaje al paciente si dejó celular
Usar WhatsAppService ya existente.
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
────────────────────────────────────────────────────────────────────────────────
@@ -350,10 +588,16 @@ Migración 002 Nuevos roles
('Operador Bot', 'operador_bot', 'Gestión de conversaciones', '#6f42c1', 0);
Migración 003 Turnero [Oleada 1]
CREATE TABLE turnero_servicios (...)
CREATE TABLE turnero_sesiones (...)
CREATE TABLE turnero_turnos (...)
CREATE TABLE turnero_modulos (...)
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 (
@@ -372,7 +616,10 @@ Migración 004 SYSTEM_MODULES dinámica (mover de config.php a BD) [Oleada
config.php mantiene el array como fallback hasta que la BD esté lista.
Migración 005 Registro de exámenes [Oleada 2]
CREATE TABLE exam_tipos (...)
-- 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(...)
@@ -431,7 +678,7 @@ GRUPOS DEL MENÚ LATERAL:
🧪 Clínico (Oleada 2)
Registro Exámenes | Resultados
🎟️ Turnero (Oleada 1)
Dashboard | Configurar Servicios
Dashboard | Recepción | Toma de Muestras | Kiosko | Configuración
📊 Reportes
Ingresos | Rendimiento | Exportar
⚙️ Sistema
@@ -467,21 +714,242 @@ FASE 2 SYSTEM_MODULES dinámica (2 días) ✅ COMPLETADA
── MÓDULOS NUEVOS ────────────────────────────────────────────────────────────
FASE 3 Turnero MVP — Oleada 1 (3-5 días)
□ Migración 003: tablas turnero_*
□ modules/turnero/module.php + views/ + api/
□ Pantalla kiosko (toma turno, sin login)
□ Pantalla display TV (SSE, sin login)
□ Dashboard admin (llamar, gestionar)
□ Registrar slug turnero en system_modules
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)
□ Migración 005: tablas exam_*
□ Catálogo de tipos de examen (CRUD admin)
□ Flujo de recepción: buscar paciente → crear orden → agregar ítems
□ Vista bacteriólogo: lista del día, cambiar estados
□ Impresión de etiquetas (PDF A6)
□ Conectar con lab_pacientes (reutilizar buscador existente)
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)
@@ -519,28 +987,47 @@ API RESPONSE FORMAT (ya establecido, mantener):
────────────────────────────────────────────────────────────────────────────────
12. DECISIONES CLAVE A CONFIRMAR CON EL CLIENTE
12. DECISIONES CONFIRMADAS
────────────────────────────────────────────────────────────────────────────────
1. ¿El turnero es para UNA sede o múltiples sedes?
(Multi-sede requiere añadir sede_id a las tablas)
1. Sede única — No se requiere sede_id en las tablas.
2. ¿Facturación electrónica (DIAN) es obligatorio desde el inicio
o puede dejarse para Oleada 2?
2. Facturación electrónica DIAN — No se maneja en esta fase.
Queda pendiente para una oleada futura.
3. ¿El portal de entrega de resultados es para los pacientes directamente
(requiere login/token para pacientes) o solo descarga interna?
3. Portal de resultados para pacientes — No se requiere aún.
La entrega de resultados es solo gestión interna por ahora.
4. ¿Se quiere app móvil nativa o es suficiente con PWA/responsive?
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. ¿Los exámenes tienen que integrar con algún analizador automático
(interfaz LIS) o el resultado se digita manual?
5. Multi-tenant — Instalación para un solo cliente.
Sin aislamiento multi-tenant en la BD.
6. ¿El turno se puede tomar ANTES de llegar (turno virtual por WhatsApp)?
Esto conecta el módulo Turnero con el Bot.
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.
7. ¿El sistema será multi-tenant (varios laboratorios/clientes en el mismo
servidor) o siempre una instalación por cliente?
────────────────────────────────────────────────────────────────────────────────
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?
────────────────────────────────────────────────────────────────────────────────
@@ -556,11 +1043,18 @@ API RESPONSE FORMAT (ya establecido, mantener):
✓ Módulos de laboratorio maduros
Lo que HAY QUE CONSTRUIR para el ERP:
→ Estructura de carpetas por módulo (core/ + modules/)
→ Router centralizado y sidebar dinámico
→ 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 (3-5 días)
→ SYSTEM_MODULES en BD (en lugar de hardcoded en config.php)
→ 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.