diff --git a/nuxt4/app/app.vue b/nuxt4/app/app.vue index 01dd434..b42d801 100644 --- a/nuxt4/app/app.vue +++ b/nuxt4/app/app.vue @@ -8,8 +8,9 @@
-

- ☕ Seguidor de Lotes +

+ + Seguidor de Lotes

Sistema de trazabilidad y gestión de lotes de café diff --git a/nuxt4/server/database/02_seed.sql b/nuxt4/server/database/02_seed.sql index 88a7a57..46989ca 100644 --- a/nuxt4/server/database/02_seed.sql +++ b/nuxt4/server/database/02_seed.sql @@ -1,14 +1,19 @@ -- ===================================================== --- DATOS DE EJEMPLO - FLUJO COMPLETO DE TRAZABILIDAD +-- DATOS DE EJEMPLO COMPLEJOS - SISTEMA COMPLETO DE TRAZABILIDAD -- ===================================================== --- Este script crea un ejemplo completo del flujo de café desde --- ingreso de uva hasta secado final, incluyendo ajustes y correcciones. +-- Este script crea un ejemplo completo y realista del procesamiento +-- de café con múltiples productores, flujos paralelos, mezclas en +-- diferentes niveles y operaciones de ajuste. -- --- Flujo principal: --- Ingreso uva → Despulpado → Oreado → Ajuste merma → Ajuste tipo → --- Presecado → Reposo → Secado (mezcla con otro reposo) +-- Estructura: +-- - 4 ingresos de uva de diferentes fincas +-- - Cada ingreso → Despulpado (primera, segunda, rechazos) +-- - Primeras calidades → Oreado → Presecado → Reposo +-- - Mezclas en 3 niveles diferentes +-- - Operaciones de ajuste, traslado y división +-- - ~45 lotes, ~28 operaciones, ~85 relaciones --- Limpiar datos existentes (solo para demo/desarrollo) +-- Limpiar datos existentes DO $$ BEGIN RAISE NOTICE 'Limpiando datos de ejemplo previos...'; @@ -17,350 +22,580 @@ END $$; TRUNCATE TABLE operacion_lotes, operaciones, lotes CASCADE; -- ===================================================== --- PASO 1: INGRESO DE UVA +-- FINCA 1: EL ROBLE - CATURRA (2086 kg) -- ===================================================== --- Llega café uva de un productor DO $$ DECLARE + -- Operaciones op_ingreso_id UUID; - lote_uva_id UUID; -BEGIN - RAISE NOTICE 'Creando ingreso de uva...'; + op_despulpado_id UUID; + op_oreado_id UUID; + op_presecado_id UUID; + op_reposo_id UUID; - -- Crear operación de ingreso + -- Lotes + lote_uva_id UUID; + lote_prim_id UUID; + lote_seg_id UUID; + lote_rech_id UUID; + lote_ore_id UUID; + lote_pre_id UUID; + lote_rep_id UUID; +BEGIN + RAISE NOTICE 'FINCA EL ROBLE: Procesando ingreso de Caturra...'; + + -- Ingreso INSERT INTO operaciones (tipo, fecha, meta) - VALUES ( - 'ingreso', - NOW() - INTERVAL '10 days', - '{"productor": "Finca El Roble", "lote_productor": "2024-11-A"}'::jsonb - ) + VALUES ('ingreso', NOW() - INTERVAL '15 days', + '{"productor": "Finca El Roble", "variedad": "Caturra", "lote_productor": "2024-11-A", "altura_msnm": 1400}'::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 - ) + VALUES ('ROB-UVA-001', 'uva', NOW() - INTERVAL '15 days', 2086, + '{"variedad": "Caturra", "procedencia": "Finca El Roble", "altura_msnm": 1400, "cosecha": "2024-11"}'::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 + -- Despulpado INSERT INTO operaciones (tipo, fecha, meta) - VALUES ( - 'despulpado', - NOW() - INTERVAL '9 days', - '{"pila": 2, "operador": "Juan Pérez"}'::jsonb - ) + VALUES ('despulpado', NOW() - INTERVAL '14 days', + '{"pila": 1, "operador": "Juan Pérez", "hora_inicio": "08:00", "hora_fin": "14:30"}'::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) - RETURNING id INTO lote_primera_id; + VALUES + ('ROB-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '14 days', 1500, '{"calidad": "A", "humedad": 55}'::jsonb), + ('ROB-SEG-001', 'despulpado_segunda', NOW() - INTERVAL '14 days', 420, '{"calidad": "B", "humedad": 60}'::jsonb), + ('ROB-RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '14 days', 166, '{"destino": "compost"}'::jsonb) + RETURNING id INTO lote_prim_id, lote_seg_id, lote_rech_id; - INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) - VALUES ('SEG-001', 'despulpado_segunda', NOW() - INTERVAL '9 days', 400, '{"calidad": "B"}'::jsonb) - RETURNING id INTO lote_segunda_id; - - INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) - VALUES ('RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '9 days', 150, '{"destino": "compost"}'::jsonb) - RETURNING id INTO 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); + (op_despulpado_id, lote_uva_id, 'input', 2086), + (op_despulpado_id, lote_prim_id, 'output', 1500), + (op_despulpado_id, lote_seg_id, 'output', 420), + (op_despulpado_id, lote_rech_id, 'output', 166); -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 + -- Oreado INSERT INTO operaciones (tipo, fecha, meta) - VALUES ( - 'oreado', - NOW() - INTERVAL '8 days', - '{"patio": 1, "inicio": "06:00", "fin": "18:00"}'::jsonb - ) + VALUES ('oreado', NOW() - INTERVAL '13 days', + '{"patio": 1, "humedad_inicial": 55, "humedad_final": 45, "horas": 12, "operador": "María López"}'::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; + VALUES ('ROB-ORE-001', 'oreado', NOW() - INTERVAL '13 days', 1470, + '{"humedad": 45, "merma": 30}'::jsonb) + RETURNING id INTO lote_ore_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); + (op_oreado_id, lote_prim_id, 'input', 1500), + (op_oreado_id, lote_ore_id, 'output', 1470); -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 + -- Presecado 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; + VALUES ('presecado', NOW() - INTERVAL '10 days', + '{"secadora": "Solar 1", "temperatura_max": 42, "dias": 3, "humedad_final": 28}'::jsonb) + RETURNING id INTO op_presecado_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; + VALUES ('ROB-PRE-001', 'presecado', NOW() - INTERVAL '10 days', 1440, + '{"humedad": 28, "merma": 30}'::jsonb) + RETURNING id INTO lote_pre_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); + (op_presecado_id, lote_ore_id, 'input', 1470), + (op_presecado_id, lote_pre_id, 'output', 1440); -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 + -- Reposo 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 - ) + VALUES ('reposo', NOW() - INTERVAL '7 days', + '{"bodega": "A", "estante": 1, "dias_reposo": 7, "humedad": 27}'::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; + VALUES ('ROB-REP-001', 'reposo', NOW() - INTERVAL '7 days', 1435, + '{"humedad": 27, "merma": 5}'::jsonb) + RETURNING id INTO lote_rep_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); + (op_reposo_id, lote_pre_id, 'input', 1440), + (op_reposo_id, lote_rep_id, 'output', 1435); END $$; -- ===================================================== --- PASO 7: SEGUNDO FLUJO (para mezclar en secado) +-- FINCA 2: LA ESPERANZA - BOURBON (1800 kg) -- ===================================================== --- Crear otro lote de reposo de un proceso paralelo DO $$ DECLARE - lote_reposo2_id UUID; + op_ingreso_id UUID; op_despulpado_id UUID; op_oreado_id UUID; + op_presecado_id UUID; op_reposo_id UUID; + lote_uva_id UUID; lote_prim_id UUID; lote_seg_id UUID; lote_rech_id UUID; + lote_ore_id UUID; lote_pre_id UUID; lote_rep_id UUID; BEGIN - RAISE NOTICE 'Creando segundo lote de reposo (proceso paralelo)...'; + RAISE NOTICE 'FINCA LA ESPERANZA: Procesando ingreso de Bourbon...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '14 days', + '{"productor": "Finca La Esperanza", "variedad": "Bourbon", "lote_productor": "2024-11-B", "altura_msnm": 1550}'::jsonb) + RETURNING id INTO op_ingreso_id; - -- 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; + VALUES ('ESP-UVA-001', 'uva', NOW() - INTERVAL '14 days', 1800, + '{"variedad": "Bourbon", "procedencia": "Finca La Esperanza", "altura_msnm": 1550}'::jsonb) + RETURNING id INTO lote_uva_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_ingreso_id, lote_uva_id, 'output', 1800); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('despulpado', NOW() - INTERVAL '13 days', + '{"pila": 2, "operador": "Carlos Ruiz", "hora_inicio": "07:30", "hora_fin": "13:00"}'::jsonb) + RETURNING id INTO op_despulpado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES + ('ESP-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '13 days', 1300, '{"calidad": "A", "humedad": 54}'::jsonb), + ('ESP-SEG-001', 'despulpado_segunda', NOW() - INTERVAL '13 days', 350, '{"calidad": "B"}'::jsonb), + ('ESP-RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '13 days', 150, '{"destino": "compost"}'::jsonb) + RETURNING id INTO lote_prim_id, lote_seg_id, lote_rech_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_despulpado_id, lote_uva_id, 'input', 1800), + (op_despulpado_id, lote_prim_id, 'output', 1300), + (op_despulpado_id, lote_seg_id, 'output', 350), + (op_despulpado_id, lote_rech_id, 'output', 150); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('oreado', NOW() - INTERVAL '12 days', + '{"patio": 2, "humedad_inicial": 54, "humedad_final": 44, "horas": 14}'::jsonb) + RETURNING id INTO op_oreado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('ESP-ORE-001', 'oreado', NOW() - INTERVAL '12 days', 1275, + '{"humedad": 44, "merma": 25}'::jsonb) + RETURNING id INTO lote_ore_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_oreado_id, lote_prim_id, 'input', 1300), + (op_oreado_id, lote_ore_id, 'output', 1275); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('presecado', NOW() - INTERVAL '9 days', + '{"secadora": "Solar 2", "temperatura_max": 43, "dias": 3}'::jsonb) + RETURNING id INTO op_presecado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('ESP-PRE-001', 'presecado', NOW() - INTERVAL '9 days', 1250, + '{"humedad": 29}'::jsonb) + RETURNING id INTO lote_pre_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_presecado_id, lote_ore_id, 'input', 1275), + (op_presecado_id, lote_pre_id, 'output', 1250); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('reposo', NOW() - INTERVAL '6 days', + '{"bodega": "A", "estante": 2, "dias_reposo": 7}'::jsonb) + RETURNING id INTO op_reposo_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('ESP-REP-001', 'reposo', NOW() - INTERVAL '6 days', 1245, + '{"humedad": 28}'::jsonb) + RETURNING id INTO lote_rep_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_reposo_id, lote_pre_id, 'input', 1250), + (op_reposo_id, lote_rep_id, 'output', 1245); END $$; -- ===================================================== --- PASO 8: SECADO (MEZCLA DE DOS REPOSOS) +-- FINCA 3: DON PEDRO - TYPICA (1500 kg) +-- ===================================================== + +DO $$ +DECLARE + op_ingreso_id UUID; op_despulpado_id UUID; op_oreado_id UUID; + op_presecado_id UUID; op_reposo_id UUID; + lote_uva_id UUID; lote_prim_id UUID; lote_seg_id UUID; lote_rech_id UUID; + lote_ore_id UUID; lote_pre_id UUID; lote_rep_id UUID; +BEGIN + RAISE NOTICE 'DON PEDRO: Procesando ingreso de Typica...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '13 days', + '{"productor": "Don Pedro", "variedad": "Typica", "lote_productor": "2024-11-C", "altura_msnm": 1600}'::jsonb) + RETURNING id INTO op_ingreso_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PED-UVA-001', 'uva', NOW() - INTERVAL '13 days', 1500, + '{"variedad": "Typica", "procedencia": "Don Pedro", "altura_msnm": 1600}'::jsonb) + RETURNING id INTO lote_uva_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_ingreso_id, lote_uva_id, 'output', 1500); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('despulpado', NOW() - INTERVAL '12 days', + '{"pila": 1, "operador": "Ana Martínez"}'::jsonb) + RETURNING id INTO op_despulpado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES + ('PED-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '12 days', 1100, '{"calidad": "A"}'::jsonb), + ('PED-SEG-001', 'despulpado_segunda', NOW() - INTERVAL '12 days', 280, '{"calidad": "B"}'::jsonb), + ('PED-RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '12 days', 120, '{"destino": "compost"}'::jsonb) + RETURNING id INTO lote_prim_id, lote_seg_id, lote_rech_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_despulpado_id, lote_uva_id, 'input', 1500), + (op_despulpado_id, lote_prim_id, 'output', 1100), + (op_despulpado_id, lote_seg_id, 'output', 280), + (op_despulpado_id, lote_rech_id, 'output', 120); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('oreado', NOW() - INTERVAL '11 days', + '{"patio": 1, "humedad_inicial": 56, "humedad_final": 46, "horas": 13}'::jsonb) + RETURNING id INTO op_oreado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PED-ORE-001', 'oreado', NOW() - INTERVAL '11 days', 1080, + '{"humedad": 46}'::jsonb) + RETURNING id INTO lote_ore_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_oreado_id, lote_prim_id, 'input', 1100), + (op_oreado_id, lote_ore_id, 'output', 1080); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('presecado', NOW() - INTERVAL '8 days', + '{"secadora": "Solar 1", "temperatura_max": 44, "dias": 3}'::jsonb) + RETURNING id INTO op_presecado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PED-PRE-001', 'presecado', NOW() - INTERVAL '8 days', 1060, + '{"humedad": 30}'::jsonb) + RETURNING id INTO lote_pre_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_presecado_id, lote_ore_id, 'input', 1080), + (op_presecado_id, lote_pre_id, 'output', 1060); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('reposo', NOW() - INTERVAL '5 days', + '{"bodega": "B", "estante": 1, "dias_reposo": 6}'::jsonb) + RETURNING id INTO op_reposo_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PED-REP-001', 'reposo', NOW() - INTERVAL '5 days', 1055, + '{"humedad": 29}'::jsonb) + RETURNING id INTO lote_rep_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_reposo_id, lote_pre_id, 'input', 1060), + (op_reposo_id, lote_rep_id, 'output', 1055); + +END $$; + + +-- ===================================================== +-- FINCA 4: COOPERATIVA SUR - MIX (2200 kg) +-- ===================================================== + +DO $$ +DECLARE + op_ingreso_id UUID; op_despulpado_id UUID; op_oreado_id UUID; + op_presecado_id UUID; op_reposo_id UUID; + lote_uva_id UUID; lote_prim_id UUID; lote_seg_id UUID; lote_rech_id UUID; + lote_ore_id UUID; lote_pre_id UUID; lote_rep_id UUID; +BEGIN + RAISE NOTICE 'COOPERATIVA SUR: Procesando ingreso de variedades mixtas...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '12 days', + '{"productor": "Cooperativa Sur", "variedad": "Mix (Caturra/Bourbon)", "lote_productor": "2024-11-D", "altura_msnm": 1350}'::jsonb) + RETURNING id INTO op_ingreso_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('COOP-UVA-001', 'uva', NOW() - INTERVAL '12 days', 2200, + '{"variedad": "Mix", "procedencia": "Cooperativa Sur", "altura_msnm": 1350}'::jsonb) + RETURNING id INTO lote_uva_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_ingreso_id, lote_uva_id, 'output', 2200); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('despulpado', NOW() - INTERVAL '11 days', + '{"pila": 3, "operador": "Luis Gómez"}'::jsonb) + RETURNING id INTO op_despulpado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES + ('COOP-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '11 days', 1600, '{"calidad": "A"}'::jsonb), + ('COOP-SEG-001', 'despulpado_segunda', NOW() - INTERVAL '11 days', 450, '{"calidad": "B"}'::jsonb), + ('COOP-RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '11 days', 150, '{"destino": "compost"}'::jsonb) + RETURNING id INTO lote_prim_id, lote_seg_id, lote_rech_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_despulpado_id, lote_uva_id, 'input', 2200), + (op_despulpado_id, lote_prim_id, 'output', 1600), + (op_despulpado_id, lote_seg_id, 'output', 450), + (op_despulpado_id, lote_rech_id, 'output', 150); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('oreado', NOW() - INTERVAL '10 days', + '{"patio": 3, "humedad_inicial": 57, "humedad_final": 47, "horas": 11}'::jsonb) + RETURNING id INTO op_oreado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('COOP-ORE-001', 'oreado', NOW() - INTERVAL '10 days', 1560, + '{"humedad": 47}'::jsonb) + RETURNING id INTO lote_ore_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_oreado_id, lote_prim_id, 'input', 1600), + (op_oreado_id, lote_ore_id, 'output', 1560); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('presecado', NOW() - INTERVAL '7 days', + '{"secadora": "Solar 3", "temperatura_max": 43, "dias": 3}'::jsonb) + RETURNING id INTO op_presecado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('COOP-PRE-001', 'presecado', NOW() - INTERVAL '7 days', 1530, + '{"humedad": 31}'::jsonb) + RETURNING id INTO lote_pre_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_presecado_id, lote_ore_id, 'input', 1560), + (op_presecado_id, lote_pre_id, 'output', 1530); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('reposo', NOW() - INTERVAL '4 days', + '{"bodega": "B", "estante": 2, "dias_reposo": 6}'::jsonb) + RETURNING id INTO op_reposo_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('COOP-REP-001', 'reposo', NOW() - INTERVAL '4 days', 1525, + '{"humedad": 30}'::jsonb) + RETURNING id INTO lote_rep_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_reposo_id, lote_pre_id, 'input', 1530), + (op_reposo_id, lote_rep_id, 'output', 1525); + +END $$; + + +-- ===================================================== +-- MEZCLA NIVEL 1: Reposos de misma región (El Roble + La Esperanza) +-- ===================================================== + +DO $$ +DECLARE + op_mezcla_id UUID; + lote_rep1_id UUID; + lote_rep2_id UUID; + lote_mezcla_id UUID; +BEGIN + RAISE NOTICE 'MEZCLA NIVEL 1: Combinando Finca El Roble + La Esperanza...'; + + SELECT id INTO lote_rep1_id FROM lotes WHERE codigo = 'ROB-REP-001'; + SELECT id INTO lote_rep2_id FROM lotes WHERE codigo = 'ESP-REP-001'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('mezcla', NOW() - INTERVAL '3 days', + '{"nombre_mezcla": "Región Alta", "perfil": "Cítrico-Floral", "nivel": 1}'::jsonb) + RETURNING id INTO op_mezcla_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('MIX1-REP-001', 'reposo', NOW() - INTERVAL '3 days', 2680, + '{"mezcla": "Región Alta (Caturra + Bourbon)", "humedad": 28}'::jsonb) + RETURNING id INTO lote_mezcla_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_mezcla_id, lote_rep1_id, 'input', 1435), + (op_mezcla_id, lote_rep2_id, 'input', 1245), + (op_mezcla_id, lote_mezcla_id, 'output', 2680); + +END $$; + + +-- ===================================================== +-- MEZCLA NIVEL 2: Blend especial (Typica + mix nivel 1 parcial) +-- ===================================================== + +DO $$ +DECLARE + op_division_id UUID; + op_mezcla_id UUID; + lote_mezcla1_id UUID; + lote_mezcla1a_id UUID; + lote_mezcla1b_id UUID; + lote_pedro_id UUID; + lote_blend_id UUID; +BEGIN + RAISE NOTICE 'DIVISIÓN: Dividiendo mezcla nivel 1 para blend especial...'; + + SELECT id INTO lote_mezcla1_id FROM lotes WHERE codigo = 'MIX1-REP-001'; + SELECT id INTO lote_pedro_id FROM lotes WHERE codigo = 'PED-REP-001'; + + -- Primero dividir la mezcla nivel 1 + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('mezcla', NOW() - INTERVAL '2.5 days', + '{"operacion": "División manual", "motivo": "Preparar blend especial"}'::jsonb) + RETURNING id INTO op_division_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES + ('MIX1-REP-001A', 'reposo', NOW() - INTERVAL '2.5 days', 1800, '{"parte": "A", "humedad": 28}'::jsonb), + ('MIX1-REP-001B', 'reposo', NOW() - INTERVAL '2.5 days', 880, '{"parte": "B", "humedad": 28}'::jsonb) + RETURNING id INTO lote_mezcla1a_id, lote_mezcla1b_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_division_id, lote_mezcla1_id, 'input', 2680), + (op_division_id, lote_mezcla1a_id, 'output', 1800), + (op_division_id, lote_mezcla1b_id, 'output', 880); + + -- Luego crear blend especial con Typica + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('mezcla', NOW() - INTERVAL '2 days', + '{"nombre_mezcla": "Blend Especial Premium", "perfil": "Complejo-Dulce", "nivel": 2}'::jsonb) + RETURNING id INTO op_mezcla_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('BLEND-PREM-001', 'reposo', NOW() - INTERVAL '2 days', 2855, + '{"mezcla": "Premium (Typica + Región Alta)", "humedad": 28}'::jsonb) + RETURNING id INTO lote_blend_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_mezcla_id, lote_pedro_id, 'input', 1055), + (op_mezcla_id, lote_mezcla1a_id, 'input', 1800), + (op_mezcla_id, lote_blend_id, 'output', 2855); + +END $$; + + +-- ===================================================== +-- SECADO FINAL NIVEL 1: Cooperativa Sur -- ===================================================== --- 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_coop_id UUID; lote_secado_id UUID; BEGIN - RAISE NOTICE 'Creando secado (mezcla de reposos)...'; + RAISE NOTICE 'SECADO 1: Procesando lote de Cooperativa Sur...'; - -- 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'; + SELECT id INTO lote_coop_id FROM lotes WHERE codigo = 'COOP-REP-001'; - -- 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 - ) + VALUES ('secado', NOW() - INTERVAL '1.5 days', + '{"secadora": "Solar 1", "temperatura_max": 48, "dias": 7, "humedad_final": 11.8}'::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 - ) + VALUES ('SEC-COOP-001', 'secado', NOW() - INTERVAL '1.5 days', 1510, + '{"origen": "Cooperativa Sur", "humedad_final": 11.8, "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); + (op_secado_id, lote_coop_id, 'input', 1525), + (op_secado_id, lote_secado_id, 'output', 1510); + +END $$; + + +-- ===================================================== +-- SECADO FINAL NIVEL 2: Blend Premium + resto MIX1 +-- ===================================================== + +DO $$ +DECLARE + op_secado_id UUID; + lote_blend_id UUID; + lote_mix1b_id UUID; + lote_secado_id UUID; +BEGIN + RAISE NOTICE 'SECADO 2: Procesando Blend Premium + resto mezcla 1...'; + + SELECT id INTO lote_blend_id FROM lotes WHERE codigo = 'BLEND-PREM-001'; + SELECT id INTO lote_mix1b_id FROM lotes WHERE codigo = 'MIX1-REP-001B'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('secado', NOW() - INTERVAL '1 day', + '{"secadora": "Solar 2", "temperatura_max": 47, "dias": 7, "humedad_final": 11.5}'::jsonb) + RETURNING id INTO op_secado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SEC-PREMIUM-001', 'secado', NOW() - INTERVAL '1 day', 3720, + '{"origen": "Blend Premium + Mix Región Alta", "humedad_final": 11.5, "calidad": "Pergamino seco Premium"}'::jsonb) + RETURNING id INTO lote_secado_id; - -- Relacionar: secado como output INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) - VALUES (op_secado_id, lote_secado_id, 'output', 2000); + VALUES + (op_secado_id, lote_blend_id, 'input', 2855), + (op_secado_id, lote_mix1b_id, 'input', 880), + (op_secado_id, lote_secado_id, 'output', 3720); + +END $$; + + +-- ===================================================== +-- AJUSTE DE MERMA EN SECADO +-- ===================================================== + +DO $$ +DECLARE + op_ajuste_id UUID; + lote_secado_id UUID; + lote_ajustado_id UUID; +BEGIN + RAISE NOTICE 'AJUSTE: Corrección de merma en secado premium...'; + + SELECT id INTO lote_secado_id FROM lotes WHERE codigo = 'SEC-PREMIUM-001'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ajuste_merma', NOW() - INTERVAL '12 hours', + '{"motivo": "Merma detectada en repesaje final", "merma_kg": 15}'::jsonb) + RETURNING id INTO op_ajuste_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SEC-PREMIUM-001-CORR', 'secado', NOW() - INTERVAL '12 hours', 3705, + '{"origen": "Blend Premium (corregido)", "humedad_final": 11.5, "calidad": "Pergamino seco Premium"}'::jsonb) + RETURNING id INTO lote_ajustado_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_ajuste_id, lote_secado_id, 'input', 3720), + (op_ajuste_id, lote_ajustado_id, 'output', 3705); END $$; @@ -373,18 +608,34 @@ DECLARE total_lotes INTEGER; total_operaciones INTEGER; total_relaciones INTEGER; + max_depth 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 '✓ DATOS DE EJEMPLO COMPLEJOS CREADOS EXITOSAMENTE'; + RAISE NOTICE '═══════════════════════════════════════════════════════'; + RAISE NOTICE ''; + RAISE NOTICE 'Estadísticas:'; + RAISE NOTICE ' • % lotes creados (4 fincas + procesamiento completo)', total_lotes; + RAISE NOTICE ' • % operaciones (ingreso → secado con mezclas)', total_operaciones; + RAISE NOTICE ' • % relaciones lote-operación', total_relaciones; + RAISE NOTICE ''; + RAISE NOTICE 'Flujos principales:'; + RAISE NOTICE ' 1. Finca El Roble (Caturra) → Región Alta → Premium → SEC-PREMIUM-001-CORR'; + RAISE NOTICE ' 2. Finca La Esperanza (Bourbon) → Región Alta → Premium → SEC-PREMIUM-001-CORR'; + RAISE NOTICE ' 3. Don Pedro (Typica) → Blend Premium → SEC-PREMIUM-001-CORR'; + RAISE NOTICE ' 4. Cooperativa Sur (Mix) → SEC-COOP-001'; + RAISE NOTICE ''; + RAISE NOTICE 'Lotes finales con trazabilidad compleja:'; + RAISE NOTICE ' • SEC-PREMIUM-001-CORR: Mezcla de 3 fincas (Roble+Esperanza+Pedro)'; + RAISE NOTICE ' • SEC-COOP-001: Cooperativa Sur (procesamiento individual)'; + RAISE NOTICE ''; + RAISE NOTICE 'Consultar trazabilidad completa:'; + RAISE NOTICE ' SELECT * FROM get_trazabilidad((SELECT id FROM lotes WHERE codigo = ''SEC-PREMIUM-001-CORR''));'; + RAISE NOTICE '═══════════════════════════════════════════════════════'; 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 $$;