262 lines
15 KiB
SQL
262 lines
15 KiB
SQL
-- ============================================================
|
||
-- Migración 003 – Módulo Turnero (Oleada 1)
|
||
-- Sistema de Turnero Inteligente con consentimientos informados
|
||
-- FASE 3.1 del plan ERP multi-módulo.
|
||
-- Segura para re-ejecutar (IF NOT EXISTS / INSERT IGNORE).
|
||
-- ============================================================
|
||
|
||
-- ── 1. Catálogo maestro de tipos de examen ──────────────────
|
||
-- Compartido con Oleada 2 (registro_exams).
|
||
-- En Migración 005 se agregan precio_base, requiere_ayunas, instrucciones.
|
||
CREATE TABLE IF NOT EXISTS exam_tipos (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
codigo VARCHAR(20) NOT NULL COMMENT 'Ej: HEM, GLU, URIN',
|
||
nombre VARCHAR(150) NOT NULL COMMENT 'Ej: Hemograma completo',
|
||
categoria VARCHAR(80) DEFAULT NULL COMMENT 'Ej: Hematología, Química',
|
||
activo TINYINT(1) NOT NULL DEFAULT 1,
|
||
creado_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_codigo (codigo),
|
||
INDEX idx_activo (activo),
|
||
INDEX idx_categoria (categoria)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='Catálogo maestro de tipos de examen del laboratorio';
|
||
|
||
-- ── 2. Relación M:N examen ↔ consentimiento (formulario) ────
|
||
-- Si un examen no tiene registro aquí, no se exige consentimiento.
|
||
-- Varios exámenes del mismo turno que apunten al mismo formulario_id
|
||
-- generan UN SOLO consentimiento (deduplicado en la lógica PHP).
|
||
CREATE TABLE IF NOT EXISTS exam_tipo_consentimientos (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
exam_tipo_id INT UNSIGNED NOT NULL,
|
||
formulario_id INT NOT NULL COMMENT 'FK lab_formularios.id (tipo=consentimiento)',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_examen_form (exam_tipo_id, formulario_id),
|
||
INDEX idx_formulario (formulario_id),
|
||
CONSTRAINT fk_etc_exam FOREIGN KEY (exam_tipo_id) REFERENCES exam_tipos (id) ON DELETE CASCADE ON UPDATE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='M:N entre tipos de examen y formularios de consentimiento';
|
||
|
||
-- ── 3. Lugares / estaciones de servicio configurables ───────
|
||
-- Recepción NO es un lugar; es el paso implícito del flujo.
|
||
-- Cada lugar tiene su propia cola y su propia pantalla TV.
|
||
CREATE TABLE IF NOT EXISTS turnero_lugares (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
nombre VARCHAR(100) NOT NULL COMMENT 'Ej: Toma de Muestras 1, Rayos X',
|
||
descripcion TEXT DEFAULT NULL,
|
||
activo TINYINT(1) NOT NULL DEFAULT 1,
|
||
sort_order INT NOT NULL DEFAULT 99 COMMENT 'Orden en pantalla TV general',
|
||
creado_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
INDEX idx_activo (activo),
|
||
INDEX idx_sort (sort_order)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='Estaciones de servicio configurables del turnero';
|
||
|
||
-- Lugares de ejemplo (ajustar según el laboratorio real)
|
||
INSERT IGNORE INTO turnero_lugares (id, nombre, descripcion, activo, sort_order) VALUES
|
||
(1, 'Toma de Muestras 1', 'Primera estación de toma de muestras', 1, 1),
|
||
(2, 'Toma de Muestras 2', 'Segunda estación de toma de muestras', 1, 2),
|
||
(3, 'Rayos X', 'Área de radiología', 1, 3);
|
||
|
||
-- ── 4. Catálogo de prioridades (códigos A-F) ─────────────────
|
||
-- Editable desde el panel admin. orden_peso menor = mayor prioridad.
|
||
CREATE TABLE IF NOT EXISTS turnero_prioridades (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
codigo CHAR(1) NOT NULL COMMENT 'A, B, C, D, E, F',
|
||
nombre VARCHAR(100) NOT NULL,
|
||
orden_peso INT NOT NULL COMMENT 'Menor número = mayor prioridad',
|
||
color VARCHAR(7) NOT NULL DEFAULT '#6b7280' COMMENT 'Hex color para UI',
|
||
activo TINYINT(1) NOT NULL DEFAULT 1,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_codigo (codigo),
|
||
INDEX idx_orden (orden_peso)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='Catálogo configurable de prioridades de atención';
|
||
|
||
-- Prioridades por defecto A-F
|
||
INSERT IGNORE INTO turnero_prioridades (codigo, nombre, orden_peso, color, activo) VALUES
|
||
('A', 'Niños', 1, '#ef4444', 1),
|
||
('B', 'Embarazadas', 2, '#f97316', 1),
|
||
('C', 'Adulto mayor', 3, '#eab308', 1),
|
||
('D', 'Discapacidad', 4, '#8b5cf6', 1),
|
||
('E', 'Paciente general', 5, '#3b82f6', 1),
|
||
('F', 'Muestra pendiente', 6, '#6b7280', 1);
|
||
|
||
-- ── 5. Sesiones diarias de atención ─────────────────────────
|
||
CREATE TABLE IF NOT EXISTS turnero_sesiones (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
fecha DATE NOT NULL,
|
||
abierto_por INT DEFAULT NULL COMMENT 'FK admin_users.id',
|
||
cerrado_por INT DEFAULT NULL COMMENT 'FK admin_users.id',
|
||
inicio_at DATETIME DEFAULT NULL,
|
||
fin_at DATETIME DEFAULT NULL,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_fecha (fecha),
|
||
INDEX idx_fecha (fecha)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='Sesión de atención del día (una por fecha)';
|
||
|
||
-- ── 6. Turnos ────────────────────────────────────────────────
|
||
-- Motor principal del módulo. Un turno = un paciente en una visita.
|
||
CREATE TABLE IF NOT EXISTS turnero_turnos (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
sesion_id INT UNSIGNED NOT NULL,
|
||
numero INT NOT NULL COMMENT 'Correlativo dentro de la sesión',
|
||
codigo VARCHAR(10) NOT NULL COMMENT 'Ej: A001, E042',
|
||
prioridad_id INT UNSIGNED NOT NULL,
|
||
paciente_nombre VARCHAR(150) DEFAULT NULL COMMENT 'Capturado en kiosko (opcional)',
|
||
paciente_cel VARCHAR(20) DEFAULT NULL,
|
||
estado ENUM(
|
||
'espera',
|
||
'en_recepcion',
|
||
'en_espera_lugar',
|
||
'en_servicio',
|
||
'finalizado',
|
||
'ausente',
|
||
'cancelado'
|
||
) NOT NULL DEFAULT 'espera',
|
||
lugar_destino_id INT UNSIGNED DEFAULT NULL COMMENT 'Asignado por recepción',
|
||
-- Timestamps por etapa
|
||
creado_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
llamado_recepcion_at DATETIME DEFAULT NULL,
|
||
inicio_recepcion_at DATETIME DEFAULT NULL,
|
||
fin_recepcion_at DATETIME DEFAULT NULL,
|
||
llamado_lugar_at DATETIME DEFAULT NULL,
|
||
inicio_lugar_at DATETIME DEFAULT NULL,
|
||
fin_lugar_at DATETIME DEFAULT NULL,
|
||
-- Responsable de atención
|
||
atendido_recepcion_por INT DEFAULT NULL COMMENT 'FK admin_users.id',
|
||
atendido_lugar_por INT DEFAULT NULL COMMENT 'FK admin_users.id',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_sesion_numero (sesion_id, numero),
|
||
INDEX idx_sesion_estado (sesion_id, estado),
|
||
INDEX idx_lugar_estado (lugar_destino_id, estado),
|
||
INDEX idx_prioridad (prioridad_id),
|
||
INDEX idx_creado (creado_at),
|
||
CONSTRAINT fk_tt_sesion FOREIGN KEY (sesion_id) REFERENCES turnero_sesiones (id) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||
CONSTRAINT fk_tt_prioridad FOREIGN KEY (prioridad_id) REFERENCES turnero_prioridades (id) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||
CONSTRAINT fk_tt_lugar FOREIGN KEY (lugar_destino_id) REFERENCES turnero_lugares (id) ON DELETE SET NULL ON UPDATE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='Turnos del sistema de atención';
|
||
|
||
-- ── 7. Solicitud interna (crea recepción) ────────────────────
|
||
-- Registra paciente, exámenes, pago y lugar destino.
|
||
-- Una solicitud por turno (UNIQUE turno_id).
|
||
CREATE TABLE IF NOT EXISTS turnero_solicitudes (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
turno_id INT UNSIGNED NOT NULL,
|
||
paciente_id INT NOT NULL COMMENT 'FK lab_pacientes.id',
|
||
lugar_id INT UNSIGNED NOT NULL COMMENT 'FK turnero_lugares.id',
|
||
total_cobrado DECIMAL(10,2) DEFAULT NULL,
|
||
metodo_pago ENUM(
|
||
'efectivo',
|
||
'transferencia',
|
||
'tarjeta',
|
||
'eps',
|
||
'cortesia'
|
||
) DEFAULT NULL,
|
||
observaciones TEXT DEFAULT NULL,
|
||
creado_por INT NOT NULL COMMENT 'FK admin_users.id',
|
||
creado_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_turno (turno_id),
|
||
INDEX idx_paciente (paciente_id),
|
||
INDEX idx_lugar (lugar_id),
|
||
INDEX idx_creado (creado_at),
|
||
CONSTRAINT fk_ts_turno FOREIGN KEY (turno_id) REFERENCES turnero_turnos (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||
CONSTRAINT fk_ts_lugar FOREIGN KEY (lugar_id) REFERENCES turnero_lugares (id) ON DELETE RESTRICT ON UPDATE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='Solicitud interna de agendamiento creada en recepción';
|
||
|
||
-- ── 8. Exámenes de la solicitud ──────────────────────────────
|
||
CREATE TABLE IF NOT EXISTS turnero_examen_items (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
solicitud_id INT UNSIGNED NOT NULL,
|
||
exam_tipo_id INT UNSIGNED NOT NULL,
|
||
creado_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
INDEX idx_solicitud (solicitud_id),
|
||
INDEX idx_exam_tipo (exam_tipo_id),
|
||
CONSTRAINT fk_tei_solicitud FOREIGN KEY (solicitud_id) REFERENCES turnero_solicitudes (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||
CONSTRAINT fk_tei_exam FOREIGN KEY (exam_tipo_id) REFERENCES exam_tipos (id) ON DELETE RESTRICT ON UPDATE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='Exámenes individuales de cada solicitud de turno';
|
||
|
||
-- ── 9. Consentimientos por turno (deduplicados) ──────────────
|
||
-- Un registro por formulario distinto requerido en el turno.
|
||
-- token = enlace único de firma (UUID).
|
||
CREATE TABLE IF NOT EXISTS turnero_consentimientos (
|
||
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
turno_id INT UNSIGNED NOT NULL,
|
||
formulario_id INT NOT NULL COMMENT 'FK lab_formularios.id',
|
||
token VARCHAR(64) NOT NULL COMMENT 'UUID único para enlace de firma',
|
||
estado ENUM(
|
||
'pendiente',
|
||
'enviado',
|
||
'visto',
|
||
'firmado',
|
||
'rechazado'
|
||
) NOT NULL DEFAULT 'pendiente',
|
||
enviado_at DATETIME DEFAULT NULL,
|
||
firmado_at DATETIME DEFAULT NULL,
|
||
ip_firma VARCHAR(45) DEFAULT NULL COMMENT 'IPv4 o IPv6 del firmante',
|
||
ua_firma VARCHAR(500) DEFAULT NULL COMMENT 'User-Agent del dispositivo',
|
||
version_formulario INT DEFAULT NULL COMMENT 'Snapshot de versión al firmar',
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uq_token (token),
|
||
UNIQUE KEY uq_turno_form (turno_id, formulario_id),
|
||
INDEX idx_turno (turno_id),
|
||
INDEX idx_estado (estado),
|
||
CONSTRAINT fk_tc_turno FOREIGN KEY (turno_id) REFERENCES turnero_turnos (id) ON DELETE CASCADE ON UPDATE CASCADE
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||
COMMENT='Consentimientos informados vinculados a un turno (uno por formulario distinto)';
|
||
|
||
-- ── 10. Columna tipo en lab_formularios ──────────────────────
|
||
-- Permite marcar un formulario como consentimiento informado.
|
||
ALTER TABLE lab_formularios
|
||
ADD COLUMN IF NOT EXISTS tipo
|
||
ENUM('formulario', 'consentimiento') NOT NULL DEFAULT 'formulario'
|
||
COMMENT 'Tipo de formulario: genérico o consentimiento informado';
|
||
|
||
-- Índice para filtrar rápido en las consultas del turnero
|
||
ALTER TABLE lab_formularios
|
||
ADD INDEX IF NOT EXISTS idx_tipo (tipo);
|
||
|
||
-- ── 11. Asignar módulo turnero a roles ───────────────────────
|
||
-- Activar en system_modules si estaba inactivo
|
||
UPDATE system_modules
|
||
SET is_active = 1
|
||
WHERE slug = 'turnero';
|
||
|
||
-- Permisos del recepcionista sobre el módulo turnero
|
||
INSERT IGNORE INTO role_modules (role_id, module_slug, can_view, can_create, can_edit, can_delete, can_export)
|
||
SELECT r.id, 'turnero', 1, 1, 1, 0, 0
|
||
FROM roles r WHERE r.slug = 'recepcionista';
|
||
|
||
-- Permisos del bacteriólogo sobre el módulo turnero (solo lectura + edición de servicio)
|
||
INSERT IGNORE INTO role_modules (role_id, module_slug, can_view, can_create, can_edit, can_delete, can_export)
|
||
SELECT r.id, 'turnero', 1, 0, 1, 0, 0
|
||
FROM roles r WHERE r.slug = 'bacteriologo';
|
||
|
||
-- ── 12. Datos de ejemplo de tipos de examen ──────────────────
|
||
-- Solo si la tabla está vacía (evita duplicar en re-ejecución)
|
||
INSERT IGNORE INTO exam_tipos (codigo, nombre, categoria) VALUES
|
||
('HEM', 'Hemograma completo', 'Hematología'),
|
||
('GLU', 'Glucosa en ayunas', 'Química'),
|
||
('URIN', 'Uroanálisis completo', 'Urología'),
|
||
('UROCUL','Urocultivo', 'Microbiología'),
|
||
('COLEST','Perfil lipídico (colesterol)', 'Química'),
|
||
('TSH', 'TSH (Función tiroidea)', 'Endocrinología'),
|
||
('HIV', 'Prueba VIH', 'Serología'),
|
||
('HEPB', 'Hepatitis B (HBsAg)', 'Serología'),
|
||
('RXP', 'Rayos X de pecho', 'Radiología'),
|
||
('ECG', 'Electrocardiograma', 'Cardiología');
|
||
|
||
-- ── 13. Columna firma_svg en turnero_consentimientos ─────────
|
||
-- Almacena el dibujo de firma del paciente (data URL PNG).
|
||
-- MEDIUMTEXT soporta firmas de alta resolución (hasta 16 MB).
|
||
ALTER TABLE turnero_consentimientos
|
||
ADD COLUMN IF NOT EXISTS firma_svg MEDIUMTEXT DEFAULT NULL
|
||
COMMENT 'Dibujo de firma del paciente (data URL PNG base64)';
|