Implementar sistema completo de trazabilidad de lotes
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s
- Agregar PostgreSQL 16 con esquema completo - Crear API endpoints para lotes y operaciones - Implementar UI con Nuxt UI (tablas, formularios, trazabilidad) - Agregar datos de ejemplo del flujo completo - Documentar sistema en PLAN_TRAZABILIDAD.md
This commit is contained in:
225
nuxt4/server/database/01_schema.sql
Normal file
225
nuxt4/server/database/01_schema.sql
Normal file
@@ -0,0 +1,225 @@
|
||||
-- =====================================================
|
||||
-- SISTEMA DE TRAZABILIDAD DE LOTES - ESQUEMA PRINCIPAL
|
||||
-- =====================================================
|
||||
-- Este esquema implementa un modelo de grafo para trazabilidad
|
||||
-- de café desde ingreso de uva hasta secado final.
|
||||
-- Permite rastrear divisiones, combinaciones y transformaciones.
|
||||
|
||||
-- Extensiones necesarias
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- =====================================================
|
||||
-- TABLA: lotes
|
||||
-- =====================================================
|
||||
-- Representa cualquier estado físico del café en un momento dado.
|
||||
-- Ejemplos: uva ingresada, café despulpado, café oreado, café secado, etc.
|
||||
|
||||
CREATE TABLE lotes (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
codigo TEXT UNIQUE, -- Código legible: UVA-001, SEC-042, etc.
|
||||
tipo TEXT NOT NULL, -- uva, despulpado_primera, despulpado_segunda, despulpado_rechazos, oreado, presecado, reposo, secado
|
||||
fecha_creado TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
lugar_id INTEGER, -- Referencia opcional a lugares (patio 1, pila 2, etc.)
|
||||
cantidad_kg NUMERIC(10,2), -- Cantidad en kilogramos
|
||||
meta JSONB, -- Información adicional (humedad, notas, etc.)
|
||||
|
||||
CONSTRAINT lotes_cantidad_positiva CHECK (cantidad_kg IS NULL OR cantidad_kg >= 0),
|
||||
CONSTRAINT lotes_tipo_valido CHECK (tipo IN (
|
||||
'uva',
|
||||
'despulpado_primera',
|
||||
'despulpado_segunda',
|
||||
'despulpado_rechazos',
|
||||
'oreado',
|
||||
'presecado',
|
||||
'reposo',
|
||||
'secado'
|
||||
))
|
||||
);
|
||||
|
||||
-- Índices para búsquedas frecuentes
|
||||
CREATE INDEX idx_lotes_tipo ON lotes(tipo);
|
||||
CREATE INDEX idx_lotes_fecha_creado ON lotes(fecha_creado DESC);
|
||||
CREATE INDEX idx_lotes_codigo ON lotes(codigo) WHERE codigo IS NOT NULL;
|
||||
|
||||
-- Comentarios
|
||||
COMMENT ON TABLE lotes IS 'Representa cualquier estado físico del café en un momento dado';
|
||||
COMMENT ON COLUMN lotes.codigo IS 'Código legible opcional para identificar el lote (ej: UVA-001, SEC-042)';
|
||||
COMMENT ON COLUMN lotes.tipo IS 'Tipo de lote: uva, despulpado_*, oreado, presecado, reposo, secado';
|
||||
COMMENT ON COLUMN lotes.meta IS 'Datos adicionales en formato JSON (ej: {humedad: 12.5, notas: "café especial"})';
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- TABLA: operaciones
|
||||
-- =====================================================
|
||||
-- Representa un evento donde lotes se transforman, combinan o dividen.
|
||||
-- Ejemplos: ingreso de uva, despulpado, oreado, ajuste de merma, etc.
|
||||
|
||||
CREATE TABLE operaciones (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
tipo TEXT NOT NULL, -- Tipo de operación
|
||||
fecha TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
lugar_id INTEGER, -- Referencia opcional a lugares
|
||||
meta JSONB, -- Información adicional específica del tipo
|
||||
|
||||
CONSTRAINT operaciones_tipo_valido CHECK (tipo IN (
|
||||
-- Operaciones de proceso normal
|
||||
'ingreso',
|
||||
'despulpado',
|
||||
'oreado',
|
||||
'presecado',
|
||||
'reposo',
|
||||
'secado',
|
||||
'traslado',
|
||||
'mezcla',
|
||||
-- Operaciones de ajuste/corrección
|
||||
'ajuste_merma',
|
||||
'ajuste_cantidad',
|
||||
'ajuste_tipo',
|
||||
'correccion_asignacion',
|
||||
'fusion_manual',
|
||||
'division_manual'
|
||||
))
|
||||
);
|
||||
|
||||
-- Índices para búsquedas frecuentes
|
||||
CREATE INDEX idx_operaciones_tipo ON operaciones(tipo);
|
||||
CREATE INDEX idx_operaciones_fecha ON operaciones(fecha DESC);
|
||||
|
||||
-- Comentarios
|
||||
COMMENT ON TABLE operaciones IS 'Eventos donde lotes se transforman, combinan o dividen';
|
||||
COMMENT ON COLUMN operaciones.tipo IS 'Tipo de operación: ingreso, despulpado, oreado, ajuste_merma, etc.';
|
||||
COMMENT ON COLUMN operaciones.meta IS 'Datos adicionales específicos del tipo de operación en formato JSON';
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- TABLA: operacion_lotes
|
||||
-- =====================================================
|
||||
-- Relación muchos a muchos entre operaciones y lotes.
|
||||
-- Define qué lotes entran (input) y salen (output) de cada operación.
|
||||
|
||||
CREATE TABLE operacion_lotes (
|
||||
operacion_id UUID NOT NULL REFERENCES operaciones(id) ON DELETE CASCADE,
|
||||
lote_id UUID NOT NULL REFERENCES lotes(id) ON DELETE CASCADE,
|
||||
rol TEXT NOT NULL, -- 'input' o 'output'
|
||||
cantidad_kg NUMERIC(10,2), -- Cantidad específica usada/producida
|
||||
|
||||
PRIMARY KEY (operacion_id, lote_id, rol),
|
||||
|
||||
CONSTRAINT operacion_lotes_rol_valido CHECK (rol IN ('input', 'output')),
|
||||
CONSTRAINT operacion_lotes_cantidad_positiva CHECK (cantidad_kg IS NULL OR cantidad_kg > 0)
|
||||
);
|
||||
|
||||
-- Índices para navegación del grafo
|
||||
CREATE INDEX idx_operacion_lotes_operacion ON operacion_lotes(operacion_id);
|
||||
CREATE INDEX idx_operacion_lotes_lote ON operacion_lotes(lote_id);
|
||||
CREATE INDEX idx_operacion_lotes_rol ON operacion_lotes(rol);
|
||||
|
||||
-- Comentarios
|
||||
COMMENT ON TABLE operacion_lotes IS 'Define qué lotes entran y salen de cada operación (grafo de trazabilidad)';
|
||||
COMMENT ON COLUMN operacion_lotes.rol IS 'input: lote usado en la operación | output: lote producido por la operación';
|
||||
COMMENT ON COLUMN operacion_lotes.cantidad_kg IS 'Cantidad en kg que participó en esta relación específica';
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- FUNCIÓN: get_trazabilidad
|
||||
-- =====================================================
|
||||
-- Obtiene el historial completo de un lote caminando el grafo hacia atrás.
|
||||
-- Retorna todos los lotes ancestros hasta llegar a los ingresos iniciales.
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_trazabilidad(lote_id_inicial UUID)
|
||||
RETURNS TABLE (
|
||||
lote_id UUID,
|
||||
codigo TEXT,
|
||||
tipo TEXT,
|
||||
cantidad_kg NUMERIC,
|
||||
operacion_id UUID,
|
||||
operacion_tipo TEXT,
|
||||
profundidad INTEGER
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
WITH RECURSIVE trazabilidad AS (
|
||||
-- Punto de partida: el lote final
|
||||
SELECT
|
||||
l.id AS lote_id,
|
||||
l.codigo,
|
||||
l.tipo,
|
||||
l.cantidad_kg,
|
||||
ol.operacion_id,
|
||||
o.tipo AS operacion_tipo,
|
||||
0 AS profundidad
|
||||
FROM lotes l
|
||||
LEFT JOIN operacion_lotes ol ON ol.lote_id = l.id AND ol.rol = 'output'
|
||||
LEFT JOIN operaciones o ON o.id = ol.operacion_id
|
||||
WHERE l.id = lote_id_inicial
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Caminar hacia atrás: buscar lotes que fueron inputs
|
||||
SELECT
|
||||
l2.id AS lote_id,
|
||||
l2.codigo,
|
||||
l2.tipo,
|
||||
l2.cantidad_kg,
|
||||
ol2.operacion_id,
|
||||
o2.tipo AS operacion_tipo,
|
||||
t.profundidad + 1
|
||||
FROM trazabilidad t
|
||||
JOIN operacion_lotes ol_in
|
||||
ON ol_in.operacion_id = t.operacion_id
|
||||
AND ol_in.rol = 'input'
|
||||
JOIN lotes l2
|
||||
ON l2.id = ol_in.lote_id
|
||||
LEFT JOIN operacion_lotes ol2
|
||||
ON ol2.lote_id = l2.id
|
||||
AND ol2.rol = 'output'
|
||||
LEFT JOIN operaciones o2
|
||||
ON o2.id = ol2.operacion_id
|
||||
WHERE t.operacion_id IS NOT NULL -- Solo continuar si hay operación
|
||||
)
|
||||
SELECT * FROM trazabilidad
|
||||
ORDER BY profundidad, tipo, codigo;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
COMMENT ON FUNCTION get_trazabilidad IS 'Obtiene el historial completo de un lote caminando el grafo hacia atrás';
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- VISTA: vista_lotes_con_origen
|
||||
-- =====================================================
|
||||
-- Vista útil que muestra cada lote con información de la operación que lo creó.
|
||||
|
||||
CREATE OR REPLACE VIEW vista_lotes_con_origen AS
|
||||
SELECT
|
||||
l.id,
|
||||
l.codigo,
|
||||
l.tipo,
|
||||
l.fecha_creado,
|
||||
l.cantidad_kg,
|
||||
l.meta,
|
||||
o.id AS operacion_id,
|
||||
o.tipo AS operacion_tipo,
|
||||
o.fecha AS operacion_fecha
|
||||
FROM lotes l
|
||||
LEFT JOIN operacion_lotes ol
|
||||
ON ol.lote_id = l.id
|
||||
AND ol.rol = 'output'
|
||||
LEFT JOIN operaciones o
|
||||
ON o.id = ol.operacion_id;
|
||||
|
||||
COMMENT ON VIEW vista_lotes_con_origen IS 'Muestra lotes con información de la operación que los creó';
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- MENSAJES DE ÉXITO
|
||||
-- =====================================================
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE '✓ Esquema de trazabilidad creado exitosamente';
|
||||
RAISE NOTICE ' - Tabla lotes creada';
|
||||
RAISE NOTICE ' - Tabla operaciones creada';
|
||||
RAISE NOTICE ' - Tabla operacion_lotes creada';
|
||||
RAISE NOTICE ' - Función get_trazabilidad() creada';
|
||||
RAISE NOTICE ' - Vista vista_lotes_con_origen creada';
|
||||
END $$;
|
||||
Reference in New Issue
Block a user