-- ============================================================= -- Migración 005 — Registro de Exámenes (Oleada 2) -- Crear: exec_ordenes, exam_items, exam_muestras, exam_resultados -- Extender: exam_tipos (precio, ayuno, instrucciones) -- Activar: módulo registro_exams en system_modules -- ============================================================= -- ----------------------------------------------------------- -- 1. Extender exam_tipos con campos clínicos -- ----------------------------------------------------------- ALTER TABLE exam_tipos ADD COLUMN IF NOT EXISTS precio_base DECIMAL(10,2) DEFAULT NULL COMMENT 'Precio de venta al público', ADD COLUMN IF NOT EXISTS requiere_ayuno TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 = requiere ayuno', ADD COLUMN IF NOT EXISTS horas_ayuno TINYINT(3) DEFAULT NULL COMMENT 'Horas mínimas de ayuno', ADD COLUMN IF NOT EXISTS instrucciones TEXT DEFAULT NULL COMMENT 'Instrucciones de preparación para el paciente'; -- ----------------------------------------------------------- -- 2. Órdenes de examen (una orden por visita) -- ----------------------------------------------------------- CREATE TABLE IF NOT EXISTS exam_ordenes ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, paciente_id INT NOT NULL COMMENT 'FK lab_pacientes.id', solicitud_id INT UNSIGNED DEFAULT NULL COMMENT 'FK turnero_solicitudes.id (opcional)', orden_medica_id INT DEFAULT NULL COMMENT 'FK lab_ordenes_medicas.id (opcional)', codigo VARCHAR(20) NOT NULL COMMENT 'Código legible EX-YYYYMMDD-NNNN', medico_nombre VARCHAR(150) DEFAULT NULL, medico_registro VARCHAR(50) DEFAULT NULL, diagnostico TEXT DEFAULT NULL, requiere_ayuno TINYINT(1) NOT NULL DEFAULT 0, horas_ayuno TINYINT(3) DEFAULT NULL, prioridad ENUM('normal','urgente','stat') NOT NULL DEFAULT 'normal', estado ENUM('pendiente','en_proceso','completa','entregada','cancelada') NOT NULL DEFAULT 'pendiente', notas TEXT DEFAULT NULL, creado_por INT DEFAULT NULL COMMENT 'FK admin_users.id', creado_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uq_codigo (codigo), KEY idx_paciente (paciente_id), KEY idx_solicitud (solicitud_id), KEY idx_estado (estado), KEY idx_creado_at (creado_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ----------------------------------------------------------- -- 3. Ítems individuales de la orden (por tipo de examen) -- ----------------------------------------------------------- CREATE TABLE IF NOT EXISTS exam_items ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, orden_id INT UNSIGNED NOT NULL COMMENT 'FK exam_ordenes.id', exam_tipo_id INT UNSIGNED NOT NULL COMMENT 'FK exam_tipos.id', estado ENUM('pendiente','muestra_tomada','en_proceso','resultado_listo','entregado') NOT NULL DEFAULT 'pendiente', notas_tecnico TEXT DEFAULT NULL, creado_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_orden (orden_id), KEY idx_tipo (exam_tipo_id), KEY idx_estado (estado), CONSTRAINT fk_ei_orden FOREIGN KEY (orden_id) REFERENCES exam_ordenes (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ----------------------------------------------------------- -- 4. Trazabilidad de muestras -- ----------------------------------------------------------- CREATE TABLE IF NOT EXISTS exam_muestras ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, orden_id INT UNSIGNED NOT NULL COMMENT 'FK exam_ordenes.id', tipo_muestra ENUM( 'sangre_venosa','sangre_capilar', 'orina_24h','orina_espontanea', 'heces','esputo','hisopado','otro' ) NOT NULL DEFAULT 'sangre_venosa', codigo_barras VARCHAR(50) DEFAULT NULL, tomada_por INT DEFAULT NULL COMMENT 'FK admin_users.id', tomada_at DATETIME DEFAULT NULL, observaciones TEXT DEFAULT NULL, estado ENUM('pendiente','tomada','procesando','procesada','rechazada') NOT NULL DEFAULT 'pendiente', PRIMARY KEY (id), KEY idx_orden (orden_id), KEY idx_barras (codigo_barras), CONSTRAINT fk_em_orden FOREIGN KEY (orden_id) REFERENCES exam_ordenes (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ----------------------------------------------------------- -- 5. Resultados por ítem (valor por campo analítico) -- ----------------------------------------------------------- CREATE TABLE IF NOT EXISTS exam_resultados ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, item_id INT UNSIGNED NOT NULL COMMENT 'FK exam_items.id', campo_nombre VARCHAR(100) NOT NULL COMMENT 'Ej: Hemoglobina, Glucosa', valor_texto TEXT DEFAULT NULL COMMENT 'Resultado en texto libre', valor_numerico DECIMAL(12,4) DEFAULT NULL COMMENT 'Resultado numérico (si aplica)', unidad VARCHAR(50) DEFAULT NULL COMMENT 'g/dL, mg/dL, etc.', referencia_min DECIMAL(12,4) DEFAULT NULL, referencia_max DECIMAL(12,4) DEFAULT NULL, referencia_texto VARCHAR(400) DEFAULT NULL COMMENT 'Rango en texto para imprimir', es_anormal TINYINT(1) NOT NULL DEFAULT 0, ingresado_por INT DEFAULT NULL COMMENT 'FK admin_users.id', ingresado_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_item (item_id), CONSTRAINT fk_er_item FOREIGN KEY (item_id) REFERENCES exam_items (id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- ----------------------------------------------------------- -- 6. Activar el módulo registro_exams -- ----------------------------------------------------------- UPDATE system_modules SET is_active = 1 WHERE slug = 'registro_exams'; -- ----------------------------------------------------------- -- 7. Permisos de roles para el módulo (bacteriólogo + recepcionista) -- Tabla real: role_modules (role_id, module_slug, can_view, can_create, can_edit, can_delete, can_export) -- ----------------------------------------------------------- INSERT IGNORE INTO role_modules (role_id, module_slug, can_view, can_create, can_edit, can_delete, can_export) SELECT r.id, 'registro_exams', 1, 1, 1, 0, 1 FROM roles r WHERE r.slug = 'bacteriologo'; INSERT IGNORE INTO role_modules (role_id, module_slug, can_view, can_create, can_edit, can_delete, can_export) SELECT r.id, 'registro_exams', 1, 1, 0, 0, 0 FROM roles r WHERE r.slug = 'recepcionista';