up
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_01_pacientes
|
||||
-- Módulo Administrativo: Pacientes del laboratorio
|
||||
-- Extiende la tabla users (contactos WhatsApp existentes)
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lab_pacientes` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` INT(11) DEFAULT NULL COMMENT 'FK a users.id (teléfono WhatsApp)',
|
||||
`numero_documento` VARCHAR(30) DEFAULT NULL COMMENT 'Cédula / NIT / Pasaporte',
|
||||
`tipo_documento` ENUM('CC','CE','TI','PA','NIT','RC','MS') DEFAULT 'CC',
|
||||
`nombre_completo` VARCHAR(150) NOT NULL,
|
||||
`telefono` VARCHAR(20) DEFAULT NULL,
|
||||
`email` VARCHAR(100) DEFAULT NULL,
|
||||
`fecha_nacimiento` DATE DEFAULT NULL,
|
||||
`genero` ENUM('M','F','O') DEFAULT NULL,
|
||||
`direccion` TEXT DEFAULT NULL,
|
||||
`ciudad` VARCHAR(100) DEFAULT NULL,
|
||||
`barrio` VARCHAR(100) DEFAULT NULL,
|
||||
`eps` VARCHAR(100) DEFAULT NULL COMMENT 'Entidad promotora de salud',
|
||||
`notas_admin` TEXT DEFAULT NULL COMMENT 'Notas internas del administrador',
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_numero_documento` (`numero_documento`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_nombre` (`nombre_completo`),
|
||||
KEY `idx_telefono` (`telefono`),
|
||||
KEY `idx_documento` (`numero_documento`),
|
||||
CONSTRAINT `fk_lab_pac_user` FOREIGN KEY (`user_id`)
|
||||
REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Pacientes del laboratorio (módulo administrativo)';
|
||||
@@ -0,0 +1,24 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_02_enfermeras
|
||||
-- Módulo Administrativo: Personal de enfermería
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lab_enfermeras` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`numero_documento` VARCHAR(30) NOT NULL,
|
||||
`tipo_documento` ENUM('CC','CE','TI','PA') DEFAULT 'CC',
|
||||
`nombre_completo` VARCHAR(150) NOT NULL,
|
||||
`telefono` VARCHAR(20) NOT NULL,
|
||||
`telefono_alt` VARCHAR(20) DEFAULT NULL,
|
||||
`email` VARCHAR(100) DEFAULT NULL,
|
||||
`zona` VARCHAR(100) DEFAULT NULL COMMENT 'Zona/barrio asignada habitualmente',
|
||||
`notas` TEXT DEFAULT NULL,
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uq_enf_documento` (`numero_documento`),
|
||||
KEY `idx_enf_nombre` (`nombre_completo`),
|
||||
KEY `idx_enf_activa` (`is_active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Personal de enfermería para domicilios';
|
||||
@@ -0,0 +1,56 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_03_ordenes_medicas
|
||||
-- Módulo Administrativo: Órdenes médicas recibidas por WhatsApp
|
||||
-- Vincula una imagen del chat con un paciente y un estado
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lab_ordenes_medicas` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`paciente_id` INT(11) NOT NULL COMMENT 'FK a lab_pacientes.id',
|
||||
`conversation_id` INT(11) DEFAULT NULL COMMENT 'FK a conversations.id (mensaje con la imagen)',
|
||||
`whatsapp_media_id` VARCHAR(255) DEFAULT NULL COMMENT 'Media ID de WhatsApp para referencia',
|
||||
`local_file` VARCHAR(255) DEFAULT NULL COMMENT 'Ruta local de la imagen de la orden',
|
||||
-- Estado del flujo de revisión
|
||||
`estado` ENUM(
|
||||
'pendiente',
|
||||
'en_revision',
|
||||
'autorizada',
|
||||
'rechazada',
|
||||
'en_domicilio',
|
||||
'completada'
|
||||
) NOT NULL DEFAULT 'pendiente',
|
||||
-- Datos de la orden médica (ingresados manualmente)
|
||||
`medico_nombre` VARCHAR(150) DEFAULT NULL,
|
||||
`medico_registro` VARCHAR(50) DEFAULT NULL,
|
||||
`fecha_orden` DATE DEFAULT NULL COMMENT 'Fecha que aparece en la orden impresa',
|
||||
`diagnostico` TEXT DEFAULT NULL,
|
||||
`examenes_solicitados` TEXT DEFAULT NULL COMMENT 'Lista de exámenes de la orden',
|
||||
`requiere_ayuno` TINYINT(1) DEFAULT 0,
|
||||
`horas_ayuno` TINYINT(3) DEFAULT NULL,
|
||||
`indicaciones` TEXT DEFAULT NULL,
|
||||
-- Gestión administrativa
|
||||
`revisada_por` INT(11) DEFAULT NULL COMMENT 'FK a admin_users.id',
|
||||
`revisada_at` DATETIME DEFAULT NULL,
|
||||
`autorizada_por` INT(11) DEFAULT NULL COMMENT 'FK a admin_users.id',
|
||||
`autorizada_at` DATETIME DEFAULT NULL,
|
||||
`comentario_revision` TEXT DEFAULT NULL,
|
||||
`notas_admin` TEXT DEFAULT NULL,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_ord_paciente` (`paciente_id`),
|
||||
KEY `idx_ord_conversation` (`conversation_id`),
|
||||
KEY `idx_ord_estado` (`estado`),
|
||||
KEY `idx_ord_fecha` (`fecha_orden`),
|
||||
KEY `idx_ord_revisada_por` (`revisada_por`),
|
||||
KEY `idx_ord_autorizada` (`autorizada_por`),
|
||||
CONSTRAINT `fk_ord_paciente` FOREIGN KEY (`paciente_id`)
|
||||
REFERENCES `lab_pacientes` (`id`) ON DELETE RESTRICT,
|
||||
CONSTRAINT `fk_ord_conversation` FOREIGN KEY (`conversation_id`)
|
||||
REFERENCES `conversations` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_ord_revisada` FOREIGN KEY (`revisada_por`)
|
||||
REFERENCES `admin_users` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_ord_autorizada` FOREIGN KEY (`autorizada_por`)
|
||||
REFERENCES `admin_users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Órdenes médicas recibidas vía WhatsApp';
|
||||
@@ -0,0 +1,53 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_04_domicilios
|
||||
-- Módulo Administrativo: Servicios a domicilio
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lab_domicilios` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`orden_id` INT(11) DEFAULT NULL COMMENT 'FK a lab_ordenes_medicas.id',
|
||||
`paciente_id` INT(11) NOT NULL COMMENT 'FK a lab_pacientes.id',
|
||||
-- Datos del domicilio
|
||||
`direccion` TEXT NOT NULL,
|
||||
`ciudad` VARCHAR(100) DEFAULT NULL,
|
||||
`barrio` VARCHAR(100) DEFAULT NULL,
|
||||
`indicaciones_dir` TEXT DEFAULT NULL COMMENT 'Referencia de la dirección',
|
||||
`fecha_programada` DATE NOT NULL,
|
||||
`hora_programada` TIME DEFAULT NULL,
|
||||
`tipo_servicio` VARCHAR(100) DEFAULT NULL COMMENT 'Tipo de toma de muestra',
|
||||
-- Estado del domicilio
|
||||
`estado` ENUM(
|
||||
'programado',
|
||||
'confirmado',
|
||||
'en_camino',
|
||||
'en_domicilio',
|
||||
'completado',
|
||||
'cancelado',
|
||||
'reprogramado'
|
||||
) NOT NULL DEFAULT 'programado',
|
||||
`motivo_cancelacion` TEXT DEFAULT NULL,
|
||||
`fecha_reprogramada` DATE DEFAULT NULL,
|
||||
-- Resultados
|
||||
`hora_llegada` TIME DEFAULT NULL,
|
||||
`hora_salida` TIME DEFAULT NULL,
|
||||
`observaciones` TEXT DEFAULT NULL,
|
||||
`muestras_tomadas` TEXT DEFAULT NULL COMMENT 'Lista de muestras obtenidas',
|
||||
-- Gestión
|
||||
`creado_por` INT(11) DEFAULT NULL COMMENT 'FK a admin_users.id',
|
||||
`notas_admin` TEXT DEFAULT NULL,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_dom_orden` (`orden_id`),
|
||||
KEY `idx_dom_paciente` (`paciente_id`),
|
||||
KEY `idx_dom_fecha` (`fecha_programada`),
|
||||
KEY `idx_dom_estado` (`estado`),
|
||||
KEY `idx_dom_creado` (`creado_por`),
|
||||
CONSTRAINT `fk_dom_orden` FOREIGN KEY (`orden_id`)
|
||||
REFERENCES `lab_ordenes_medicas` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_dom_paciente` FOREIGN KEY (`paciente_id`)
|
||||
REFERENCES `lab_pacientes` (`id`) ON DELETE RESTRICT,
|
||||
CONSTRAINT `fk_dom_creado` FOREIGN KEY (`creado_por`)
|
||||
REFERENCES `admin_users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Servicios a domicilio programados';
|
||||
@@ -0,0 +1,33 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_05_asignaciones
|
||||
-- Módulo Administrativo: Asignación de enfermera a domicilio
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lab_asignaciones` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`domicilio_id` INT(11) NOT NULL COMMENT 'FK a lab_domicilios.id',
|
||||
`enfermera_id` INT(11) NOT NULL COMMENT 'FK a lab_enfermeras.id',
|
||||
`asignada_por` INT(11) DEFAULT NULL COMMENT 'FK a admin_users.id',
|
||||
`estado` ENUM(
|
||||
'asignada',
|
||||
'confirmada',
|
||||
'liberada',
|
||||
'completada'
|
||||
) NOT NULL DEFAULT 'asignada',
|
||||
`notas` TEXT DEFAULT NULL,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
-- Solo una enfermera activa por domicilio
|
||||
UNIQUE KEY `uq_asig_domicilio` (`domicilio_id`),
|
||||
KEY `idx_asig_enfermera` (`enfermera_id`),
|
||||
KEY `idx_asig_estado` (`estado`),
|
||||
KEY `idx_asig_asignada` (`asignada_por`),
|
||||
CONSTRAINT `fk_asig_domicilio` FOREIGN KEY (`domicilio_id`)
|
||||
REFERENCES `lab_domicilios` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_asig_enfermera` FOREIGN KEY (`enfermera_id`)
|
||||
REFERENCES `lab_enfermeras` (`id`) ON DELETE RESTRICT,
|
||||
CONSTRAINT `fk_asig_admin` FOREIGN KEY (`asignada_por`)
|
||||
REFERENCES `admin_users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Asignación de enfermeras a domicilios';
|
||||
@@ -0,0 +1,34 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_06_autorizaciones
|
||||
-- Módulo Administrativo: Log de cambios de estado de órdenes
|
||||
-- Cada cambio de estado genera un registro aquí (trazabilidad)
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lab_autorizaciones` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`orden_id` INT(11) NOT NULL COMMENT 'FK a lab_ordenes_medicas.id',
|
||||
`accion` ENUM(
|
||||
'creada',
|
||||
'en_revision',
|
||||
'autorizada',
|
||||
'rechazada',
|
||||
'en_domicilio',
|
||||
'completada',
|
||||
'editada'
|
||||
) NOT NULL,
|
||||
`estado_anterior` VARCHAR(50) DEFAULT NULL,
|
||||
`estado_nuevo` VARCHAR(50) DEFAULT NULL,
|
||||
`realizada_por` INT(11) DEFAULT NULL COMMENT 'FK a admin_users.id',
|
||||
`comentario` TEXT DEFAULT NULL,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_aut_orden` (`orden_id`),
|
||||
KEY `idx_aut_admin` (`realizada_por`),
|
||||
KEY `idx_aut_accion` (`accion`),
|
||||
KEY `idx_aut_fecha` (`created_at`),
|
||||
CONSTRAINT `fk_aut_orden` FOREIGN KEY (`orden_id`)
|
||||
REFERENCES `lab_ordenes_medicas` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_aut_admin` FOREIGN KEY (`realizada_por`)
|
||||
REFERENCES `admin_users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Historial de cambios de estado de órdenes médicas';
|
||||
@@ -0,0 +1,27 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_07_actividad_admin
|
||||
-- Módulo Administrativo: Trazabilidad general del módulo
|
||||
-- Registra TODA acción realizada por administradoras
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lab_actividad_admin` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`admin_id` INT(11) DEFAULT NULL COMMENT 'FK a admin_users.id',
|
||||
`admin_nombre` VARCHAR(150) DEFAULT NULL COMMENT 'Snapshot del nombre (por si se elimina)',
|
||||
`modulo` VARCHAR(50) NOT NULL COMMENT 'pacientes|ordenes|domicilios|enfermeras|asignaciones',
|
||||
`accion` VARCHAR(100) NOT NULL COMMENT 'crear|editar|eliminar|autorizar|rechazar|asignar...',
|
||||
`entidad_id` INT(11) DEFAULT NULL COMMENT 'ID del registro afectado',
|
||||
`detalle` TEXT DEFAULT NULL COMMENT 'JSON o descripción del cambio',
|
||||
`ip_address` VARCHAR(45) DEFAULT NULL,
|
||||
`user_agent` VARCHAR(255) DEFAULT NULL,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_act_admin` (`admin_id`),
|
||||
KEY `idx_act_modulo` (`modulo`),
|
||||
KEY `idx_act_accion` (`accion`),
|
||||
KEY `idx_act_entidad` (`entidad_id`),
|
||||
KEY `idx_act_fecha` (`created_at`),
|
||||
CONSTRAINT `fk_act_admin` FOREIGN KEY (`admin_id`)
|
||||
REFERENCES `admin_users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Log de trazabilidad del módulo administrativo';
|
||||
@@ -0,0 +1,47 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_08_roles_enfermeros
|
||||
-- Módulo Laboratorio: Rol enfermero + servicios extra
|
||||
-- ============================================================
|
||||
|
||||
-- 1. Agregar columnas role y enfermera_id a admin_users
|
||||
ALTER TABLE `admin_users`
|
||||
ADD COLUMN IF NOT EXISTS `role` ENUM('admin','enfermero') NOT NULL DEFAULT 'admin'
|
||||
COMMENT 'Rol del usuario: admin = acceso total, enfermero = solo portal propio',
|
||||
ADD COLUMN IF NOT EXISTS `enfermera_id` INT(11) NULL DEFAULT NULL
|
||||
COMMENT 'Vincula el usuario con su registro en lab_enfermeras';
|
||||
|
||||
-- Índice para lookups rápidos por rol
|
||||
ALTER TABLE `admin_users`
|
||||
ADD INDEX IF NOT EXISTS `idx_role` (`role`),
|
||||
ADD INDEX IF NOT EXISTS `idx_enf_id` (`enfermera_id`);
|
||||
|
||||
-- 2. Tabla de servicios extra (sin orden médica)
|
||||
-- El enfermero puede agregar servicios adicionales durante la visita
|
||||
CREATE TABLE IF NOT EXISTS `lab_servicios_extra` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`domicilio_id` INT(11) NOT NULL,
|
||||
`descripcion` VARCHAR(255) NOT NULL COMMENT 'Ej: Inyección, Cura, Nebulización',
|
||||
`tipo` ENUM(
|
||||
'inyeccion',
|
||||
'cura',
|
||||
'nebulizacion',
|
||||
'toma_muestra',
|
||||
'tension_arterial',
|
||||
'glucometria',
|
||||
'otro'
|
||||
) NOT NULL DEFAULT 'otro',
|
||||
`notas` TEXT DEFAULT NULL,
|
||||
`requiere_pago` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`valor` DECIMAL(10,2) DEFAULT NULL,
|
||||
`realizado_por` INT(11) DEFAULT NULL COMMENT 'ID de lab_enfermeras',
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_se_domicilio` (`domicilio_id`),
|
||||
KEY `idx_se_enfermera` (`realizado_por`),
|
||||
CONSTRAINT `fk_se_domicilio` FOREIGN KEY (`domicilio_id`)
|
||||
REFERENCES `lab_domicilios` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_se_enfermera` FOREIGN KEY (`realizado_por`)
|
||||
REFERENCES `lab_enfermeras` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Servicios adicionales agregados por enfermeros durante visitas';
|
||||
@@ -0,0 +1,63 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260302_lab_09_formularios
|
||||
-- Módulo Formularios: creador drag&drop, envío a clientes, firma
|
||||
-- ============================================================
|
||||
|
||||
-- 1. Plantillas de formularios (diseñadas por admins)
|
||||
CREATE TABLE IF NOT EXISTS `lab_formularios` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`nombre` VARCHAR(150) NOT NULL,
|
||||
`descripcion` TEXT DEFAULT NULL,
|
||||
`categoria` ENUM(
|
||||
'consentimiento',
|
||||
'historia_clinica',
|
||||
'autorizacion',
|
||||
'encuesta',
|
||||
'otro'
|
||||
) NOT NULL DEFAULT 'otro',
|
||||
`esquema` LONGTEXT NOT NULL COMMENT 'JSON con el array de campos del formulario',
|
||||
`permite_firma` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`requiere_firma` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`version` SMALLINT NOT NULL DEFAULT 1,
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||||
`creado_por` INT(11) DEFAULT NULL,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_form_activo` (`is_active`),
|
||||
KEY `idx_form_categ` (`categoria`),
|
||||
CONSTRAINT `fk_form_admin` FOREIGN KEY (`creado_por`)
|
||||
REFERENCES `admin_users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Plantillas de formularios creadas por administradores';
|
||||
|
||||
-- 2. Envíos (instancias de un formulario enviado a un paciente)
|
||||
CREATE TABLE IF NOT EXISTS `lab_form_envios` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`formulario_id` INT(11) NOT NULL,
|
||||
`paciente_id` INT(11) DEFAULT NULL,
|
||||
`domicilio_id` INT(11) DEFAULT NULL,
|
||||
`token` CHAR(64) NOT NULL UNIQUE COMMENT 'Token público único para acceso del cliente',
|
||||
`datos_prefilled` LONGTEXT DEFAULT NULL COMMENT 'JSON con datos pre-llenados por el enfermero',
|
||||
`datos_cliente` LONGTEXT DEFAULT NULL COMMENT 'JSON con respuestas del cliente',
|
||||
`firma_svg` LONGTEXT DEFAULT NULL COMMENT 'Firma del cliente como SVG/PNG base64',
|
||||
`ip_cliente` VARCHAR(45) DEFAULT NULL,
|
||||
`user_agent` VARCHAR(512) DEFAULT NULL,
|
||||
`estado` ENUM('pendiente','completado','firmado','expirado') NOT NULL DEFAULT 'pendiente',
|
||||
`enviado_por` INT(11) DEFAULT NULL COMMENT 'ID admin_users que envió el link',
|
||||
`enviado_via` ENUM('whatsapp','email','link') DEFAULT 'whatsapp',
|
||||
`expira_en` DATETIME DEFAULT NULL,
|
||||
`completado_en` DATETIME DEFAULT NULL,
|
||||
`created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_fenv_form` (`formulario_id`),
|
||||
KEY `idx_fenv_paciente` (`paciente_id`),
|
||||
KEY `idx_fenv_token` (`token`),
|
||||
KEY `idx_fenv_estado` (`estado`),
|
||||
CONSTRAINT `fk_fenv_form` FOREIGN KEY (`formulario_id`) REFERENCES `lab_formularios` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_fenv_paciente` FOREIGN KEY (`paciente_id`) REFERENCES `lab_pacientes` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_fenv_domicilio` FOREIGN KEY (`domicilio_id`) REFERENCES `lab_domicilios` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_fenv_enviado` FOREIGN KEY (`enviado_por`) REFERENCES `admin_users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Instancias de formularios enviados a pacientes';
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* Migración: Módulo Administrativo de Laboratorio
|
||||
* Ejecuta las 7 migraciones SQL del módulo en orden
|
||||
*
|
||||
* Uso:
|
||||
* php migrations/20260302_lab_run_migrations.php
|
||||
* php migrations/20260302_lab_run_migrations.php --rollback
|
||||
*
|
||||
* Las tablas se crean en este orden para respetar las FK:
|
||||
* 1. lab_pacientes (depende de users)
|
||||
* 2. lab_enfermeras (independiente)
|
||||
* 3. lab_ordenes_medicas (depende de lab_pacientes, conversations, admin_users)
|
||||
* 4. lab_domicilios (depende de lab_ordenes_medicas, lab_pacientes)
|
||||
* 5. lab_asignaciones (depende de lab_domicilios, lab_enfermeras)
|
||||
* 6. lab_autorizaciones (depende de lab_ordenes_medicas)
|
||||
* 7. lab_actividad_admin (depende de admin_users)
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
|
||||
$isRollback = in_array('--rollback', $argv ?? []);
|
||||
$line = str_repeat('─', 60);
|
||||
|
||||
echo "\n$line\n";
|
||||
echo $isRollback
|
||||
? " 🔄 ROLLBACK — Módulo Administrativo Lab\n"
|
||||
: " 🚀 MIGRACIÓN — Módulo Administrativo Lab\n";
|
||||
echo "$line\n\n";
|
||||
|
||||
// ── Archivos en orden de ejecución (rollback = inverso) ──────────────────────
|
||||
$migrations = [
|
||||
'20260302_lab_01_pacientes.sql',
|
||||
'20260302_lab_02_enfermeras.sql',
|
||||
'20260302_lab_03_ordenes_medicas.sql',
|
||||
'20260302_lab_04_domicilios.sql',
|
||||
'20260302_lab_05_asignaciones.sql',
|
||||
'20260302_lab_06_autorizaciones.sql',
|
||||
'20260302_lab_07_actividad_admin.sql',
|
||||
];
|
||||
|
||||
// ── Sentencias DROP para rollback (orden inverso para respetar FK) ───────────
|
||||
$rollback = [
|
||||
'DROP TABLE IF EXISTS `lab_actividad_admin`',
|
||||
'DROP TABLE IF EXISTS `lab_autorizaciones`',
|
||||
'DROP TABLE IF EXISTS `lab_asignaciones`',
|
||||
'DROP TABLE IF EXISTS `lab_domicilios`',
|
||||
'DROP TABLE IF EXISTS `lab_ordenes_medicas`',
|
||||
'DROP TABLE IF EXISTS `lab_enfermeras`',
|
||||
'DROP TABLE IF EXISTS `lab_pacientes`',
|
||||
];
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$pdo = $db->getConnection();
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
if ($isRollback) {
|
||||
// ── ROLLBACK ─────────────────────────────────────────────────────────
|
||||
foreach ($rollback as $sql) {
|
||||
$table = preg_replace('/.*`(lab_\w+)`.*/', '$1', $sql);
|
||||
$pdo->exec($sql);
|
||||
echo " ✅ DROP $table\n";
|
||||
}
|
||||
echo "\n ✔ Rollback completado correctamente.\n\n";
|
||||
} else {
|
||||
// ── MIGRACIÓN ────────────────────────────────────────────────────────
|
||||
$dir = __DIR__;
|
||||
|
||||
foreach ($migrations as $file) {
|
||||
$path = "$dir/$file";
|
||||
|
||||
if (!file_exists($path)) {
|
||||
echo " ⚠️ Archivo no encontrado: $file (omitido)\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$sql = file_get_contents($path);
|
||||
|
||||
// Separar sentencias por ';' pero solo las CREATE TABLE
|
||||
// (Los archivos contienen una sola sentencia CREATE TABLE)
|
||||
$pdo->exec($sql);
|
||||
|
||||
// Extraer nombre de tabla del archivo para feedback
|
||||
preg_match('/CREATE TABLE IF NOT EXISTS `(\w+)`/i', $sql, $m);
|
||||
$table = $m[1] ?? $file;
|
||||
echo " ✅ $table\n";
|
||||
}
|
||||
|
||||
echo "\n$line\n";
|
||||
echo " ✔ Todas las migraciones ejecutadas correctamente.\n";
|
||||
echo "$line\n\n";
|
||||
|
||||
// ── Tabla de control de migraciones ejecutadas en system_logs ────────
|
||||
try {
|
||||
$pdo->prepare("
|
||||
INSERT INTO system_logs (level, message, context, created_at)
|
||||
VALUES ('info', 'lab_module_migration', ?, NOW())
|
||||
")->execute([json_encode([
|
||||
'version' => '20260302',
|
||||
'module' => 'lab_admin',
|
||||
'tables' => 7,
|
||||
'executed' => date('Y-m-d H:i:s'),
|
||||
])]);
|
||||
} catch (Exception $e) {
|
||||
// system_logs puede no tener estas columnas — no falla la migración
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo "\n ❌ ERROR: " . $e->getMessage() . "\n\n";
|
||||
echo " Ejecuta --rollback para deshacer los cambios parciales.\n\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
-- ============================================================
|
||||
-- Migration: 20260303_lab_10_domicilio_extras
|
||||
-- Agrega tipo_cliente (particular/seguro) y examenes_solicitados
|
||||
-- a la tabla lab_domicilios, para cuando no hay orden médica.
|
||||
-- ============================================================
|
||||
|
||||
ALTER TABLE `lab_domicilios`
|
||||
ADD COLUMN `tipo_cliente` ENUM('particular','seguro','eps') NOT NULL DEFAULT 'particular'
|
||||
COMMENT 'Si el servicio es particular, por seguro o EPS'
|
||||
AFTER `tipo_servicio`,
|
||||
|
||||
ADD COLUMN `examenes_solicitados` TEXT DEFAULT NULL
|
||||
COMMENT 'Exámenes escritos (cuando no hay foto de orden médica)'
|
||||
AFTER `tipo_cliente`;
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Migración: agregar columnas de contenido a message_templates (producción)
|
||||
-- Las columnas body_text, header_*, footer_text, components, example_parameters
|
||||
-- existen en el schema local pero faltaban en producción.
|
||||
|
||||
ALTER TABLE `message_templates`
|
||||
ADD COLUMN IF NOT EXISTS `body_text` TEXT DEFAULT NULL
|
||||
COMMENT 'Texto del cuerpo de la plantilla'
|
||||
AFTER `status`,
|
||||
ADD COLUMN IF NOT EXISTS `header_text` VARCHAR(255) DEFAULT NULL
|
||||
COMMENT 'Texto del encabezado (si header_type=text)'
|
||||
AFTER `body_text`,
|
||||
ADD COLUMN IF NOT EXISTS `header_type` ENUM('text','image','video','document') DEFAULT NULL
|
||||
COMMENT 'Tipo de encabezado multimedia'
|
||||
AFTER `header_text`,
|
||||
ADD COLUMN IF NOT EXISTS `footer_text` VARCHAR(255) DEFAULT NULL
|
||||
COMMENT 'Texto del pie de la plantilla'
|
||||
AFTER `header_type`,
|
||||
ADD COLUMN IF NOT EXISTS `components` LONGTEXT DEFAULT NULL
|
||||
COMMENT 'JSON completo de componentes de la plantilla'
|
||||
AFTER `footer_text`,
|
||||
ADD COLUMN IF NOT EXISTS `example_parameters` LONGTEXT DEFAULT NULL
|
||||
COMMENT 'JSON con parámetros de ejemplo'
|
||||
AFTER `components`,
|
||||
ADD COLUMN IF NOT EXISTS `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
AFTER `created_at`;
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
$db = Database::getInstance();
|
||||
|
||||
// ── 1. Tabla lab_config ───────────────────────────────────────────────
|
||||
$db->query('CREATE TABLE IF NOT EXISTS lab_config (
|
||||
clave VARCHAR(80) NOT NULL PRIMARY KEY,
|
||||
valor LONGTEXT NOT NULL DEFAULT "",
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4');
|
||||
echo "tabla lab_config OK\n";
|
||||
|
||||
// Valores iniciales
|
||||
$defaults = [
|
||||
['empresa_nombre', 'Laboratorio Clínico Ximena'],
|
||||
['empresa_subtitulo', 'Análisis Clínicos'],
|
||||
['empresa_direccion', ''],
|
||||
['empresa_telefono', ''],
|
||||
['empresa_email', ''],
|
||||
['empresa_ciudad', ''],
|
||||
['doc_color', '#1565c0'],
|
||||
['doc_logo_base64', ''],
|
||||
['doc_pie_pagina', 'Documento generado digitalmente. Verifique su autenticidad en el sistema.'],
|
||||
];
|
||||
foreach ($defaults as [$k, $v]) {
|
||||
$db->query('INSERT IGNORE INTO lab_config(clave, valor) VALUES(?, ?)', [$k, $v]);
|
||||
}
|
||||
echo count($defaults) . " valores iniciales insertados (IGNORE)\n";
|
||||
|
||||
// ── 2. Columnas nuevas en lab_formularios ─────────────────────────────
|
||||
$cols = [
|
||||
'doc_encabezado VARCHAR(200) NULL DEFAULT NULL',
|
||||
'doc_subtitulo VARCHAR(200) NULL DEFAULT NULL',
|
||||
'doc_logo_base64 LONGTEXT NULL DEFAULT NULL',
|
||||
'doc_color VARCHAR(20) NULL DEFAULT NULL',
|
||||
'doc_pie_pagina VARCHAR(500) NULL DEFAULT NULL',
|
||||
];
|
||||
|
||||
foreach ($cols as $def) {
|
||||
$name = explode(' ', trim($def))[0];
|
||||
$exists = $db->fetchAll("SHOW COLUMNS FROM lab_formularios WHERE Field = '$name'");
|
||||
if (!$exists) {
|
||||
$db->query("ALTER TABLE lab_formularios ADD COLUMN $def");
|
||||
echo "Columna agregada: $name\n";
|
||||
} else {
|
||||
echo "Ya existía: $name\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\nMigración completada OK\n";
|
||||
@@ -0,0 +1,75 @@
|
||||
-- ============================================================
|
||||
-- Migración: Sistema de Roles y Módulos
|
||||
-- Fecha: 2026-03-04
|
||||
-- Descripción: Crea tablas roles y role_modules; vincula admin_users
|
||||
-- ============================================================
|
||||
|
||||
-- ── 1. Tabla de roles ────────────────────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS `roles` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(100) NOT NULL COMMENT 'Nombre legible del rol',
|
||||
`slug` VARCHAR(50) NOT NULL COMMENT 'Clave interna (enfermero, admin, …)',
|
||||
`description` TEXT DEFAULT NULL,
|
||||
`color` VARCHAR(20) DEFAULT '#6c757d' COMMENT 'Color HEX para la UI',
|
||||
`is_system` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1 = no se puede eliminar',
|
||||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_slug` (`slug`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ── 2. Tabla de módulos asignados por rol ────────────────────
|
||||
-- Cada fila «activa» el módulo para ese rol.
|
||||
CREATE TABLE IF NOT EXISTS `role_modules` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`role_id` INT(11) NOT NULL,
|
||||
`module_slug` VARCHAR(100) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_role_module` (`role_id`, `module_slug`),
|
||||
CONSTRAINT `fk_rm_role` FOREIGN KEY (`role_id`)
|
||||
REFERENCES `roles`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ── 3. Vincular admin_users con roles ────────────────────────
|
||||
-- (Se ignora si la columna ya existe - compatible MySQL y MariaDB)
|
||||
ALTER TABLE `admin_users`
|
||||
ADD COLUMN `role_id` INT(11) NULL DEFAULT NULL
|
||||
COMMENT 'FK a roles.id';
|
||||
|
||||
ALTER TABLE `admin_users`
|
||||
ADD INDEX `idx_role_id` (`role_id`);
|
||||
|
||||
-- ── 4. Roles del sistema (no borrables) ─────────────────────
|
||||
INSERT IGNORE INTO `roles` (`id`, `name`, `slug`, `description`, `color`, `is_system`) VALUES
|
||||
(1, 'Administrador', 'admin', 'Acceso completo a todos los módulos', '#0d6efd', 1),
|
||||
(2, 'Enfermero', 'enfermero', 'Solo portal de domicilios asignados y formularios','#6f42c1', 1);
|
||||
|
||||
-- ── 5. Módulos para el rol Administrador (todos) ─────────────
|
||||
INSERT IGNORE INTO `role_modules` (`role_id`, `module_slug`) VALUES
|
||||
(1, 'whatsapp'),
|
||||
(1, 'lab_dashboard'),
|
||||
(1, 'lab_ordenes'),
|
||||
(1, 'lab_pacientes'),
|
||||
(1, 'lab_domicilios'),
|
||||
(1, 'lab_enfermeras'),
|
||||
(1, 'lab_formularios'),
|
||||
(1, 'lab_reportes'),
|
||||
(1, 'lab_configuracion'),
|
||||
(1, 'usuarios');
|
||||
|
||||
-- ── 6. Módulos para el rol Enfermero ────────────────────────
|
||||
INSERT IGNORE INTO `role_modules` (`role_id`, `module_slug`) VALUES
|
||||
(2, 'enfermero_portal'),
|
||||
(2, 'lab_formularios');
|
||||
|
||||
-- ── 7. Vincular usuarios existentes con su role_id ───────────
|
||||
UPDATE `admin_users` SET `role_id` = 1 WHERE `role` = 'admin' AND `role_id` IS NULL;
|
||||
UPDATE `admin_users` SET `role_id` = 2 WHERE `role` = 'enfermero' AND `role_id` IS NULL;
|
||||
-- Si algún usuario no tiene rol asignado, asignarle admin por defecto
|
||||
UPDATE `admin_users` SET `role_id` = 1 WHERE `role_id` IS NULL;
|
||||
|
||||
-- ── 8. FK suave (solo si FK no existe aún) ──────────────────
|
||||
-- (MariaDB/MySQL no tiene ADD CONSTRAINT IF NOT EXISTS, usamos el IGNORE del INSERT)
|
||||
-- La FK se omite intencionalmente para no bloquear si ya existe;
|
||||
-- conéctala manualmente si el motor lo permite:
|
||||
-- ALTER TABLE admin_users ADD CONSTRAINT fk_au_role FOREIGN KEY (role_id) REFERENCES roles(id);
|
||||
Reference in New Issue
Block a user