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:
385
nuxt4/server/database/02_seed.sql
Normal file
385
nuxt4/server/database/02_seed.sql
Normal file
@@ -0,0 +1,385 @@
|
||||
-- =====================================================
|
||||
-- DATOS DE EJEMPLO - FLUJO COMPLETO DE TRAZABILIDAD
|
||||
-- =====================================================
|
||||
-- Este script crea un ejemplo completo del flujo de café desde
|
||||
-- ingreso de uva hasta secado final, incluyendo ajustes y correcciones.
|
||||
--
|
||||
-- Flujo principal:
|
||||
-- Ingreso uva → Despulpado → Oreado → Ajuste merma → Ajuste tipo →
|
||||
-- Presecado → Reposo → Secado (mezcla con otro reposo)
|
||||
|
||||
-- Limpiar datos existentes (solo para demo/desarrollo)
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'Limpiando datos de ejemplo previos...';
|
||||
END $$;
|
||||
|
||||
TRUNCATE TABLE operacion_lotes, operaciones, lotes CASCADE;
|
||||
|
||||
-- =====================================================
|
||||
-- PASO 1: INGRESO DE UVA
|
||||
-- =====================================================
|
||||
-- Llega café uva de un productor
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
op_ingreso_id UUID;
|
||||
lote_uva_id UUID;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Creando ingreso de uva...';
|
||||
|
||||
-- Crear operación de ingreso
|
||||
INSERT INTO operaciones (tipo, fecha, meta)
|
||||
VALUES (
|
||||
'ingreso',
|
||||
NOW() - INTERVAL '10 days',
|
||||
'{"productor": "Finca El Roble", "lote_productor": "2024-11-A"}'::jsonb
|
||||
)
|
||||
RETURNING id INTO op_ingreso_id;
|
||||
|
||||
-- Crear lote de uva
|
||||
INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta)
|
||||
VALUES (
|
||||
'UVA-001',
|
||||
'uva',
|
||||
NOW() - INTERVAL '10 days',
|
||||
2086,
|
||||
'{"variedad": "Caturra", "procedencia": "Finca El Roble"}'::jsonb
|
||||
)
|
||||
RETURNING id INTO lote_uva_id;
|
||||
|
||||
-- Relacionar: operación de ingreso → lote de uva (output)
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES (op_ingreso_id, lote_uva_id, 'output', 2086);
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- PASO 2: DESPULPADO
|
||||
-- =====================================================
|
||||
-- Se despulpa la uva y se obtienen tres lotes: primera, segunda y rechazos
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
op_despulpado_id UUID;
|
||||
lote_uva_id UUID;
|
||||
lote_primera_id UUID;
|
||||
lote_segunda_id UUID;
|
||||
lote_rechazos_id UUID;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Creando despulpado...';
|
||||
|
||||
-- Obtener ID del lote de uva
|
||||
SELECT id INTO lote_uva_id FROM lotes WHERE codigo = 'UVA-001';
|
||||
|
||||
-- Crear operación de despulpado
|
||||
INSERT INTO operaciones (tipo, fecha, meta)
|
||||
VALUES (
|
||||
'despulpado',
|
||||
NOW() - INTERVAL '9 days',
|
||||
'{"pila": 2, "operador": "Juan Pérez"}'::jsonb
|
||||
)
|
||||
RETURNING id INTO op_despulpado_id;
|
||||
|
||||
-- Crear lotes de salida
|
||||
INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta)
|
||||
VALUES
|
||||
('PRIM-001', 'despulpado_primera', NOW() - INTERVAL '9 days', 1500, '{"calidad": "A"}'::jsonb),
|
||||
('SEG-001', 'despulpado_segunda', NOW() - INTERVAL '9 days', 400, '{"calidad": "B"}'::jsonb),
|
||||
('RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '9 days', 150, '{"destino": "compost"}'::jsonb)
|
||||
RETURNING id INTO lote_primera_id, lote_segunda_id, lote_rechazos_id;
|
||||
|
||||
-- Relacionar: uva → despulpado (input)
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES (op_despulpado_id, lote_uva_id, 'input', 2086);
|
||||
|
||||
-- Relacionar: despulpado → primera, segunda, rechazos (outputs)
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES
|
||||
(op_despulpado_id, lote_primera_id, 'output', 1500),
|
||||
(op_despulpado_id, lote_segunda_id, 'output', 400),
|
||||
(op_despulpado_id, lote_rechazos_id, 'output', 150);
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- PASO 3: OREADO (con error en registro)
|
||||
-- =====================================================
|
||||
-- Se orea el lote de primera calidad, pero se registra mal la cantidad
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
op_oreado_id UUID;
|
||||
lote_primera_id UUID;
|
||||
lote_oreado_id UUID;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Creando oreado (con error de registro)...';
|
||||
|
||||
-- Obtener ID del lote de primera
|
||||
SELECT id INTO lote_primera_id FROM lotes WHERE codigo = 'PRIM-001';
|
||||
|
||||
-- Crear operación de oreado
|
||||
INSERT INTO operaciones (tipo, fecha, meta)
|
||||
VALUES (
|
||||
'oreado',
|
||||
NOW() - INTERVAL '8 days',
|
||||
'{"patio": 1, "inicio": "06:00", "fin": "18:00"}'::jsonb
|
||||
)
|
||||
RETURNING id INTO op_oreado_id;
|
||||
|
||||
-- Crear lote oreado (cantidad mal registrada: debería ser menos por merma)
|
||||
INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta)
|
||||
VALUES (
|
||||
'ORE-001',
|
||||
'oreado',
|
||||
NOW() - INTERVAL '8 days',
|
||||
1500, -- Error: debería ser 1480 kg
|
||||
'{"humedad_inicial": 55, "humedad_final": 45}'::jsonb
|
||||
)
|
||||
RETURNING id INTO lote_oreado_id;
|
||||
|
||||
-- Relacionar
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES
|
||||
(op_oreado_id, lote_primera_id, 'input', 1500),
|
||||
(op_oreado_id, lote_oreado_id, 'output', 1500);
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- PASO 4: AJUSTE DE MERMA
|
||||
-- =====================================================
|
||||
-- Se corrige la cantidad: realmente hubo merma de 20 kg
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
op_ajuste_id UUID;
|
||||
lote_oreado_id UUID;
|
||||
lote_oreado_corr_id UUID;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Aplicando ajuste de merma...';
|
||||
|
||||
-- Obtener ID del lote oreado
|
||||
SELECT id INTO lote_oreado_id FROM lotes WHERE codigo = 'ORE-001';
|
||||
|
||||
-- Crear operación de ajuste
|
||||
INSERT INTO operaciones (tipo, fecha, meta)
|
||||
VALUES (
|
||||
'ajuste_merma',
|
||||
NOW() - INTERVAL '7 days',
|
||||
'{"motivo": "Corrección de pesaje", "merma_kg": 20}'::jsonb
|
||||
)
|
||||
RETURNING id INTO op_ajuste_id;
|
||||
|
||||
-- Crear lote corregido
|
||||
INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta)
|
||||
VALUES (
|
||||
'ORE-001A',
|
||||
'oreado',
|
||||
NOW() - INTERVAL '7 days',
|
||||
1480,
|
||||
'{"humedad": 45, "corregido": true}'::jsonb
|
||||
)
|
||||
RETURNING id INTO lote_oreado_corr_id;
|
||||
|
||||
-- Relacionar
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES
|
||||
(op_ajuste_id, lote_oreado_id, 'input', 1500),
|
||||
(op_ajuste_id, lote_oreado_corr_id, 'output', 1480);
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- PASO 5: AJUSTE DE TIPO
|
||||
-- =====================================================
|
||||
-- Se descubre que en realidad era presecado, no oreado
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
op_ajuste_tipo_id UUID;
|
||||
lote_oreado_corr_id UUID;
|
||||
lote_presecado_id UUID;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Aplicando ajuste de tipo...';
|
||||
|
||||
-- Obtener ID del lote oreado corregido
|
||||
SELECT id INTO lote_oreado_corr_id FROM lotes WHERE codigo = 'ORE-001A';
|
||||
|
||||
-- Crear operación de ajuste de tipo
|
||||
INSERT INTO operaciones (tipo, fecha, meta)
|
||||
VALUES (
|
||||
'ajuste_tipo',
|
||||
NOW() - INTERVAL '6 days',
|
||||
'{"motivo": "Revisión de proceso", "tipo_anterior": "oreado", "tipo_nuevo": "presecado"}'::jsonb
|
||||
)
|
||||
RETURNING id INTO op_ajuste_tipo_id;
|
||||
|
||||
-- Crear lote con tipo correcto
|
||||
INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta)
|
||||
VALUES (
|
||||
'PRE-001',
|
||||
'presecado',
|
||||
NOW() - INTERVAL '6 days',
|
||||
1480,
|
||||
'{"humedad": 45, "tipo_corregido": true}'::jsonb
|
||||
)
|
||||
RETURNING id INTO lote_presecado_id;
|
||||
|
||||
-- Relacionar
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES
|
||||
(op_ajuste_tipo_id, lote_oreado_corr_id, 'input', 1480),
|
||||
(op_ajuste_tipo_id, lote_presecado_id, 'output', 1480);
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- PASO 6: REPOSO
|
||||
-- =====================================================
|
||||
-- El presecado pasa a reposo
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
op_reposo_id UUID;
|
||||
lote_presecado_id UUID;
|
||||
lote_reposo_id UUID;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Creando reposo...';
|
||||
|
||||
-- Obtener ID del lote presecado
|
||||
SELECT id INTO lote_presecado_id FROM lotes WHERE codigo = 'PRE-001';
|
||||
|
||||
-- Crear operación de reposo
|
||||
INSERT INTO operaciones (tipo, fecha, meta)
|
||||
VALUES (
|
||||
'reposo',
|
||||
NOW() - INTERVAL '5 days',
|
||||
'{"area": "Bodega A", "dias_reposo": 3}'::jsonb
|
||||
)
|
||||
RETURNING id INTO op_reposo_id;
|
||||
|
||||
-- Crear lote en reposo
|
||||
INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta)
|
||||
VALUES (
|
||||
'REP-001',
|
||||
'reposo',
|
||||
NOW() - INTERVAL '5 days',
|
||||
1480,
|
||||
'{"humedad": 43}'::jsonb
|
||||
)
|
||||
RETURNING id INTO lote_reposo_id;
|
||||
|
||||
-- Relacionar
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES
|
||||
(op_reposo_id, lote_presecado_id, 'input', 1480),
|
||||
(op_reposo_id, lote_reposo_id, 'output', 1480);
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- PASO 7: SEGUNDO FLUJO (para mezclar en secado)
|
||||
-- =====================================================
|
||||
-- Crear otro lote de reposo de un proceso paralelo
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
lote_reposo2_id UUID;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Creando segundo lote de reposo (proceso paralelo)...';
|
||||
|
||||
-- Crear lote de reposo directamente (proceso simplificado)
|
||||
INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta)
|
||||
VALUES (
|
||||
'REP-002',
|
||||
'reposo',
|
||||
NOW() - INTERVAL '4 days',
|
||||
520,
|
||||
'{"humedad": 42, "origen": "Proceso B"}'::jsonb
|
||||
)
|
||||
RETURNING id INTO lote_reposo2_id;
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- PASO 8: SECADO (MEZCLA DE DOS REPOSOS)
|
||||
-- =====================================================
|
||||
-- Se mezclan REP-001 y REP-002 para el secado final
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
op_secado_id UUID;
|
||||
lote_reposo1_id UUID;
|
||||
lote_reposo2_id UUID;
|
||||
lote_secado_id UUID;
|
||||
BEGIN
|
||||
RAISE NOTICE 'Creando secado (mezcla de reposos)...';
|
||||
|
||||
-- Obtener IDs de los lotes de reposo
|
||||
SELECT id INTO lote_reposo1_id FROM lotes WHERE codigo = 'REP-001';
|
||||
SELECT id INTO lote_reposo2_id FROM lotes WHERE codigo = 'REP-002';
|
||||
|
||||
-- Crear operación de secado
|
||||
INSERT INTO operaciones (tipo, fecha, meta)
|
||||
VALUES (
|
||||
'secado',
|
||||
NOW() - INTERVAL '2 days',
|
||||
'{"secadora": "Solar 1", "temperatura_max": 45, "dias": 7}'::jsonb
|
||||
)
|
||||
RETURNING id INTO op_secado_id;
|
||||
|
||||
-- Crear lote secado final
|
||||
INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta)
|
||||
VALUES (
|
||||
'SEC-001',
|
||||
'secado',
|
||||
NOW() - INTERVAL '2 days',
|
||||
2000,
|
||||
'{"humedad_final": 11.5, "calidad": "Pergamino seco"}'::jsonb
|
||||
)
|
||||
RETURNING id INTO lote_secado_id;
|
||||
|
||||
-- Relacionar: dos reposos como input
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES
|
||||
(op_secado_id, lote_reposo1_id, 'input', 1480),
|
||||
(op_secado_id, lote_reposo2_id, 'input', 520);
|
||||
|
||||
-- Relacionar: secado como output
|
||||
INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg)
|
||||
VALUES (op_secado_id, lote_secado_id, 'output', 2000);
|
||||
|
||||
END $$;
|
||||
|
||||
|
||||
-- =====================================================
|
||||
-- RESUMEN DE DATOS CREADOS
|
||||
-- =====================================================
|
||||
DO $$
|
||||
DECLARE
|
||||
total_lotes INTEGER;
|
||||
total_operaciones INTEGER;
|
||||
total_relaciones INTEGER;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO total_lotes FROM lotes;
|
||||
SELECT COUNT(*) INTO total_operaciones FROM operaciones;
|
||||
SELECT COUNT(*) INTO total_relaciones FROM operacion_lotes;
|
||||
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE '✓ Datos de ejemplo creados exitosamente';
|
||||
RAISE NOTICE ' - % lotes creados', total_lotes;
|
||||
RAISE NOTICE ' - % operaciones creadas', total_operaciones;
|
||||
RAISE NOTICE ' - % relaciones lote-operación creadas', total_relaciones;
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE 'Lote final: SEC-001 (Secado)';
|
||||
RAISE NOTICE 'Puedes consultar su trazabilidad completa con:';
|
||||
RAISE NOTICE ' SELECT * FROM get_trazabilidad((SELECT id FROM lotes WHERE codigo = ''SEC-001''));';
|
||||
END $$;
|
||||
Reference in New Issue
Block a user