feat: version 4.7.0 -- Agenda medica

Modulo clinic (habilitado por usuario): citas de pacientes para medicos con choques
bloqueantes (medico, paciente con cualquier medico, quirofano/bloqueos recurrentes y
horario de atencion), validados en transaccion con bloqueo de filas para que dos
recepcionistas no tomen el mismo hueco. Recepcion (alcance todos) y medico (alcance
propio). Vista Dia por columnas de medico, Semana y Lista; pacientes con historial;
bloqueos; configuracion de personal, horarios y tipos solo admin/superadmin. Capa de
citas en el calendario personal del medico. Migracion 036.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-10-28 12:57:43 -05:00
parent bdc62403f4
commit 1e25022630
29 changed files with 1649 additions and 34 deletions
+102
View File
@@ -0,0 +1,102 @@
SET NAMES utf8mb4;
CREATE TABLE IF NOT EXISTS clinic_staff (
user_id INT PRIMARY KEY,
scope ENUM('all','own') NOT NULL DEFAULT 'own',
is_doctor TINYINT(1) NOT NULL DEFAULT 0,
specialty VARCHAR(120) NULL,
color VARCHAR(7) NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
edit_version INT UNSIGNED NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT fk_clinic_staff_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS clinic_patients (
id INT AUTO_INCREMENT PRIMARY KEY,
first_names VARCHAR(120) NOT NULL,
last_names VARCHAR(120) NOT NULL,
identification VARCHAR(40) NULL UNIQUE,
phone VARCHAR(40) NOT NULL,
email VARCHAR(160) NULL,
birth_date DATE NULL,
notes VARCHAR(500) NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_by INT NULL,
edit_version INT UNSIGNED NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_clinic_patient_name (last_names, first_names),
INDEX idx_clinic_patient_phone (phone),
CONSTRAINT fk_clinic_patient_creator FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS clinic_schedules (
id INT AUTO_INCREMENT PRIMARY KEY,
doctor_user_id INT NOT NULL,
weekday TINYINT UNSIGNED NOT NULL,
starts_time TIME NOT NULL,
ends_time TIME NOT NULL,
INDEX idx_clinic_schedule_doctor_day (doctor_user_id, weekday),
CONSTRAINT fk_clinic_schedule_doctor FOREIGN KEY (doctor_user_id) REFERENCES clinic_staff(user_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS clinic_appointment_types (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(120) NOT NULL,
duration_minutes SMALLINT UNSIGNED NOT NULL,
color VARCHAR(7) NOT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
edit_version INT UNSIGNED NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS clinic_appointments (
id INT AUTO_INCREMENT PRIMARY KEY,
doctor_user_id INT NOT NULL,
patient_id INT NOT NULL,
type_id INT NOT NULL,
starts_at DATETIME NOT NULL,
ends_at DATETIME NOT NULL,
status ENUM('scheduled','confirmed','attended','no_show','cancelled') NOT NULL DEFAULT 'scheduled',
channel ENUM('phone','whatsapp','in_person','other') NOT NULL DEFAULT 'phone',
notes VARCHAR(500) NULL,
created_by INT NULL,
cancelled_at DATETIME NULL,
cancelled_by INT NULL,
cancelled_reason VARCHAR(500) NULL,
edit_version INT UNSIGNED NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_clinic_appointment_doctor_range (doctor_user_id, starts_at, ends_at, status),
INDEX idx_clinic_appointment_patient_range (patient_id, starts_at, ends_at, status),
CONSTRAINT fk_clinic_appointment_doctor FOREIGN KEY (doctor_user_id) REFERENCES clinic_staff(user_id),
CONSTRAINT fk_clinic_appointment_patient FOREIGN KEY (patient_id) REFERENCES clinic_patients(id),
CONSTRAINT fk_clinic_appointment_type FOREIGN KEY (type_id) REFERENCES clinic_appointment_types(id),
CONSTRAINT fk_clinic_appointment_creator FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT fk_clinic_appointment_canceller FOREIGN KEY (cancelled_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS clinic_blocks (
id INT AUTO_INCREMENT PRIMARY KEY,
doctor_user_id INT NOT NULL,
kind ENUM('surgery','vacation','other') NOT NULL,
title VARCHAR(160) NOT NULL,
starts_at DATETIME NOT NULL,
ends_at DATETIME NOT NULL,
recurrence_json TEXT NULL,
created_by INT NULL,
edit_version INT UNSIGNED NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_clinic_block_doctor_range (doctor_user_id, starts_at, ends_at),
CONSTRAINT fk_clinic_block_doctor FOREIGN KEY (doctor_user_id) REFERENCES clinic_staff(user_id),
CONSTRAINT fk_clinic_block_creator FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Bootstrap del único configurador inicial. El resto del personal se habilita desde la UI.
INSERT IGNORE INTO clinic_staff (user_id, scope, is_doctor, is_active)
SELECT u.id, 'all', 0, 1 FROM users u JOIN roles r ON r.id=u.role_id
WHERE r.code='superadmin' AND u.is_active=1 ORDER BY u.id LIMIT 1;