Migración desde clinica-dental/database - Estándar multi-repo v2
Código migrado del proyecto monorepo original Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4511fc6a5a
commit
8c61a7e449
502
schemas/01-dental-schema-ddl.sql
Normal file
502
schemas/01-dental-schema-ddl.sql
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- DENTAL SCHEMA - Especialización de ERP-Clínicas
|
||||||
|
-- Clínica Dental
|
||||||
|
-- ============================================================================
|
||||||
|
-- Fecha: 2026-01-04
|
||||||
|
-- Versión: 1.0
|
||||||
|
-- Hereda de: erp-clinicas FASE-8
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Schema
|
||||||
|
CREATE SCHEMA IF NOT EXISTS dental;
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- ENUMS
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE dental.estado_pieza AS ENUM (
|
||||||
|
'sano', 'caries', 'obturacion', 'endodoncia', 'corona',
|
||||||
|
'puente', 'implante', 'ausente', 'extraccion_indicada',
|
||||||
|
'diente_temporal', 'fractura', 'movilidad'
|
||||||
|
);
|
||||||
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE dental.cara_dental AS ENUM (
|
||||||
|
'mesial', 'distal', 'oclusal', 'incisal',
|
||||||
|
'vestibular', 'bucal', 'lingual', 'palatino'
|
||||||
|
);
|
||||||
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE dental.estado_tratamiento AS ENUM (
|
||||||
|
'pendiente', 'en_proceso', 'completado', 'cancelado'
|
||||||
|
);
|
||||||
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE dental.tipo_ortodoncia AS ENUM (
|
||||||
|
'brackets_metalicos', 'brackets_esteticos', 'brackets_linguales',
|
||||||
|
'alineadores', 'removible', 'retenedor'
|
||||||
|
);
|
||||||
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- CATÁLOGOS
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Piezas dentales
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.piezas_dentales (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
numero VARCHAR(10) NOT NULL UNIQUE, -- '11', '12', ... '48', '51'...'85'
|
||||||
|
nombre VARCHAR(50) NOT NULL,
|
||||||
|
cuadrante INTEGER NOT NULL CHECK (cuadrante BETWEEN 1 AND 8),
|
||||||
|
es_temporal BOOLEAN DEFAULT false,
|
||||||
|
descripcion TEXT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.piezas_dentales IS 'Catálogo de piezas dentales (nomenclatura FDI)';
|
||||||
|
|
||||||
|
-- Tratamientos dentales
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.tratamientos_catalogo (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
codigo VARCHAR(20) NOT NULL,
|
||||||
|
nombre VARCHAR(100) NOT NULL,
|
||||||
|
categoria VARCHAR(50), -- 'prevencion', 'restauracion', 'endodoncia', etc.
|
||||||
|
descripcion TEXT,
|
||||||
|
duracion_minutos INTEGER DEFAULT 30,
|
||||||
|
precio_base NUMERIC(10,2),
|
||||||
|
requiere_rx BOOLEAN DEFAULT false,
|
||||||
|
requiere_anestesia BOOLEAN DEFAULT false,
|
||||||
|
active BOOLEAN DEFAULT true,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
CONSTRAINT uq_tratamientos_tenant_codigo UNIQUE(tenant_id, codigo)
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.tratamientos_catalogo IS 'Catálogo de tratamientos dentales';
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- TABLAS PRINCIPALES
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Odontograma
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.odontogramas (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
patient_id UUID NOT NULL, -- Referencia a clinica.patients
|
||||||
|
fecha_creacion DATE NOT NULL DEFAULT CURRENT_DATE,
|
||||||
|
fecha_actualizacion DATE,
|
||||||
|
notas TEXT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.odontogramas IS 'Odontogramas de pacientes';
|
||||||
|
|
||||||
|
-- Estado de piezas dentales por odontograma
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.odontograma_piezas (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
odontograma_id UUID NOT NULL REFERENCES dental.odontogramas(id) ON DELETE CASCADE,
|
||||||
|
pieza_id UUID NOT NULL REFERENCES dental.piezas_dentales(id),
|
||||||
|
-- Estado general
|
||||||
|
estado dental.estado_pieza DEFAULT 'sano',
|
||||||
|
-- Estados por cara (JSONB para flexibilidad)
|
||||||
|
caras_afectadas JSONB, -- {"mesial": "caries", "oclusal": "obturacion"}
|
||||||
|
-- Notas
|
||||||
|
observaciones TEXT,
|
||||||
|
-- Control
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
CONSTRAINT uq_odontograma_pieza UNIQUE(odontograma_id, pieza_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.odontograma_piezas IS 'Estado de cada pieza dental en el odontograma';
|
||||||
|
|
||||||
|
-- Tratamientos de paciente
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.tratamientos_paciente (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
patient_id UUID NOT NULL,
|
||||||
|
odontograma_id UUID REFERENCES dental.odontogramas(id),
|
||||||
|
tratamiento_id UUID REFERENCES dental.tratamientos_catalogo(id),
|
||||||
|
odontologo_id UUID, -- Referencia a clinica.doctors
|
||||||
|
consultation_id UUID, -- Referencia a clinica.consultations
|
||||||
|
-- Pieza(s) tratada(s)
|
||||||
|
pieza_id UUID REFERENCES dental.piezas_dentales(id),
|
||||||
|
caras_tratadas dental.cara_dental[],
|
||||||
|
-- Datos del tratamiento
|
||||||
|
fecha_inicio DATE NOT NULL DEFAULT CURRENT_DATE,
|
||||||
|
fecha_fin DATE,
|
||||||
|
estado dental.estado_tratamiento DEFAULT 'pendiente',
|
||||||
|
-- Costo
|
||||||
|
precio NUMERIC(10,2),
|
||||||
|
descuento NUMERIC(5,2) DEFAULT 0,
|
||||||
|
precio_final NUMERIC(10,2),
|
||||||
|
-- Notas
|
||||||
|
notas TEXT,
|
||||||
|
-- Control
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.tratamientos_paciente IS 'Tratamientos realizados a pacientes';
|
||||||
|
|
||||||
|
-- Ortodoncia
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.ortodoncia (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
patient_id UUID NOT NULL,
|
||||||
|
odontologo_id UUID,
|
||||||
|
-- Tipo de tratamiento
|
||||||
|
tipo dental.tipo_ortodoncia NOT NULL,
|
||||||
|
marca VARCHAR(100),
|
||||||
|
-- Fechas
|
||||||
|
fecha_inicio DATE NOT NULL,
|
||||||
|
fecha_estimada_fin DATE,
|
||||||
|
fecha_real_fin DATE,
|
||||||
|
-- Estado
|
||||||
|
estado dental.estado_tratamiento DEFAULT 'en_proceso',
|
||||||
|
meses_estimados INTEGER,
|
||||||
|
-- Costo
|
||||||
|
costo_total NUMERIC(10,2),
|
||||||
|
enganche NUMERIC(10,2),
|
||||||
|
mensualidad NUMERIC(10,2),
|
||||||
|
-- Notas
|
||||||
|
notas TEXT,
|
||||||
|
-- Control
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.ortodoncia IS 'Tratamientos de ortodoncia';
|
||||||
|
|
||||||
|
-- Citas de ortodoncia (seguimiento)
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.ortodoncia_citas (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
ortodoncia_id UUID NOT NULL REFERENCES dental.ortodoncia(id) ON DELETE CASCADE,
|
||||||
|
appointment_id UUID, -- Referencia a clinica.appointments
|
||||||
|
-- Datos de la cita
|
||||||
|
fecha DATE NOT NULL,
|
||||||
|
numero_cita INTEGER,
|
||||||
|
-- Procedimiento
|
||||||
|
procedimiento TEXT,
|
||||||
|
arco_superior VARCHAR(50),
|
||||||
|
arco_inferior VARCHAR(50),
|
||||||
|
ligas VARCHAR(50),
|
||||||
|
-- Observaciones
|
||||||
|
observaciones TEXT,
|
||||||
|
proxima_cita DATE,
|
||||||
|
-- Control
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.ortodoncia_citas IS 'Citas de seguimiento de ortodoncia';
|
||||||
|
|
||||||
|
-- Prótesis
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.protesis (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
patient_id UUID NOT NULL,
|
||||||
|
odontologo_id UUID,
|
||||||
|
-- Tipo
|
||||||
|
tipo VARCHAR(50) NOT NULL, -- 'corona', 'puente', 'parcial', 'total', 'implante'
|
||||||
|
-- Piezas involucradas
|
||||||
|
piezas_involucradas TEXT[], -- ['11', '12', '13']
|
||||||
|
-- Laboratorio
|
||||||
|
laboratorio_id UUID, -- Referencia a proveedor
|
||||||
|
fecha_envio_lab DATE,
|
||||||
|
fecha_recepcion_lab DATE,
|
||||||
|
-- Material
|
||||||
|
material VARCHAR(100),
|
||||||
|
color VARCHAR(50),
|
||||||
|
-- Estado
|
||||||
|
estado dental.estado_tratamiento DEFAULT 'en_proceso',
|
||||||
|
fecha_colocacion DATE,
|
||||||
|
-- Garantía
|
||||||
|
tiene_garantia BOOLEAN DEFAULT false,
|
||||||
|
meses_garantia INTEGER,
|
||||||
|
-- Costo
|
||||||
|
costo_laboratorio NUMERIC(10,2),
|
||||||
|
precio_paciente NUMERIC(10,2),
|
||||||
|
-- Notas
|
||||||
|
notas TEXT,
|
||||||
|
-- Control
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.protesis IS 'Registro de prótesis dentales';
|
||||||
|
|
||||||
|
-- Radiografías
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.radiografias (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
patient_id UUID NOT NULL,
|
||||||
|
consultation_id UUID,
|
||||||
|
-- Tipo
|
||||||
|
tipo VARCHAR(50) NOT NULL, -- 'periapical', 'panoramica', 'cefalometrica', 'oclusal'
|
||||||
|
pieza_id UUID REFERENCES dental.piezas_dentales(id),
|
||||||
|
-- Archivo
|
||||||
|
fecha DATE NOT NULL DEFAULT CURRENT_DATE,
|
||||||
|
url_imagen VARCHAR(255),
|
||||||
|
-- Interpretación
|
||||||
|
interpretacion TEXT,
|
||||||
|
-- Control
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.radiografias IS 'Registro de radiografías dentales';
|
||||||
|
|
||||||
|
-- Presupuestos
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.presupuestos (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
patient_id UUID NOT NULL,
|
||||||
|
odontologo_id UUID,
|
||||||
|
-- Datos
|
||||||
|
numero VARCHAR(20),
|
||||||
|
fecha DATE NOT NULL DEFAULT CURRENT_DATE,
|
||||||
|
fecha_vencimiento DATE,
|
||||||
|
-- Estado
|
||||||
|
estado VARCHAR(20) DEFAULT 'pendiente', -- 'pendiente', 'aprobado', 'rechazado', 'vencido'
|
||||||
|
-- Totales
|
||||||
|
subtotal NUMERIC(12,2) DEFAULT 0,
|
||||||
|
descuento_porcentaje NUMERIC(5,2) DEFAULT 0,
|
||||||
|
descuento_monto NUMERIC(12,2) DEFAULT 0,
|
||||||
|
total NUMERIC(12,2) DEFAULT 0,
|
||||||
|
-- Plan de pago
|
||||||
|
requiere_financiamiento BOOLEAN DEFAULT false,
|
||||||
|
enganche NUMERIC(12,2),
|
||||||
|
numero_pagos INTEGER,
|
||||||
|
monto_pago NUMERIC(12,2),
|
||||||
|
-- Notas
|
||||||
|
notas TEXT,
|
||||||
|
-- Control
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.presupuestos IS 'Presupuestos de tratamiento';
|
||||||
|
|
||||||
|
-- Líneas de presupuesto
|
||||||
|
CREATE TABLE IF NOT EXISTS dental.presupuesto_lineas (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
presupuesto_id UUID NOT NULL REFERENCES dental.presupuestos(id) ON DELETE CASCADE,
|
||||||
|
tratamiento_id UUID REFERENCES dental.tratamientos_catalogo(id),
|
||||||
|
-- Pieza
|
||||||
|
pieza_id UUID REFERENCES dental.piezas_dentales(id),
|
||||||
|
descripcion TEXT,
|
||||||
|
-- Cantidades
|
||||||
|
cantidad INTEGER DEFAULT 1,
|
||||||
|
precio_unitario NUMERIC(10,2),
|
||||||
|
descuento NUMERIC(5,2) DEFAULT 0,
|
||||||
|
subtotal NUMERIC(10,2),
|
||||||
|
-- Secuencia
|
||||||
|
sequence INTEGER DEFAULT 10,
|
||||||
|
-- Control
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE dental.presupuesto_lineas IS 'Líneas de presupuesto';
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- EXTENSIONES A TABLAS DE ERP-CLINICAS
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
-- Extensión a clinica.patients
|
||||||
|
IF EXISTS (SELECT 1 FROM information_schema.tables
|
||||||
|
WHERE table_schema = 'clinica' AND table_name = 'patients') THEN
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'clinica' AND table_name = 'patients'
|
||||||
|
AND column_name = 'odontograma_activo_id') THEN
|
||||||
|
ALTER TABLE clinica.patients ADD COLUMN odontograma_activo_id UUID;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'clinica' AND table_name = 'patients'
|
||||||
|
AND column_name = 'tiene_ortodoncia') THEN
|
||||||
|
ALTER TABLE clinica.patients ADD COLUMN tiene_ortodoncia BOOLEAN DEFAULT false;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_schema = 'clinica' AND table_name = 'patients'
|
||||||
|
AND column_name = 'tiene_protesis') THEN
|
||||||
|
ALTER TABLE clinica.patients ADD COLUMN tiene_protesis BOOLEAN DEFAULT false;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- SEED: Piezas dentales (catálogo global)
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
INSERT INTO dental.piezas_dentales (numero, nombre, cuadrante, es_temporal) VALUES
|
||||||
|
-- Cuadrante 1 - Superior derecho (permanentes)
|
||||||
|
('18', 'Tercer molar superior derecho', 1, false),
|
||||||
|
('17', 'Segundo molar superior derecho', 1, false),
|
||||||
|
('16', 'Primer molar superior derecho', 1, false),
|
||||||
|
('15', 'Segundo premolar superior derecho', 1, false),
|
||||||
|
('14', 'Primer premolar superior derecho', 1, false),
|
||||||
|
('13', 'Canino superior derecho', 1, false),
|
||||||
|
('12', 'Incisivo lateral superior derecho', 1, false),
|
||||||
|
('11', 'Incisivo central superior derecho', 1, false),
|
||||||
|
-- Cuadrante 2 - Superior izquierdo (permanentes)
|
||||||
|
('21', 'Incisivo central superior izquierdo', 2, false),
|
||||||
|
('22', 'Incisivo lateral superior izquierdo', 2, false),
|
||||||
|
('23', 'Canino superior izquierdo', 2, false),
|
||||||
|
('24', 'Primer premolar superior izquierdo', 2, false),
|
||||||
|
('25', 'Segundo premolar superior izquierdo', 2, false),
|
||||||
|
('26', 'Primer molar superior izquierdo', 2, false),
|
||||||
|
('27', 'Segundo molar superior izquierdo', 2, false),
|
||||||
|
('28', 'Tercer molar superior izquierdo', 2, false),
|
||||||
|
-- Cuadrante 3 - Inferior izquierdo (permanentes)
|
||||||
|
('31', 'Incisivo central inferior izquierdo', 3, false),
|
||||||
|
('32', 'Incisivo lateral inferior izquierdo', 3, false),
|
||||||
|
('33', 'Canino inferior izquierdo', 3, false),
|
||||||
|
('34', 'Primer premolar inferior izquierdo', 3, false),
|
||||||
|
('35', 'Segundo premolar inferior izquierdo', 3, false),
|
||||||
|
('36', 'Primer molar inferior izquierdo', 3, false),
|
||||||
|
('37', 'Segundo molar inferior izquierdo', 3, false),
|
||||||
|
('38', 'Tercer molar inferior izquierdo', 3, false),
|
||||||
|
-- Cuadrante 4 - Inferior derecho (permanentes)
|
||||||
|
('41', 'Incisivo central inferior derecho', 4, false),
|
||||||
|
('42', 'Incisivo lateral inferior derecho', 4, false),
|
||||||
|
('43', 'Canino inferior derecho', 4, false),
|
||||||
|
('44', 'Primer premolar inferior derecho', 4, false),
|
||||||
|
('45', 'Segundo premolar inferior derecho', 4, false),
|
||||||
|
('46', 'Primer molar inferior derecho', 4, false),
|
||||||
|
('47', 'Segundo molar inferior derecho', 4, false),
|
||||||
|
('48', 'Tercer molar inferior derecho', 4, false),
|
||||||
|
-- Cuadrante 5 - Superior derecho (temporales)
|
||||||
|
('55', 'Segundo molar temporal superior derecho', 5, true),
|
||||||
|
('54', 'Primer molar temporal superior derecho', 5, true),
|
||||||
|
('53', 'Canino temporal superior derecho', 5, true),
|
||||||
|
('52', 'Incisivo lateral temporal superior derecho', 5, true),
|
||||||
|
('51', 'Incisivo central temporal superior derecho', 5, true),
|
||||||
|
-- Cuadrante 6 - Superior izquierdo (temporales)
|
||||||
|
('61', 'Incisivo central temporal superior izquierdo', 6, true),
|
||||||
|
('62', 'Incisivo lateral temporal superior izquierdo', 6, true),
|
||||||
|
('63', 'Canino temporal superior izquierdo', 6, true),
|
||||||
|
('64', 'Primer molar temporal superior izquierdo', 6, true),
|
||||||
|
('65', 'Segundo molar temporal superior izquierdo', 6, true),
|
||||||
|
-- Cuadrante 7 - Inferior izquierdo (temporales)
|
||||||
|
('71', 'Incisivo central temporal inferior izquierdo', 7, true),
|
||||||
|
('72', 'Incisivo lateral temporal inferior izquierdo', 7, true),
|
||||||
|
('73', 'Canino temporal inferior izquierdo', 7, true),
|
||||||
|
('74', 'Primer molar temporal inferior izquierdo', 7, true),
|
||||||
|
('75', 'Segundo molar temporal inferior izquierdo', 7, true),
|
||||||
|
-- Cuadrante 8 - Inferior derecho (temporales)
|
||||||
|
('81', 'Incisivo central temporal inferior derecho', 8, true),
|
||||||
|
('82', 'Incisivo lateral temporal inferior derecho', 8, true),
|
||||||
|
('83', 'Canino temporal inferior derecho', 8, true),
|
||||||
|
('84', 'Primer molar temporal inferior derecho', 8, true),
|
||||||
|
('85', 'Segundo molar temporal inferior derecho', 8, true)
|
||||||
|
ON CONFLICT (numero) DO NOTHING;
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- ÍNDICES
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tratamientos_catalogo_tenant ON dental.tratamientos_catalogo(tenant_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tratamientos_catalogo_categoria ON dental.tratamientos_catalogo(tenant_id, categoria);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_odontogramas_tenant ON dental.odontogramas(tenant_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_odontogramas_patient ON dental.odontogramas(patient_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_odontograma_piezas_odontograma ON dental.odontograma_piezas(odontograma_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_odontograma_piezas_pieza ON dental.odontograma_piezas(pieza_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tratamientos_paciente_tenant ON dental.tratamientos_paciente(tenant_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tratamientos_paciente_patient ON dental.tratamientos_paciente(patient_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tratamientos_paciente_estado ON dental.tratamientos_paciente(tenant_id, estado);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ortodoncia_tenant ON dental.ortodoncia(tenant_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ortodoncia_patient ON dental.ortodoncia(patient_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ortodoncia_estado ON dental.ortodoncia(tenant_id, estado);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ortodoncia_citas_ortodoncia ON dental.ortodoncia_citas(ortodoncia_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_protesis_tenant ON dental.protesis(tenant_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_protesis_patient ON dental.protesis(patient_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_radiografias_tenant ON dental.radiografias(tenant_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_radiografias_patient ON dental.radiografias(patient_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_presupuestos_tenant ON dental.presupuestos(tenant_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_presupuestos_patient ON dental.presupuestos(patient_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_presupuestos_estado ON dental.presupuestos(tenant_id, estado);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_presupuesto_lineas_presupuesto ON dental.presupuesto_lineas(presupuesto_id);
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- RLS
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
ALTER TABLE dental.tratamientos_catalogo ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.odontogramas ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.odontograma_piezas ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.tratamientos_paciente ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.ortodoncia ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.ortodoncia_citas ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.protesis ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.radiografias ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.presupuestos ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE dental.presupuesto_lineas ENABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_tratamientos_cat ON dental.tratamientos_catalogo;
|
||||||
|
CREATE POLICY tenant_isolation_tratamientos_cat ON dental.tratamientos_catalogo
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_odontogramas ON dental.odontogramas;
|
||||||
|
CREATE POLICY tenant_isolation_odontogramas ON dental.odontogramas
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_odontograma_piezas ON dental.odontograma_piezas;
|
||||||
|
CREATE POLICY tenant_isolation_odontograma_piezas ON dental.odontograma_piezas
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_tratamientos_pac ON dental.tratamientos_paciente;
|
||||||
|
CREATE POLICY tenant_isolation_tratamientos_pac ON dental.tratamientos_paciente
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_ortodoncia ON dental.ortodoncia;
|
||||||
|
CREATE POLICY tenant_isolation_ortodoncia ON dental.ortodoncia
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_ortodoncia_citas ON dental.ortodoncia_citas;
|
||||||
|
CREATE POLICY tenant_isolation_ortodoncia_citas ON dental.ortodoncia_citas
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_protesis ON dental.protesis;
|
||||||
|
CREATE POLICY tenant_isolation_protesis ON dental.protesis
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_radiografias ON dental.radiografias;
|
||||||
|
CREATE POLICY tenant_isolation_radiografias ON dental.radiografias
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_presupuestos ON dental.presupuestos;
|
||||||
|
CREATE POLICY tenant_isolation_presupuestos ON dental.presupuestos
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
DROP POLICY IF EXISTS tenant_isolation_presupuesto_lineas ON dental.presupuesto_lineas;
|
||||||
|
CREATE POLICY tenant_isolation_presupuesto_lineas ON dental.presupuesto_lineas
|
||||||
|
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- FIN DENTAL SCHEMA
|
||||||
|
-- ============================================================================
|
||||||
101
seeds/fase8/01-dental-catalogos.sql
Normal file
101
seeds/fase8/01-dental-catalogos.sql
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- SEED DATA: Catálogos de Clínica Dental
|
||||||
|
-- Especialización de ERP-Clínicas
|
||||||
|
-- ============================================================================
|
||||||
|
-- NOTA: Ejecutar después de SET app.current_tenant_id = 'UUID-DEL-TENANT';
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Tratamientos dentales
|
||||||
|
INSERT INTO dental.tratamientos_catalogo (tenant_id, codigo, nombre, categoria, duracion_minutos, precio_base, requiere_rx, requiere_anestesia)
|
||||||
|
SELECT current_setting('app.current_tenant_id', true)::UUID, codigo, nombre, categoria, duracion, precio, rx, anestesia
|
||||||
|
FROM (VALUES
|
||||||
|
-- Prevención
|
||||||
|
('PREV-001', 'Limpieza dental básica', 'prevencion', 45, 600.00, false, false),
|
||||||
|
('PREV-002', 'Limpieza dental profunda', 'prevencion', 60, 1200.00, false, true),
|
||||||
|
('PREV-003', 'Aplicación de flúor', 'prevencion', 15, 300.00, false, false),
|
||||||
|
('PREV-004', 'Sellador de fosetas', 'prevencion', 20, 400.00, false, false),
|
||||||
|
-- Restauración
|
||||||
|
('REST-001', 'Resina simple (1 cara)', 'restauracion', 30, 800.00, true, true),
|
||||||
|
('REST-002', 'Resina compuesta (2 caras)', 'restauracion', 45, 1000.00, true, true),
|
||||||
|
('REST-003', 'Resina compleja (3+ caras)', 'restauracion', 60, 1300.00, true, true),
|
||||||
|
('REST-004', 'Incrustación de resina', 'restauracion', 90, 2500.00, true, true),
|
||||||
|
('REST-005', 'Incrustación de porcelana', 'restauracion', 90, 4000.00, true, true),
|
||||||
|
-- Endodoncia
|
||||||
|
('ENDO-001', 'Endodoncia unirradicular', 'endodoncia', 60, 3000.00, true, true),
|
||||||
|
('ENDO-002', 'Endodoncia birradicular', 'endodoncia', 90, 4000.00, true, true),
|
||||||
|
('ENDO-003', 'Endodoncia multirradicular', 'endodoncia', 120, 5000.00, true, true),
|
||||||
|
('ENDO-004', 'Retratamiento endodóntico', 'endodoncia', 120, 5500.00, true, true),
|
||||||
|
-- Periodoncia
|
||||||
|
('PERIO-001', 'Raspado y alisado radicular (cuadrante)', 'periodoncia', 60, 1500.00, true, true),
|
||||||
|
('PERIO-002', 'Cirugía periodontal', 'periodoncia', 120, 6000.00, true, true),
|
||||||
|
-- Cirugía
|
||||||
|
('CIRUG-001', 'Extracción simple', 'cirugia', 30, 800.00, true, true),
|
||||||
|
('CIRUG-002', 'Extracción de tercer molar', 'cirugia', 60, 3500.00, true, true),
|
||||||
|
('CIRUG-003', 'Extracción quirúrgica compleja', 'cirugia', 90, 5000.00, true, true),
|
||||||
|
-- Prótesis
|
||||||
|
('PROT-001', 'Corona de porcelana', 'protesis', 60, 6000.00, true, true),
|
||||||
|
('PROT-002', 'Corona de zirconia', 'protesis', 60, 8000.00, true, true),
|
||||||
|
('PROT-003', 'Puente fijo (3 unidades)', 'protesis', 120, 18000.00, true, true),
|
||||||
|
('PROT-004', 'Prótesis parcial removible', 'protesis', 120, 8000.00, true, false),
|
||||||
|
('PROT-005', 'Prótesis total', 'protesis', 180, 12000.00, true, false),
|
||||||
|
-- Implantes
|
||||||
|
('IMPL-001', 'Implante dental (sin corona)', 'implantes', 90, 15000.00, true, true),
|
||||||
|
('IMPL-002', 'Corona sobre implante', 'implantes', 60, 8000.00, false, false),
|
||||||
|
-- Ortodoncia
|
||||||
|
('ORTO-001', 'Brackets metálicos (tratamiento completo)', 'ortodoncia', 60, 35000.00, true, false),
|
||||||
|
('ORTO-002', 'Brackets estéticos (tratamiento completo)', 'ortodoncia', 60, 45000.00, true, false),
|
||||||
|
('ORTO-003', 'Alineadores invisibles', 'ortodoncia', 45, 60000.00, true, false),
|
||||||
|
('ORTO-004', 'Control mensual ortodoncia', 'ortodoncia', 30, 800.00, false, false),
|
||||||
|
('ORTO-005', 'Retenedor fijo', 'ortodoncia', 45, 3000.00, false, false),
|
||||||
|
-- Estética
|
||||||
|
('ESTE-001', 'Blanqueamiento en consultorio', 'estetica', 90, 5000.00, false, false),
|
||||||
|
('ESTE-002', 'Blanqueamiento casero', 'estetica', 30, 3000.00, false, false),
|
||||||
|
('ESTE-003', 'Carilla de resina', 'estetica', 60, 3500.00, false, false),
|
||||||
|
('ESTE-004', 'Carilla de porcelana', 'estetica', 60, 8000.00, false, false),
|
||||||
|
-- Diagnóstico
|
||||||
|
('DIAG-001', 'Radiografía periapical', 'diagnostico', 5, 100.00, false, false),
|
||||||
|
('DIAG-002', 'Radiografía panorámica', 'diagnostico', 10, 500.00, false, false),
|
||||||
|
('DIAG-003', 'Radiografía cefalométrica', 'diagnostico', 10, 400.00, false, false),
|
||||||
|
('DIAG-004', 'Tomografía dental', 'diagnostico', 15, 1500.00, false, false)
|
||||||
|
) AS t(codigo, nombre, categoria, duracion, precio, rx, anestesia)
|
||||||
|
WHERE current_setting('app.current_tenant_id', true) IS NOT NULL
|
||||||
|
AND current_setting('app.current_tenant_id', true) != ''
|
||||||
|
ON CONFLICT (tenant_id, codigo) DO NOTHING;
|
||||||
|
|
||||||
|
-- Skills específicos dentales
|
||||||
|
INSERT INTO hr.skills (tenant_id, skill_type_id, name, requiere_cedula)
|
||||||
|
SELECT
|
||||||
|
current_setting('app.current_tenant_id', true)::UUID,
|
||||||
|
st.id,
|
||||||
|
unnest(ARRAY[
|
||||||
|
'Odontología General',
|
||||||
|
'Ortodoncia',
|
||||||
|
'Endodoncia',
|
||||||
|
'Periodoncia',
|
||||||
|
'Cirugía Maxilofacial',
|
||||||
|
'Odontopediatría',
|
||||||
|
'Prostodoncia',
|
||||||
|
'Implantología',
|
||||||
|
'Estética Dental',
|
||||||
|
'Rehabilitación Oral'
|
||||||
|
]),
|
||||||
|
true
|
||||||
|
FROM hr.skill_types st
|
||||||
|
WHERE st.name = 'Especialidad Médica'
|
||||||
|
AND st.tenant_id = current_setting('app.current_tenant_id', true)::UUID
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
-- Ubicaciones (unidades dentales)
|
||||||
|
INSERT INTO hr.work_locations (tenant_id, name, tipo_consultorio, capacidad, equipamiento)
|
||||||
|
SELECT current_setting('app.current_tenant_id', true)::UUID, name, tipo, capacidad, equipamiento::TEXT[]
|
||||||
|
FROM (VALUES
|
||||||
|
('Unidad Dental 1', 'especialidad', 1, ARRAY['sillon', 'rayos_x', 'ultrasonido']),
|
||||||
|
('Unidad Dental 2', 'especialidad', 1, ARRAY['sillon', 'rayos_x', 'ultrasonido']),
|
||||||
|
('Unidad Dental 3', 'especialidad', 1, ARRAY['sillon', 'rayos_x']),
|
||||||
|
('Quirófano Dental', 'quirofano', 1, ARRAY['sillon', 'rayos_x', 'equipo_cirugia']),
|
||||||
|
('Sala de Rayos X', 'laboratorio', 2, ARRAY['panoramico', 'cefalometrico']),
|
||||||
|
('Laboratorio Dental', 'laboratorio', 2, ARRAY['modelos', 'protesis'])
|
||||||
|
) AS t(name, tipo, capacidad, equipamiento)
|
||||||
|
WHERE current_setting('app.current_tenant_id', true) IS NOT NULL
|
||||||
|
AND current_setting('app.current_tenant_id', true) != ''
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
Loading…
Reference in New Issue
Block a user