[MULTI-REPO] Convertir a estructura multi-repo con submodules -v2
- backend → clinica-veterinaria-backend-v2.git - database → clinica-veterinaria-database-v2.git - frontend → clinica-veterinaria-frontend-v2.git Estandarización arquitectura multi-repo Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e99d051743
commit
f5a37ca344
11
.gitmodules
vendored
Normal file
11
.gitmodules
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
[submodule "backend"]
|
||||
path = backend
|
||||
url = git@gitea-server:rckrdmrd/clinica-veterinaria-backend-v2.git
|
||||
|
||||
[submodule "database"]
|
||||
path = database
|
||||
url = git@gitea-server:rckrdmrd/clinica-veterinaria-database-v2.git
|
||||
|
||||
[submodule "frontend"]
|
||||
path = frontend
|
||||
url = git@gitea-server:rckrdmrd/clinica-veterinaria-frontend-v2.git
|
||||
1
backend
Submodule
1
backend
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 25d59cd031f9577af1a3e3fd7870887ca6db74be
|
||||
1
database
Submodule
1
database
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit afa4f1a6fcb4a12c8e1eed7112972a5323cdad6e
|
||||
@ -1,387 +0,0 @@
|
||||
-- ============================================================================
|
||||
-- VETERINARIA SCHEMA - Especialización de ERP-Clínicas
|
||||
-- Clínica Veterinaria
|
||||
-- ============================================================================
|
||||
-- Fecha: 2026-01-04
|
||||
-- Versión: 1.0
|
||||
-- Hereda de: erp-clinicas FASE-8
|
||||
-- ============================================================================
|
||||
|
||||
-- Schema
|
||||
CREATE SCHEMA IF NOT EXISTS veterinaria;
|
||||
|
||||
-- ============================================================================
|
||||
-- ENUMS
|
||||
-- ============================================================================
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE veterinaria.sexo_animal AS ENUM ('macho', 'hembra', 'desconocido');
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE veterinaria.estado_hospitalizacion AS ENUM (
|
||||
'ingresado', 'en_tratamiento', 'estable', 'critico', 'alta', 'fallecido'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
-- ============================================================================
|
||||
-- CATÁLOGOS
|
||||
-- ============================================================================
|
||||
|
||||
-- Especies
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.especies (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
nombre VARCHAR(50) NOT NULL,
|
||||
nombre_cientifico VARCHAR(100),
|
||||
descripcion TEXT,
|
||||
active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.especies IS 'Catálogo de especies animales';
|
||||
|
||||
-- Razas
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.razas (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
especie_id UUID NOT NULL REFERENCES veterinaria.especies(id) ON DELETE CASCADE,
|
||||
nombre VARCHAR(100) NOT NULL,
|
||||
descripcion TEXT,
|
||||
tamanio_promedio VARCHAR(20), -- 'pequeño', 'mediano', 'grande', 'gigante'
|
||||
peso_promedio_kg NUMERIC(5,2),
|
||||
active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.razas IS 'Catálogo de razas por especie';
|
||||
|
||||
-- Vacunas
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.vacunas (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
nombre VARCHAR(100) NOT NULL,
|
||||
descripcion TEXT,
|
||||
especie_id UUID REFERENCES veterinaria.especies(id),
|
||||
laboratorio VARCHAR(100),
|
||||
dosis_ml NUMERIC(5,2),
|
||||
intervalo_refuerzo_dias INTEGER,
|
||||
es_obligatoria BOOLEAN DEFAULT false,
|
||||
active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.vacunas IS 'Catálogo de vacunas veterinarias';
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLAS PRINCIPALES
|
||||
-- ============================================================================
|
||||
|
||||
-- Propietarios (dueños de mascotas)
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.propietarios (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
partner_id UUID, -- Referencia opcional a core.partners
|
||||
nombre VARCHAR(100) NOT NULL,
|
||||
apellidos VARCHAR(100),
|
||||
telefono VARCHAR(20),
|
||||
telefono_emergencia VARCHAR(20),
|
||||
email VARCHAR(100),
|
||||
direccion TEXT,
|
||||
rfc VARCHAR(13),
|
||||
-- Control
|
||||
active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.propietarios IS 'Propietarios/dueños de mascotas';
|
||||
|
||||
-- Mascotas (pacientes)
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.mascotas (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
propietario_id UUID NOT NULL REFERENCES veterinaria.propietarios(id),
|
||||
especie_id UUID NOT NULL REFERENCES veterinaria.especies(id),
|
||||
raza_id UUID REFERENCES veterinaria.razas(id),
|
||||
-- Datos básicos
|
||||
nombre VARCHAR(100) NOT NULL,
|
||||
sexo veterinaria.sexo_animal DEFAULT 'desconocido',
|
||||
fecha_nacimiento DATE,
|
||||
edad_aproximada VARCHAR(50), -- "3 años", "6 meses"
|
||||
color VARCHAR(50),
|
||||
peso_kg NUMERIC(6,2),
|
||||
-- Identificación
|
||||
numero_chip VARCHAR(50),
|
||||
tiene_chip BOOLEAN DEFAULT false,
|
||||
-- Estado
|
||||
esterilizado BOOLEAN DEFAULT false,
|
||||
fecha_esterilizacion DATE,
|
||||
-- Notas
|
||||
alergias TEXT,
|
||||
condiciones_especiales TEXT,
|
||||
notas TEXT,
|
||||
-- Foto
|
||||
foto_url VARCHAR(255),
|
||||
-- Control
|
||||
active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.mascotas IS 'Mascotas/pacientes de la clínica veterinaria';
|
||||
|
||||
-- Cartilla de vacunación
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.cartilla_vacunacion (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
mascota_id UUID NOT NULL REFERENCES veterinaria.mascotas(id) ON DELETE CASCADE,
|
||||
vacuna_id UUID NOT NULL REFERENCES veterinaria.vacunas(id),
|
||||
veterinario_id UUID, -- Referencia a clinica.doctors
|
||||
-- Datos de aplicación
|
||||
fecha_aplicacion DATE NOT NULL,
|
||||
fecha_proximo_refuerzo DATE,
|
||||
lote VARCHAR(50),
|
||||
laboratorio VARCHAR(100),
|
||||
-- Notas
|
||||
observaciones TEXT,
|
||||
-- Control
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.cartilla_vacunacion IS 'Historial de vacunación de mascotas';
|
||||
|
||||
-- Desparasitaciones
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.desparasitaciones (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
mascota_id UUID NOT NULL REFERENCES veterinaria.mascotas(id) ON DELETE CASCADE,
|
||||
veterinario_id UUID,
|
||||
-- Datos
|
||||
tipo VARCHAR(50) NOT NULL, -- 'interna', 'externa', 'ambas'
|
||||
producto VARCHAR(100) NOT NULL,
|
||||
dosis VARCHAR(50),
|
||||
via_administracion VARCHAR(50),
|
||||
fecha_aplicacion DATE NOT NULL,
|
||||
fecha_proxima DATE,
|
||||
-- Notas
|
||||
observaciones TEXT,
|
||||
-- Control
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.desparasitaciones IS 'Historial de desparasitaciones';
|
||||
|
||||
-- Hospitalización
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.hospitalizacion (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
mascota_id UUID NOT NULL REFERENCES veterinaria.mascotas(id),
|
||||
veterinario_id UUID,
|
||||
consultation_id UUID, -- Referencia a clinica.consultations
|
||||
-- Datos de ingreso
|
||||
fecha_ingreso TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
motivo_ingreso TEXT NOT NULL,
|
||||
diagnostico_ingreso TEXT,
|
||||
-- Ubicación
|
||||
area VARCHAR(50), -- 'jaula_pequena', 'jaula_grande', 'quirofano', 'uci'
|
||||
numero_jaula VARCHAR(20),
|
||||
-- Estado
|
||||
estado veterinaria.estado_hospitalizacion DEFAULT 'ingresado',
|
||||
-- Alta
|
||||
fecha_alta TIMESTAMPTZ,
|
||||
diagnostico_alta TEXT,
|
||||
instrucciones_alta TEXT,
|
||||
-- Control
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.hospitalizacion IS 'Registro de hospitalizaciones';
|
||||
|
||||
-- Monitoreo de hospitalización
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.hospitalizacion_monitoreo (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
hospitalizacion_id UUID NOT NULL REFERENCES veterinaria.hospitalizacion(id) ON DELETE CASCADE,
|
||||
-- Signos vitales
|
||||
fecha_hora TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
peso_kg NUMERIC(6,2),
|
||||
temperatura NUMERIC(4,1),
|
||||
frecuencia_cardiaca INTEGER,
|
||||
frecuencia_respiratoria INTEGER,
|
||||
-- Alimentación
|
||||
comio BOOLEAN,
|
||||
bebio_agua BOOLEAN,
|
||||
-- Eliminación
|
||||
orino BOOLEAN,
|
||||
defeco BOOLEAN,
|
||||
consistencia_heces VARCHAR(50),
|
||||
-- Estado
|
||||
estado_animo VARCHAR(50),
|
||||
nivel_dolor INTEGER CHECK (nivel_dolor BETWEEN 0 AND 10),
|
||||
-- Notas
|
||||
observaciones TEXT,
|
||||
registrado_por UUID, -- employee_id
|
||||
-- Control
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.hospitalizacion_monitoreo IS 'Monitoreo durante hospitalización';
|
||||
|
||||
-- Servicios de estética
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.estetica (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
mascota_id UUID NOT NULL REFERENCES veterinaria.mascotas(id),
|
||||
estilista_id UUID, -- employee_id
|
||||
-- Servicios
|
||||
fecha_servicio TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
servicios TEXT[], -- ['baño', 'corte', 'limpieza_oidos', 'corte_unas']
|
||||
tipo_corte VARCHAR(50),
|
||||
shampoo_usado VARCHAR(100),
|
||||
-- Estado
|
||||
estado VARCHAR(20) DEFAULT 'pendiente', -- 'pendiente', 'en_proceso', 'terminado'
|
||||
hora_inicio TIME,
|
||||
hora_fin TIME,
|
||||
-- Notas
|
||||
observaciones TEXT,
|
||||
observaciones_piel TEXT,
|
||||
-- Precio
|
||||
precio NUMERIC(10,2),
|
||||
-- Control
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.estetica IS 'Servicios de estética/grooming';
|
||||
|
||||
-- ============================================================================
|
||||
-- EXTENSIONES A TABLAS DE ERP-CLINICAS
|
||||
-- ============================================================================
|
||||
|
||||
-- Extensión a clinica.consultations (si existe)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'clinica' AND table_name = 'consultations') THEN
|
||||
|
||||
-- mascota_id
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'clinica' AND table_name = 'consultations'
|
||||
AND column_name = 'mascota_id') THEN
|
||||
ALTER TABLE clinica.consultations ADD COLUMN mascota_id UUID
|
||||
REFERENCES veterinaria.mascotas(id);
|
||||
END IF;
|
||||
|
||||
-- peso_actual
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'clinica' AND table_name = 'consultations'
|
||||
AND column_name = 'peso_actual') THEN
|
||||
ALTER TABLE clinica.consultations ADD COLUMN peso_actual NUMERIC(6,2);
|
||||
END IF;
|
||||
|
||||
-- temperatura
|
||||
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
|
||||
WHERE table_schema = 'clinica' AND table_name = 'consultations'
|
||||
AND column_name = 'temperatura') THEN
|
||||
ALTER TABLE clinica.consultations ADD COLUMN temperatura NUMERIC(4,1);
|
||||
END IF;
|
||||
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ============================================================================
|
||||
-- ÍNDICES
|
||||
-- ============================================================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_especies_tenant ON veterinaria.especies(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_razas_tenant ON veterinaria.razas(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_razas_especie ON veterinaria.razas(especie_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_vacunas_tenant ON veterinaria.vacunas(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_vacunas_especie ON veterinaria.vacunas(especie_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_propietarios_tenant ON veterinaria.propietarios(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_propietarios_telefono ON veterinaria.propietarios(telefono);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_mascotas_tenant ON veterinaria.mascotas(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_mascotas_propietario ON veterinaria.mascotas(propietario_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_mascotas_especie ON veterinaria.mascotas(especie_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_mascotas_chip ON veterinaria.mascotas(numero_chip) WHERE numero_chip IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_cartilla_tenant ON veterinaria.cartilla_vacunacion(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cartilla_mascota ON veterinaria.cartilla_vacunacion(mascota_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cartilla_fecha ON veterinaria.cartilla_vacunacion(fecha_proximo_refuerzo);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_desparasitaciones_tenant ON veterinaria.desparasitaciones(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_desparasitaciones_mascota ON veterinaria.desparasitaciones(mascota_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_hospitalizacion_tenant ON veterinaria.hospitalizacion(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hospitalizacion_mascota ON veterinaria.hospitalizacion(mascota_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hospitalizacion_estado ON veterinaria.hospitalizacion(tenant_id, estado);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_hospitalizacion_monitoreo_hosp ON veterinaria.hospitalizacion_monitoreo(hospitalizacion_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_estetica_tenant ON veterinaria.estetica(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_estetica_mascota ON veterinaria.estetica(mascota_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_estetica_fecha ON veterinaria.estetica(fecha_servicio);
|
||||
|
||||
-- ============================================================================
|
||||
-- RLS
|
||||
-- ============================================================================
|
||||
|
||||
ALTER TABLE veterinaria.especies ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.razas ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.vacunas ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.propietarios ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.mascotas ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.cartilla_vacunacion ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.desparasitaciones ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.hospitalizacion ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.hospitalizacion_monitoreo ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.estetica ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_especies ON veterinaria.especies;
|
||||
CREATE POLICY tenant_isolation_especies ON veterinaria.especies
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_razas ON veterinaria.razas;
|
||||
CREATE POLICY tenant_isolation_razas ON veterinaria.razas
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_vacunas ON veterinaria.vacunas;
|
||||
CREATE POLICY tenant_isolation_vacunas ON veterinaria.vacunas
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_propietarios ON veterinaria.propietarios;
|
||||
CREATE POLICY tenant_isolation_propietarios ON veterinaria.propietarios
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_mascotas ON veterinaria.mascotas;
|
||||
CREATE POLICY tenant_isolation_mascotas ON veterinaria.mascotas
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_cartilla ON veterinaria.cartilla_vacunacion;
|
||||
CREATE POLICY tenant_isolation_cartilla ON veterinaria.cartilla_vacunacion
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_desparasitaciones ON veterinaria.desparasitaciones;
|
||||
CREATE POLICY tenant_isolation_desparasitaciones ON veterinaria.desparasitaciones
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_hospitalizacion ON veterinaria.hospitalizacion;
|
||||
CREATE POLICY tenant_isolation_hospitalizacion ON veterinaria.hospitalizacion
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_hosp_monitoreo ON veterinaria.hospitalizacion_monitoreo;
|
||||
CREATE POLICY tenant_isolation_hosp_monitoreo ON veterinaria.hospitalizacion_monitoreo
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_estetica ON veterinaria.estetica;
|
||||
CREATE POLICY tenant_isolation_estetica ON veterinaria.estetica
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
-- ============================================================================
|
||||
-- FIN VETERINARIA SCHEMA
|
||||
-- ============================================================================
|
||||
@ -1,464 +0,0 @@
|
||||
-- ============================================================================
|
||||
-- VETERINARIA SCHEMA - Farmacia (VET-006)
|
||||
-- Sistema de gestion de farmacia veterinaria
|
||||
-- ============================================================================
|
||||
-- Fecha: 2026-01-07
|
||||
-- Version: 1.0
|
||||
-- Basado en: VET-006-farmacia.md
|
||||
-- ============================================================================
|
||||
|
||||
-- ============================================================================
|
||||
-- ENUMS
|
||||
-- ============================================================================
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE veterinaria.categoria_medicamento AS ENUM (
|
||||
'antibiotico',
|
||||
'antiparasitario',
|
||||
'analgesico',
|
||||
'antiinflamatorio',
|
||||
'vacuna',
|
||||
'vitamina',
|
||||
'dermatologico',
|
||||
'oftalmico',
|
||||
'cardiaco',
|
||||
'digestivo',
|
||||
'otro'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE veterinaria.tipo_movimiento_farmacia AS ENUM (
|
||||
'entrada',
|
||||
'salida',
|
||||
'ajuste_positivo',
|
||||
'ajuste_negativo',
|
||||
'devolucion',
|
||||
'merma'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE veterinaria.fraccion_controlada AS ENUM (
|
||||
'no_controlado',
|
||||
'fraccion_i',
|
||||
'fraccion_ii',
|
||||
'fraccion_iii',
|
||||
'fraccion_iv'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
-- ============================================================================
|
||||
-- TABLAS PRINCIPALES
|
||||
-- ============================================================================
|
||||
|
||||
-- Catalogo de medicamentos
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.medicamentos (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
-- Identificacion
|
||||
codigo VARCHAR(50),
|
||||
nombre VARCHAR(150) NOT NULL,
|
||||
nombre_comercial VARCHAR(150),
|
||||
principio_activo VARCHAR(200),
|
||||
-- Clasificacion
|
||||
categoria veterinaria.categoria_medicamento DEFAULT 'otro',
|
||||
-- Presentacion
|
||||
presentacion VARCHAR(100), -- 'tabletas', 'inyectable', 'suspension', etc.
|
||||
concentracion VARCHAR(50), -- '500mg', '100mg/ml'
|
||||
contenido VARCHAR(50), -- '30 tabletas', '100ml'
|
||||
-- Fabricante
|
||||
laboratorio VARCHAR(100),
|
||||
-- Control
|
||||
requiere_receta BOOLEAN DEFAULT false,
|
||||
controlado BOOLEAN DEFAULT false,
|
||||
fraccion_controlada veterinaria.fraccion_controlada DEFAULT 'no_controlado',
|
||||
-- Stock
|
||||
stock_minimo INTEGER DEFAULT 10,
|
||||
stock_actual INTEGER DEFAULT 0,
|
||||
-- Precios
|
||||
precio_compra NUMERIC(10,2),
|
||||
precio_venta NUMERIC(10,2),
|
||||
-- Especies aplicables (NULL = todas)
|
||||
especies_aplicables UUID[], -- Array de especie_id
|
||||
-- Estado
|
||||
active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.medicamentos IS 'Catalogo de medicamentos veterinarios';
|
||||
|
||||
-- Lotes de medicamentos (control de caducidad)
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.medicamentos_lotes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
medicamento_id UUID NOT NULL REFERENCES veterinaria.medicamentos(id) ON DELETE CASCADE,
|
||||
-- Lote
|
||||
numero_lote VARCHAR(50) NOT NULL,
|
||||
fecha_caducidad DATE NOT NULL,
|
||||
-- Cantidades
|
||||
cantidad_inicial INTEGER NOT NULL,
|
||||
cantidad_actual INTEGER NOT NULL,
|
||||
-- Compra
|
||||
precio_compra NUMERIC(10,2),
|
||||
factura_compra VARCHAR(50),
|
||||
proveedor VARCHAR(100),
|
||||
fecha_recepcion DATE DEFAULT CURRENT_DATE,
|
||||
-- Estado
|
||||
bloqueado BOOLEAN DEFAULT false, -- Bloquear si esta vencido
|
||||
motivo_bloqueo TEXT,
|
||||
-- Control
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.medicamentos_lotes IS 'Lotes de medicamentos con control de caducidad';
|
||||
|
||||
-- Dispensaciones de medicamentos
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.dispensaciones (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
-- Referencias
|
||||
medicamento_id UUID NOT NULL REFERENCES veterinaria.medicamentos(id),
|
||||
lote_id UUID NOT NULL REFERENCES veterinaria.medicamentos_lotes(id),
|
||||
mascota_id UUID REFERENCES veterinaria.mascotas(id),
|
||||
veterinario_id UUID, -- Referencia a clinica.doctors
|
||||
receta_id UUID, -- Referencia a clinica.prescriptions si existe
|
||||
consultation_id UUID, -- Referencia a clinica.consultations
|
||||
-- Dispensacion
|
||||
cantidad INTEGER NOT NULL,
|
||||
fecha_dispensacion TIMESTAMPTZ DEFAULT NOW(),
|
||||
-- Instrucciones
|
||||
dosis VARCHAR(100), -- '1 tableta cada 8 horas'
|
||||
duracion_tratamiento VARCHAR(50), -- '7 dias'
|
||||
instrucciones TEXT,
|
||||
-- Control
|
||||
dispensado_por UUID, -- employee_id
|
||||
notas TEXT,
|
||||
-- Auditoria
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.dispensaciones IS 'Registro de dispensacion de medicamentos';
|
||||
|
||||
-- Movimientos de inventario (kardex)
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.movimientos_farmacia (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
medicamento_id UUID NOT NULL REFERENCES veterinaria.medicamentos(id),
|
||||
lote_id UUID REFERENCES veterinaria.medicamentos_lotes(id),
|
||||
-- Movimiento
|
||||
tipo veterinaria.tipo_movimiento_farmacia NOT NULL,
|
||||
cantidad INTEGER NOT NULL,
|
||||
stock_anterior INTEGER NOT NULL,
|
||||
stock_posterior INTEGER NOT NULL,
|
||||
-- Referencia
|
||||
referencia_tipo VARCHAR(50), -- 'dispensacion', 'compra', 'ajuste'
|
||||
referencia_id UUID,
|
||||
-- Detalles
|
||||
motivo TEXT,
|
||||
documento VARCHAR(100), -- Factura, nota, etc.
|
||||
-- Auditoria
|
||||
usuario_id UUID,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.movimientos_farmacia IS 'Kardex de movimientos de inventario de farmacia';
|
||||
|
||||
-- Bitacora de medicamentos controlados
|
||||
CREATE TABLE IF NOT EXISTS veterinaria.bitacora_controlados (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL,
|
||||
medicamento_id UUID NOT NULL REFERENCES veterinaria.medicamentos(id),
|
||||
lote_id UUID REFERENCES veterinaria.medicamentos_lotes(id),
|
||||
dispensacion_id UUID REFERENCES veterinaria.dispensaciones(id),
|
||||
-- Movimiento
|
||||
tipo_movimiento veterinaria.tipo_movimiento_farmacia NOT NULL,
|
||||
cantidad INTEGER NOT NULL,
|
||||
-- Paciente
|
||||
mascota_id UUID REFERENCES veterinaria.mascotas(id),
|
||||
propietario_nombre VARCHAR(200), -- Snapshot del nombre
|
||||
-- Prescripcion
|
||||
receta_id UUID,
|
||||
veterinario_id UUID,
|
||||
veterinario_cedula VARCHAR(50),
|
||||
-- Justificacion
|
||||
justificacion TEXT NOT NULL,
|
||||
diagnostico TEXT,
|
||||
-- Auditoria
|
||||
fecha_registro TIMESTAMPTZ DEFAULT NOW(),
|
||||
registrado_por UUID NOT NULL,
|
||||
ip_address VARCHAR(45),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE veterinaria.bitacora_controlados IS 'Bitacora de movimientos de medicamentos controlados (requerido por COFEPRIS)';
|
||||
|
||||
-- ============================================================================
|
||||
-- INDICES
|
||||
-- ============================================================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_medicamentos_tenant ON veterinaria.medicamentos(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_medicamentos_codigo ON veterinaria.medicamentos(tenant_id, codigo);
|
||||
CREATE INDEX IF NOT EXISTS idx_medicamentos_nombre ON veterinaria.medicamentos(tenant_id, nombre);
|
||||
CREATE INDEX IF NOT EXISTS idx_medicamentos_categoria ON veterinaria.medicamentos(tenant_id, categoria);
|
||||
CREATE INDEX IF NOT EXISTS idx_medicamentos_controlado ON veterinaria.medicamentos(tenant_id, controlado) WHERE controlado = true;
|
||||
CREATE INDEX IF NOT EXISTS idx_medicamentos_stock_bajo ON veterinaria.medicamentos(tenant_id)
|
||||
WHERE stock_actual <= stock_minimo;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_lotes_tenant ON veterinaria.medicamentos_lotes(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_lotes_medicamento ON veterinaria.medicamentos_lotes(medicamento_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_lotes_caducidad ON veterinaria.medicamentos_lotes(fecha_caducidad);
|
||||
CREATE INDEX IF NOT EXISTS idx_lotes_numero ON veterinaria.medicamentos_lotes(tenant_id, numero_lote);
|
||||
CREATE INDEX IF NOT EXISTS idx_lotes_proximos_caducar ON veterinaria.medicamentos_lotes(tenant_id, fecha_caducidad)
|
||||
WHERE cantidad_actual > 0 AND bloqueado = false;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_dispensaciones_tenant ON veterinaria.dispensaciones(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_dispensaciones_medicamento ON veterinaria.dispensaciones(medicamento_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_dispensaciones_mascota ON veterinaria.dispensaciones(mascota_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_dispensaciones_fecha ON veterinaria.dispensaciones(fecha_dispensacion);
|
||||
CREATE INDEX IF NOT EXISTS idx_dispensaciones_veterinario ON veterinaria.dispensaciones(veterinario_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_movimientos_tenant ON veterinaria.movimientos_farmacia(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_movimientos_medicamento ON veterinaria.movimientos_farmacia(medicamento_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_movimientos_fecha ON veterinaria.movimientos_farmacia(created_at);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_bitacora_tenant ON veterinaria.bitacora_controlados(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_bitacora_medicamento ON veterinaria.bitacora_controlados(medicamento_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_bitacora_fecha ON veterinaria.bitacora_controlados(fecha_registro);
|
||||
|
||||
-- ============================================================================
|
||||
-- RLS
|
||||
-- ============================================================================
|
||||
|
||||
ALTER TABLE veterinaria.medicamentos ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.medicamentos_lotes ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.dispensaciones ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.movimientos_farmacia ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE veterinaria.bitacora_controlados ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_medicamentos ON veterinaria.medicamentos;
|
||||
CREATE POLICY tenant_isolation_medicamentos ON veterinaria.medicamentos
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_lotes ON veterinaria.medicamentos_lotes;
|
||||
CREATE POLICY tenant_isolation_lotes ON veterinaria.medicamentos_lotes
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_dispensaciones ON veterinaria.dispensaciones;
|
||||
CREATE POLICY tenant_isolation_dispensaciones ON veterinaria.dispensaciones
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_movimientos ON veterinaria.movimientos_farmacia;
|
||||
CREATE POLICY tenant_isolation_movimientos ON veterinaria.movimientos_farmacia
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
DROP POLICY IF EXISTS tenant_isolation_bitacora ON veterinaria.bitacora_controlados;
|
||||
CREATE POLICY tenant_isolation_bitacora ON veterinaria.bitacora_controlados
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
-- ============================================================================
|
||||
-- TRIGGERS
|
||||
-- ============================================================================
|
||||
|
||||
-- Trigger para actualizar stock_actual en medicamentos
|
||||
CREATE OR REPLACE FUNCTION veterinaria.actualizar_stock_medicamento()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF TG_OP = 'INSERT' THEN
|
||||
-- Actualizar stock del medicamento
|
||||
UPDATE veterinaria.medicamentos
|
||||
SET stock_actual = stock_actual + NEW.cantidad_inicial,
|
||||
updated_at = NOW()
|
||||
WHERE id = NEW.medicamento_id;
|
||||
ELSIF TG_OP = 'UPDATE' THEN
|
||||
-- Si cambia cantidad_actual
|
||||
UPDATE veterinaria.medicamentos
|
||||
SET stock_actual = (
|
||||
SELECT COALESCE(SUM(cantidad_actual), 0)
|
||||
FROM veterinaria.medicamentos_lotes
|
||||
WHERE medicamento_id = NEW.medicamento_id
|
||||
AND bloqueado = false
|
||||
),
|
||||
updated_at = NOW()
|
||||
WHERE id = NEW.medicamento_id;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_actualizar_stock ON veterinaria.medicamentos_lotes;
|
||||
CREATE TRIGGER trg_actualizar_stock
|
||||
AFTER INSERT OR UPDATE OF cantidad_actual ON veterinaria.medicamentos_lotes
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION veterinaria.actualizar_stock_medicamento();
|
||||
|
||||
COMMENT ON FUNCTION veterinaria.actualizar_stock_medicamento() IS 'Actualiza stock_actual en medicamentos cuando cambian los lotes';
|
||||
|
||||
-- Trigger para registrar movimiento en dispensacion
|
||||
CREATE OR REPLACE FUNCTION veterinaria.registrar_movimiento_dispensacion()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
v_stock_anterior INTEGER;
|
||||
BEGIN
|
||||
-- Obtener stock anterior
|
||||
SELECT stock_actual INTO v_stock_anterior
|
||||
FROM veterinaria.medicamentos
|
||||
WHERE id = NEW.medicamento_id;
|
||||
|
||||
-- Descontar del lote
|
||||
UPDATE veterinaria.medicamentos_lotes
|
||||
SET cantidad_actual = cantidad_actual - NEW.cantidad,
|
||||
updated_at = NOW()
|
||||
WHERE id = NEW.lote_id;
|
||||
|
||||
-- Registrar movimiento
|
||||
INSERT INTO veterinaria.movimientos_farmacia (
|
||||
tenant_id, medicamento_id, lote_id,
|
||||
tipo, cantidad, stock_anterior, stock_posterior,
|
||||
referencia_tipo, referencia_id, usuario_id
|
||||
) VALUES (
|
||||
NEW.tenant_id, NEW.medicamento_id, NEW.lote_id,
|
||||
'salida', NEW.cantidad, v_stock_anterior, v_stock_anterior - NEW.cantidad,
|
||||
'dispensacion', NEW.id, NEW.dispensado_por
|
||||
);
|
||||
|
||||
-- Si es controlado, registrar en bitacora
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM veterinaria.medicamentos
|
||||
WHERE id = NEW.medicamento_id AND controlado = true
|
||||
) THEN
|
||||
INSERT INTO veterinaria.bitacora_controlados (
|
||||
tenant_id, medicamento_id, lote_id, dispensacion_id,
|
||||
tipo_movimiento, cantidad, mascota_id,
|
||||
propietario_nombre, receta_id, veterinario_id,
|
||||
justificacion, registrado_por
|
||||
)
|
||||
SELECT
|
||||
NEW.tenant_id, NEW.medicamento_id, NEW.lote_id, NEW.id,
|
||||
'salida', NEW.cantidad, NEW.mascota_id,
|
||||
CONCAT(p.nombre, ' ', COALESCE(p.apellidos, '')),
|
||||
NEW.receta_id, NEW.veterinario_id,
|
||||
COALESCE(NEW.notas, 'Dispensacion de medicamento'),
|
||||
NEW.dispensado_por
|
||||
FROM veterinaria.mascotas m
|
||||
JOIN veterinaria.propietarios p ON m.propietario_id = p.id
|
||||
WHERE m.id = NEW.mascota_id;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_registrar_dispensacion ON veterinaria.dispensaciones;
|
||||
CREATE TRIGGER trg_registrar_dispensacion
|
||||
AFTER INSERT ON veterinaria.dispensaciones
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION veterinaria.registrar_movimiento_dispensacion();
|
||||
|
||||
COMMENT ON FUNCTION veterinaria.registrar_movimiento_dispensacion() IS 'Registra movimiento y bitacora al dispensar medicamentos';
|
||||
|
||||
-- ============================================================================
|
||||
-- FUNCIONES DE CONSULTA
|
||||
-- ============================================================================
|
||||
|
||||
-- Funcion para obtener lotes proximos a caducar
|
||||
CREATE OR REPLACE FUNCTION veterinaria.get_lotes_proximos_caducar(
|
||||
p_tenant_id UUID,
|
||||
p_dias INTEGER DEFAULT 30
|
||||
)
|
||||
RETURNS TABLE (
|
||||
lote_id UUID,
|
||||
medicamento_id UUID,
|
||||
medicamento_nombre VARCHAR,
|
||||
numero_lote VARCHAR,
|
||||
fecha_caducidad DATE,
|
||||
dias_restantes INTEGER,
|
||||
cantidad_actual INTEGER
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
l.id AS lote_id,
|
||||
m.id AS medicamento_id,
|
||||
m.nombre AS medicamento_nombre,
|
||||
l.numero_lote,
|
||||
l.fecha_caducidad,
|
||||
(l.fecha_caducidad - CURRENT_DATE)::INTEGER AS dias_restantes,
|
||||
l.cantidad_actual
|
||||
FROM veterinaria.medicamentos_lotes l
|
||||
JOIN veterinaria.medicamentos m ON l.medicamento_id = m.id
|
||||
WHERE l.tenant_id = p_tenant_id
|
||||
AND l.cantidad_actual > 0
|
||||
AND l.bloqueado = false
|
||||
AND l.fecha_caducidad <= CURRENT_DATE + p_dias
|
||||
ORDER BY l.fecha_caducidad ASC;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION veterinaria.get_lotes_proximos_caducar(UUID, INTEGER) IS 'Obtiene lotes que caducaran en los proximos N dias';
|
||||
|
||||
-- Funcion para obtener medicamentos con stock bajo
|
||||
CREATE OR REPLACE FUNCTION veterinaria.get_medicamentos_stock_bajo(p_tenant_id UUID)
|
||||
RETURNS TABLE (
|
||||
medicamento_id UUID,
|
||||
codigo VARCHAR,
|
||||
nombre VARCHAR,
|
||||
stock_actual INTEGER,
|
||||
stock_minimo INTEGER,
|
||||
diferencia INTEGER
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
m.id AS medicamento_id,
|
||||
m.codigo,
|
||||
m.nombre,
|
||||
m.stock_actual,
|
||||
m.stock_minimo,
|
||||
(m.stock_minimo - m.stock_actual) AS diferencia
|
||||
FROM veterinaria.medicamentos m
|
||||
WHERE m.tenant_id = p_tenant_id
|
||||
AND m.active = true
|
||||
AND m.stock_actual <= m.stock_minimo
|
||||
ORDER BY diferencia DESC;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION veterinaria.get_medicamentos_stock_bajo(UUID) IS 'Obtiene medicamentos con stock igual o menor al minimo';
|
||||
|
||||
-- Funcion para seleccionar lote FEFO (First Expired, First Out)
|
||||
CREATE OR REPLACE FUNCTION veterinaria.seleccionar_lote_fefo(
|
||||
p_medicamento_id UUID,
|
||||
p_cantidad INTEGER
|
||||
)
|
||||
RETURNS UUID AS $$
|
||||
DECLARE
|
||||
v_lote_id UUID;
|
||||
BEGIN
|
||||
SELECT id INTO v_lote_id
|
||||
FROM veterinaria.medicamentos_lotes
|
||||
WHERE medicamento_id = p_medicamento_id
|
||||
AND cantidad_actual >= p_cantidad
|
||||
AND bloqueado = false
|
||||
AND fecha_caducidad > CURRENT_DATE
|
||||
ORDER BY fecha_caducidad ASC
|
||||
LIMIT 1;
|
||||
|
||||
IF v_lote_id IS NULL THEN
|
||||
RAISE EXCEPTION 'No hay lotes disponibles con stock suficiente para el medicamento %', p_medicamento_id;
|
||||
END IF;
|
||||
|
||||
RETURN v_lote_id;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION veterinaria.seleccionar_lote_fefo(UUID, INTEGER) IS 'Selecciona el lote con fecha de caducidad mas proxima (FEFO)';
|
||||
|
||||
-- ============================================================================
|
||||
-- FIN VETERINARIA FARMACIA SCHEMA
|
||||
-- ============================================================================
|
||||
@ -1,146 +0,0 @@
|
||||
-- ============================================================================
|
||||
-- SEED DATA: Catálogos de Veterinaria
|
||||
-- Especialización de ERP-Clínicas
|
||||
-- ============================================================================
|
||||
-- NOTA: Ejecutar después de SET app.current_tenant_id = 'UUID-DEL-TENANT';
|
||||
-- ============================================================================
|
||||
|
||||
-- Especies
|
||||
INSERT INTO veterinaria.especies (tenant_id, nombre, nombre_cientifico)
|
||||
SELECT current_setting('app.current_tenant_id', true)::UUID, nombre, nombre_cientifico
|
||||
FROM (VALUES
|
||||
('Perro', 'Canis lupus familiaris'),
|
||||
('Gato', 'Felis silvestris catus'),
|
||||
('Ave', NULL),
|
||||
('Reptil', NULL),
|
||||
('Roedor', NULL),
|
||||
('Conejo', 'Oryctolagus cuniculus'),
|
||||
('Pez', NULL),
|
||||
('Hurón', 'Mustela putorius furo'),
|
||||
('Otro', NULL)
|
||||
) AS t(nombre, nombre_cientifico)
|
||||
WHERE current_setting('app.current_tenant_id', true) IS NOT NULL
|
||||
AND current_setting('app.current_tenant_id', true) != ''
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Razas de perro
|
||||
INSERT INTO veterinaria.razas (tenant_id, especie_id, nombre, tamanio_promedio, peso_promedio_kg)
|
||||
SELECT
|
||||
current_setting('app.current_tenant_id', true)::UUID,
|
||||
e.id,
|
||||
r.nombre,
|
||||
r.tamanio,
|
||||
r.peso
|
||||
FROM veterinaria.especies e
|
||||
CROSS JOIN (VALUES
|
||||
('Mestizo', 'mediano', 15.0),
|
||||
('Chihuahua', 'pequeño', 2.5),
|
||||
('Poodle', 'pequeño', 5.0),
|
||||
('Bulldog Francés', 'pequeño', 12.0),
|
||||
('Beagle', 'mediano', 12.0),
|
||||
('Labrador Retriever', 'grande', 30.0),
|
||||
('Golden Retriever', 'grande', 32.0),
|
||||
('Pastor Alemán', 'grande', 35.0),
|
||||
('Rottweiler', 'grande', 45.0),
|
||||
('Husky Siberiano', 'grande', 25.0),
|
||||
('Pug', 'pequeño', 8.0),
|
||||
('Yorkshire Terrier', 'pequeño', 3.0),
|
||||
('Schnauzer', 'mediano', 7.0),
|
||||
('Boxer', 'grande', 30.0),
|
||||
('Pitbull', 'mediano', 25.0)
|
||||
) AS r(nombre, tamanio, peso)
|
||||
WHERE e.nombre = 'Perro'
|
||||
AND e.tenant_id = current_setting('app.current_tenant_id', true)::UUID
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Razas de gato
|
||||
INSERT INTO veterinaria.razas (tenant_id, especie_id, nombre, tamanio_promedio, peso_promedio_kg)
|
||||
SELECT
|
||||
current_setting('app.current_tenant_id', true)::UUID,
|
||||
e.id,
|
||||
r.nombre,
|
||||
r.tamanio,
|
||||
r.peso
|
||||
FROM veterinaria.especies e
|
||||
CROSS JOIN (VALUES
|
||||
('Mestizo', 'mediano', 4.0),
|
||||
('Siamés', 'mediano', 4.5),
|
||||
('Persa', 'mediano', 5.0),
|
||||
('Maine Coon', 'grande', 8.0),
|
||||
('Bengalí', 'mediano', 5.5),
|
||||
('Ragdoll', 'grande', 7.0),
|
||||
('British Shorthair', 'mediano', 6.0),
|
||||
('Angora', 'mediano', 4.5),
|
||||
('Sphynx', 'mediano', 4.0),
|
||||
('Abisinio', 'mediano', 4.0)
|
||||
) AS r(nombre, tamanio, peso)
|
||||
WHERE e.nombre = 'Gato'
|
||||
AND e.tenant_id = current_setting('app.current_tenant_id', true)::UUID
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Vacunas para perros
|
||||
INSERT INTO veterinaria.vacunas (tenant_id, especie_id, nombre, descripcion, intervalo_refuerzo_dias, es_obligatoria)
|
||||
SELECT
|
||||
current_setting('app.current_tenant_id', true)::UUID,
|
||||
e.id,
|
||||
v.nombre,
|
||||
v.descripcion,
|
||||
v.intervalo,
|
||||
v.obligatoria
|
||||
FROM veterinaria.especies e
|
||||
CROSS JOIN (VALUES
|
||||
('Parvovirus', 'Protege contra parvovirus canino', 365, false),
|
||||
('Moquillo', 'Protege contra distemper canino', 365, false),
|
||||
('Hepatitis', 'Protege contra hepatitis infecciosa canina', 365, false),
|
||||
('Rabia', 'Vacuna antirrábica - OBLIGATORIA', 365, true),
|
||||
('Leptospirosis', 'Protege contra leptospirosis', 365, false),
|
||||
('Bordetella', 'Protege contra tos de las perreras', 180, false),
|
||||
('Cuádruple', 'Moquillo, Hepatitis, Parvo, Parainfluenza', 365, false),
|
||||
('Séxtuple', 'Cuádruple + Coronavirus + Leptospira', 365, false)
|
||||
) AS v(nombre, descripcion, intervalo, obligatoria)
|
||||
WHERE e.nombre = 'Perro'
|
||||
AND e.tenant_id = current_setting('app.current_tenant_id', true)::UUID
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Vacunas para gatos
|
||||
INSERT INTO veterinaria.vacunas (tenant_id, especie_id, nombre, descripcion, intervalo_refuerzo_dias, es_obligatoria)
|
||||
SELECT
|
||||
current_setting('app.current_tenant_id', true)::UUID,
|
||||
e.id,
|
||||
v.nombre,
|
||||
v.descripcion,
|
||||
v.intervalo,
|
||||
v.obligatoria
|
||||
FROM veterinaria.especies e
|
||||
CROSS JOIN (VALUES
|
||||
('Triple Felina', 'Rinotraqueitis, Calicivirus, Panleucopenia', 365, false),
|
||||
('Leucemia Felina', 'Protege contra FeLV', 365, false),
|
||||
('Rabia', 'Vacuna antirrábica', 365, true),
|
||||
('PIF', 'Peritonitis Infecciosa Felina', 365, false)
|
||||
) AS v(nombre, descripcion, intervalo, obligatoria)
|
||||
WHERE e.nombre = 'Gato'
|
||||
AND e.tenant_id = current_setting('app.current_tenant_id', true)::UUID
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Skills específicos veterinarios
|
||||
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[
|
||||
'Medicina Veterinaria General',
|
||||
'Cirugía Veterinaria',
|
||||
'Dermatología Veterinaria',
|
||||
'Cardiología Veterinaria',
|
||||
'Oftalmología Veterinaria',
|
||||
'Ortopedia Veterinaria',
|
||||
'Oncología Veterinaria',
|
||||
'Medicina de Exóticos',
|
||||
'Anestesiología Veterinaria',
|
||||
'Imagenología Veterinaria'
|
||||
]),
|
||||
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;
|
||||
1
frontend
Submodule
1
frontend
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 35f98c825860ee86b4de996385f7f3d22e50e7cc
|
||||
Loading…
Reference in New Issue
Block a user