From f3a170c88224d3664c2063b095866eaba3e3a825 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Sat, 22 Nov 2025 04:05:24 -0600 Subject: [PATCH] Feat: agregar 4 flujos complejos al seed y filtrar lotes finales en grafos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Agregar flujo 5: Las Nubes (Geisha) + El Paraíso (Castillo) → SEC-EXOTIC-001 - Agregar flujo 6: Santa Rita (Caturra Rojo) → División → SEC-SRT-PREM-001 + SEC-SRT-STD-001 - Agregar flujo 7: Trinidad + San José + Villa Rosa → Triple Blend → SEC-TRIPLE-001 - Agregar flujo 8: Mezcla de segundas calidades → SEC-COMERCIAL-001 - Implementar filtro soloFinales en queries, API y composable - Modificar tab Grafos para mostrar solo lotes finales (sin hijos) - Actualizar descripción de tab Grafos para clarificar el filtro - Total: 7 lotes finales de secado para visualización de grafos --- nuxt4/app/app.vue | 5 +- nuxt4/app/composables/useLotes.ts | 2 + nuxt4/server/api/lotes/index.get.ts | 2 + nuxt4/server/database/02_seed.sql | 639 +++++++++++++++++++++++++++- nuxt4/server/utils/queries.ts | 10 + 5 files changed, 644 insertions(+), 14 deletions(-) diff --git a/nuxt4/app/app.vue b/nuxt4/app/app.vue index b42d801..68c39d2 100644 --- a/nuxt4/app/app.vue +++ b/nuxt4/app/app.vue @@ -116,7 +116,7 @@

Grafo de trazabilidad

-

Visualiza el grafo desde el lote seleccionado (por defecto el más reciente).

+

Visualiza el grafo completo desde un lote final (sin hijos). Solo se muestran lotes que no han sido procesados.

{ graphLoading.value = true graphError.value = null try { - const lotes = await fetchLotesComposable() + // Filtrar solo lotes finales (sin hijos) para el grafo + const lotes = await fetchLotesComposable({ soloFinales: true }) graphLotes.value = lotes.sort((a, b) => new Date(b.fecha_creado).getTime() - new Date(a.fecha_creado).getTime() ) diff --git a/nuxt4/app/composables/useLotes.ts b/nuxt4/app/composables/useLotes.ts index 014b714..4d79e6e 100644 --- a/nuxt4/app/composables/useLotes.ts +++ b/nuxt4/app/composables/useLotes.ts @@ -48,6 +48,7 @@ export const useLotes = () => { tipo?: string limit?: number offset?: number + soloFinales?: boolean }) => { console.log('🔵 fetchLotes: Iniciando, filtros:', filtros) try { @@ -55,6 +56,7 @@ export const useLotes = () => { if (filtros?.tipo) query.append('tipo', filtros.tipo) if (filtros?.limit) query.append('limit', filtros.limit.toString()) if (filtros?.offset) query.append('offset', filtros.offset.toString()) + if (filtros?.soloFinales) query.append('soloFinales', 'true') const queryString = query.toString() const url = `/api/lotes${queryString ? `?${queryString}` : ''}` diff --git a/nuxt4/server/api/lotes/index.get.ts b/nuxt4/server/api/lotes/index.get.ts index 25a5839..27c551c 100644 --- a/nuxt4/server/api/lotes/index.get.ts +++ b/nuxt4/server/api/lotes/index.get.ts @@ -8,6 +8,7 @@ import { getLotes } from '../../utils/queries' * - tipo: filtrar por tipo de lote (uva, despulpado_primera, oreado, etc.) * - limit: límite de resultados * - offset: offset para paginación + * - soloFinales: filtrar solo lotes sin hijos (true/false) */ export default defineEventHandler(async (event) => { console.log('🟦 API /api/lotes: Request recibido') @@ -19,6 +20,7 @@ export default defineEventHandler(async (event) => { tipo: query.tipo as string | undefined, limit: query.limit ? parseInt(query.limit as string) : undefined, offset: query.offset ? parseInt(query.offset as string) : undefined, + soloFinales: query.soloFinales === 'true' || query.soloFinales === '1', } console.log('🟦 API /api/lotes: Filtros procesados:', filtros) diff --git a/nuxt4/server/database/02_seed.sql b/nuxt4/server/database/02_seed.sql index 00eaa47..a9e7d1d 100644 --- a/nuxt4/server/database/02_seed.sql +++ b/nuxt4/server/database/02_seed.sql @@ -622,6 +622,615 @@ BEGIN END $$; +-- ===================================================== +-- FLUJO 5: LAS NUBES (GEISHA) + EL PARAÍSO (CASTILLO) → MEZCLA EXÓTICA +-- ===================================================== + +DO $$ +DECLARE + -- Las Nubes + op_ing1_id UUID; op_desp1_id UUID; op_ore1_id UUID; op_pre1_id UUID; op_rep1_id UUID; + lote_uva1_id UUID; lote_prim1_id UUID; lote_seg1_id UUID; lote_rech1_id UUID; + lote_ore1_id UUID; lote_pre1_id UUID; lote_rep1_id UUID; + + -- El Paraíso + op_ing2_id UUID; op_desp2_id UUID; op_ore2_id UUID; op_pre2_id UUID; op_rep2_id UUID; + lote_uva2_id UUID; lote_prim2_id UUID; lote_seg2_id UUID; lote_rech2_id UUID; + lote_ore2_id UUID; lote_pre2_id UUID; lote_rep2_id UUID; + + -- Mezcla y secado + op_mezcla_id UUID; op_secado_id UUID; + lote_mezcla_id UUID; lote_secado_id UUID; +BEGIN + RAISE NOTICE 'FLUJO 5: Las Nubes (Geisha) - procesamiento completo...'; + + -- Ingreso Las Nubes (Geisha - variedad premium) + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '20 days', + '{"productor": "Finca Las Nubes", "variedad": "Geisha", "lote_productor": "2024-11-E", "altura_msnm": 1750, "certificacion": "Orgánico"}'::jsonb) + RETURNING id INTO op_ing1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('NUB-UVA-001', 'uva', NOW() - INTERVAL '20 days', 950, + '{"variedad": "Geisha", "procedencia": "Finca Las Nubes", "altura_msnm": 1750, "certificacion": "Orgánico"}'::jsonb) + RETURNING id INTO lote_uva1_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_ing1_id, lote_uva1_id, 'output', 950); + + -- Despulpado Las Nubes + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('despulpado', NOW() - INTERVAL '19 days', + '{"pila": 1, "operador": "Patricia Silva", "proceso": "Lavado tradicional"}'::jsonb) + RETURNING id INTO op_desp1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('NUB-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '19 days', 720, '{"calidad": "AA", "humedad": 53}'::jsonb) + RETURNING id INTO lote_prim1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('NUB-SEG-001', 'despulpado_segunda', NOW() - INTERVAL '19 days', 160, '{"calidad": "A"}'::jsonb) + RETURNING id INTO lote_seg1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('NUB-RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '19 days', 70, '{"destino": "compost"}'::jsonb) + RETURNING id INTO lote_rech1_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_desp1_id, lote_uva1_id, 'input', 950), + (op_desp1_id, lote_prim1_id, 'output', 720), + (op_desp1_id, lote_seg1_id, 'output', 160), + (op_desp1_id, lote_rech1_id, 'output', 70); + + -- Oreado, Presecado, Reposo Las Nubes + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('oreado', NOW() - INTERVAL '18 days', '{"patio": 1, "humedad_inicial": 53, "humedad_final": 42, "horas": 16}'::jsonb) + RETURNING id INTO op_ore1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('NUB-ORE-001', 'oreado', NOW() - INTERVAL '18 days', 705, '{"humedad": 42}'::jsonb) + RETURNING id INTO lote_ore1_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_ore1_id, lote_prim1_id, 'input', 720), (op_ore1_id, lote_ore1_id, 'output', 705); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('presecado', NOW() - INTERVAL '15 days', '{"secadora": "Solar Premium", "temperatura_max": 40, "dias": 4}'::jsonb) + RETURNING id INTO op_pre1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('NUB-PRE-001', 'presecado', NOW() - INTERVAL '15 days', 690, '{"humedad": 26}'::jsonb) + RETURNING id INTO lote_pre1_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_pre1_id, lote_ore1_id, 'input', 705), (op_pre1_id, lote_pre1_id, 'output', 690); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('reposo', NOW() - INTERVAL '12 days', '{"bodega": "Premium", "estante": 1, "dias_reposo": 10}'::jsonb) + RETURNING id INTO op_rep1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('NUB-REP-001', 'reposo', NOW() - INTERVAL '12 days', 687, '{"humedad": 25}'::jsonb) + RETURNING id INTO lote_rep1_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_rep1_id, lote_pre1_id, 'input', 690), (op_rep1_id, lote_rep1_id, 'output', 687); + + -- Ingreso El Paraíso (Castillo) + RAISE NOTICE 'FLUJO 5: El Paraíso (Castillo) - procesamiento completo...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '19 days', + '{"productor": "Finca El Paraíso", "variedad": "Castillo", "lote_productor": "2024-11-F", "altura_msnm": 1650}'::jsonb) + RETURNING id INTO op_ing2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PAR-UVA-001', 'uva', NOW() - INTERVAL '19 days', 1350, + '{"variedad": "Castillo", "procedencia": "Finca El Paraíso", "altura_msnm": 1650}'::jsonb) + RETURNING id INTO lote_uva2_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_ing2_id, lote_uva2_id, 'output', 1350); + + -- Despulpado El Paraíso + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('despulpado', NOW() - INTERVAL '18 days', '{"pila": 2, "operador": "Roberto Paz"}'::jsonb) + RETURNING id INTO op_desp2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PAR-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '18 days', 980, '{"calidad": "A", "humedad": 55}'::jsonb) + RETURNING id INTO lote_prim2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PAR-SEG-001', 'despulpado_segunda', NOW() - INTERVAL '18 days', 255, '{"calidad": "B"}'::jsonb) + RETURNING id INTO lote_seg2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PAR-RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '18 days', 115, '{"destino": "compost"}'::jsonb) + RETURNING id INTO lote_rech2_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_desp2_id, lote_uva2_id, 'input', 1350), + (op_desp2_id, lote_prim2_id, 'output', 980), + (op_desp2_id, lote_seg2_id, 'output', 255), + (op_desp2_id, lote_rech2_id, 'output', 115); + + -- Oreado, Presecado, Reposo El Paraíso + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('oreado', NOW() - INTERVAL '17 days', '{"patio": 2, "humedad_inicial": 55, "humedad_final": 44, "horas": 13}'::jsonb) + RETURNING id INTO op_ore2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PAR-ORE-001', 'oreado', NOW() - INTERVAL '17 days', 960, '{"humedad": 44}'::jsonb) + RETURNING id INTO lote_ore2_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_ore2_id, lote_prim2_id, 'input', 980), (op_ore2_id, lote_ore2_id, 'output', 960); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('presecado', NOW() - INTERVAL '14 days', '{"secadora": "Solar 2", "temperatura_max": 42, "dias": 3}'::jsonb) + RETURNING id INTO op_pre2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PAR-PRE-001', 'presecado', NOW() - INTERVAL '14 days', 940, '{"humedad": 28}'::jsonb) + RETURNING id INTO lote_pre2_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_pre2_id, lote_ore2_id, 'input', 960), (op_pre2_id, lote_pre2_id, 'output', 940); + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('reposo', NOW() - INTERVAL '11 days', '{"bodega": "A", "estante": 3, "dias_reposo": 8}'::jsonb) + RETURNING id INTO op_rep2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('PAR-REP-001', 'reposo', NOW() - INTERVAL '11 days', 935, '{"humedad": 27}'::jsonb) + RETURNING id INTO lote_rep2_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_rep2_id, lote_pre2_id, 'input', 940), (op_rep2_id, lote_rep2_id, 'output', 935); + + -- Mezcla Exótica + RAISE NOTICE 'FLUJO 5: Creando mezcla exótica Geisha + Castillo...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('mezcla', NOW() - INTERVAL '8 days', + '{"nombre_mezcla": "Blend Exótico", "perfil": "Floral-Cítrico Premium", "nivel": 1}'::jsonb) + RETURNING id INTO op_mezcla_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('EXOTIC-REP-001', 'reposo', NOW() - INTERVAL '8 days', 1622, + '{"mezcla": "Geisha + Castillo", "perfil": "Exótico Premium"}'::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', 687), + (op_mezcla_id, lote_rep2_id, 'input', 935), + (op_mezcla_id, lote_mezcla_id, 'output', 1622); + + -- Secado Exótico + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('secado', NOW() - INTERVAL '5 days', + '{"secadora": "Solar Premium", "temperatura_max": 45, "dias": 8, "humedad_final": 11.2, "proceso": "Secado lento controlado"}'::jsonb) + RETURNING id INTO op_secado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SEC-EXOTIC-001', 'secado', NOW() - INTERVAL '5 days', 1605, + '{"origen": "Blend Exótico", "humedad_final": 11.2, "calidad": "Pergamino Premium Exótico", "notas": "Floral, cítrico, miel"}'::jsonb) + RETURNING id INTO lote_secado_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_secado_id, lote_mezcla_id, 'input', 1622), (op_secado_id, lote_secado_id, 'output', 1605); + +END $$; + + +-- ===================================================== +-- FLUJO 6: SANTA RITA (CATURRA ROJO) → DIVISIÓN → DOS SECADOS +-- ===================================================== + +DO $$ +DECLARE + op_ingreso_id UUID; op_despulpado_id UUID; op_oreado_id UUID; + op_presecado_id UUID; op_reposo_id UUID; op_division_id UUID; + op_secado1_id UUID; op_secado2_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; + lote_div1_id UUID; lote_div2_id UUID; lote_div3_id UUID; + lote_sec1_id UUID; lote_sec2_id UUID; +BEGIN + RAISE NOTICE 'FLUJO 6: Santa Rita (Caturra Rojo) - procesamiento completo...'; + + -- Ingreso + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '17 days', + '{"productor": "Finca Santa Rita", "variedad": "Caturra Rojo", "lote_productor": "2024-11-G", "altura_msnm": 1500}'::jsonb) + RETURNING id INTO op_ingreso_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-UVA-001', 'uva', NOW() - INTERVAL '17 days', 2650, + '{"variedad": "Caturra Rojo", "procedencia": "Finca Santa Rita", "altura_msnm": 1500}'::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', 2650); + + -- Despulpado + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('despulpado', NOW() - INTERVAL '16 days', '{"pila": 2, "operador": "Fernando Cruz"}'::jsonb) + RETURNING id INTO op_despulpado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '16 days', 1920, '{"calidad": "A"}'::jsonb) + RETURNING id INTO lote_prim_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-SEG-001', 'despulpado_segunda', NOW() - INTERVAL '16 days', 530, '{"calidad": "B"}'::jsonb) + RETURNING id INTO lote_seg_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-RECH-001', 'despulpado_rechazos', NOW() - INTERVAL '16 days', 200, '{"destino": "compost"}'::jsonb) + RETURNING id INTO lote_rech_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_despulpado_id, lote_uva_id, 'input', 2650), + (op_despulpado_id, lote_prim_id, 'output', 1920), + (op_despulpado_id, lote_seg_id, 'output', 530), + (op_despulpado_id, lote_rech_id, 'output', 200); + + -- Oreado + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('oreado', NOW() - INTERVAL '15 days', '{"patio": 3, "humedad_inicial": 56, "humedad_final": 45, "horas": 12}'::jsonb) + RETURNING id INTO op_oreado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-ORE-001', 'oreado', NOW() - INTERVAL '15 days', 1880, '{"humedad": 45}'::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', 1920), (op_oreado_id, lote_ore_id, 'output', 1880); + + -- Presecado + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('presecado', NOW() - INTERVAL '12 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 ('SRT-PRE-001', 'presecado', NOW() - INTERVAL '12 days', 1845, '{"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', 1880), (op_presecado_id, lote_pre_id, 'output', 1845); + + -- Reposo + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('reposo', NOW() - INTERVAL '9 days', '{"bodega": "B", "estante": 3, "dias_reposo": 7}'::jsonb) + RETURNING id INTO op_reposo_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-REP-001', 'reposo', NOW() - INTERVAL '9 days', 1840, '{"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', 1845), (op_reposo_id, lote_rep_id, 'output', 1840); + + -- División en 3 partes + RAISE NOTICE 'FLUJO 6: Dividiendo lote Santa Rita en 3 partes...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('mezcla', NOW() - INTERVAL '6 days', + '{"operacion": "División por calidad", "motivo": "Separar para diferentes mercados"}'::jsonb) + RETURNING id INTO op_division_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-REP-001A', 'reposo', NOW() - INTERVAL '6 days', 920, '{"parte": "A Premium"}'::jsonb) + RETURNING id INTO lote_div1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-REP-001B', 'reposo', NOW() - INTERVAL '6 days', 600, '{"parte": "B Especial"}'::jsonb) + RETURNING id INTO lote_div2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SRT-REP-001C', 'reposo', NOW() - INTERVAL '6 days', 320, '{"parte": "C Estándar"}'::jsonb) + RETURNING id INTO lote_div3_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_division_id, lote_rep_id, 'input', 1840), + (op_division_id, lote_div1_id, 'output', 920), + (op_division_id, lote_div2_id, 'output', 600), + (op_division_id, lote_div3_id, 'output', 320); + + -- Secado 1: Premium + Especial + RAISE NOTICE 'FLUJO 6: Secado Premium (A+B)...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('secado', NOW() - INTERVAL '3 days', + '{"secadora": "Solar 1", "temperatura_max": 46, "dias": 7, "humedad_final": 11.4}'::jsonb) + RETURNING id INTO op_secado1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SEC-SRT-PREM-001', 'secado', NOW() - INTERVAL '3 days', 1508, + '{"origen": "Santa Rita Premium", "humedad_final": 11.4, "calidad": "Pergamino Premium"}'::jsonb) + RETURNING id INTO lote_sec1_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_secado1_id, lote_div1_id, 'input', 920), + (op_secado1_id, lote_div2_id, 'input', 600), + (op_secado1_id, lote_sec1_id, 'output', 1508); + + -- Secado 2: Estándar + RAISE NOTICE 'FLUJO 6: Secado Estándar (C)...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('secado', NOW() - INTERVAL '3 days', + '{"secadora": "Solar 3", "temperatura_max": 48, "dias": 6, "humedad_final": 11.8}'::jsonb) + RETURNING id INTO op_secado2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SEC-SRT-STD-001', 'secado', NOW() - INTERVAL '3 days', 316, + '{"origen": "Santa Rita Estándar", "humedad_final": 11.8, "calidad": "Pergamino Estándar"}'::jsonb) + RETURNING id INTO lote_sec2_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_secado2_id, lote_div3_id, 'input', 320), (op_secado2_id, lote_sec2_id, 'output', 316); + +END $$; + + +-- ===================================================== +-- FLUJO 7: TRIPLE MEZCLA (TRINIDAD + SAN JOSÉ + VILLA ROSA) → SECADO PREMIUM PLUS +-- ===================================================== + +DO $$ +DECLARE + -- Declaraciones para 3 fincas completas + op_ing1_id UUID; op_desp1_id UUID; op_ore1_id UUID; op_pre1_id UUID; op_rep1_id UUID; + lote_uva1_id UUID; lote_prim1_id UUID; lote_ore1_id UUID; lote_pre1_id UUID; lote_rep1_id UUID; + + op_ing2_id UUID; op_desp2_id UUID; op_ore2_id UUID; op_pre2_id UUID; op_rep2_id UUID; + lote_uva2_id UUID; lote_prim2_id UUID; lote_ore2_id UUID; lote_pre2_id UUID; lote_rep2_id UUID; + + op_ing3_id UUID; op_desp3_id UUID; op_ore3_id UUID; op_pre3_id UUID; op_rep3_id UUID; + lote_uva3_id UUID; lote_prim3_id UUID; lote_ore3_id UUID; lote_pre3_id UUID; lote_rep3_id UUID; + + op_mezcla1_id UUID; op_mezcla2_id UUID; op_secado_id UUID; + lote_mezcla1_id UUID; lote_mezcla2_id UUID; lote_secado_id UUID; +BEGIN + RAISE NOTICE 'FLUJO 7: La Trinidad (Bourbon) - procesamiento...'; + + -- Finca 1: La Trinidad (Bourbon) + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '16 days', + '{"productor": "Finca La Trinidad", "variedad": "Bourbon Rojo", "lote_productor": "2024-11-H", "altura_msnm": 1550}'::jsonb) + RETURNING id INTO op_ing1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('TRI-UVA-001', 'uva', NOW() - INTERVAL '16 days', 1420, + '{"variedad": "Bourbon Rojo", "procedencia": "Finca La Trinidad"}'::jsonb) + RETURNING id INTO lote_uva1_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_ing1_id, lote_uva1_id, 'output', 1420); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('despulpado', NOW() - INTERVAL '15 days', '{}'::jsonb) RETURNING id INTO op_desp1_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('TRI-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '15 days', 1050, '{}'::jsonb) RETURNING id INTO lote_prim1_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_desp1_id, lote_uva1_id, 'input', 1420), (op_desp1_id, lote_prim1_id, 'output', 1050); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('oreado', NOW() - INTERVAL '14 days', '{}'::jsonb) RETURNING id INTO op_ore1_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('TRI-ORE-001', 'oreado', NOW() - INTERVAL '14 days', 1030, '{}'::jsonb) RETURNING id INTO lote_ore1_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_ore1_id, lote_prim1_id, 'input', 1050), (op_ore1_id, lote_ore1_id, 'output', 1030); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('presecado', NOW() - INTERVAL '11 days', '{}'::jsonb) RETURNING id INTO op_pre1_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('TRI-PRE-001', 'presecado', NOW() - INTERVAL '11 days', 1010, '{}'::jsonb) RETURNING id INTO lote_pre1_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_pre1_id, lote_ore1_id, 'input', 1030), (op_pre1_id, lote_pre1_id, 'output', 1010); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('reposo', NOW() - INTERVAL '8 days', '{}'::jsonb) RETURNING id INTO op_rep1_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('TRI-REP-001', 'reposo', NOW() - INTERVAL '8 days', 1005, '{}'::jsonb) RETURNING id INTO lote_rep1_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_rep1_id, lote_pre1_id, 'input', 1010), (op_rep1_id, lote_rep1_id, 'output', 1005); + + -- Finca 2: San José (Typica) + RAISE NOTICE 'FLUJO 7: San José (Typica) - procesamiento...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '15 days', + '{"productor": "Finca San José", "variedad": "Typica", "lote_productor": "2024-11-I"}'::jsonb) + RETURNING id INTO op_ing2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SJO-UVA-001', 'uva', NOW() - INTERVAL '15 days', 1180, '{"variedad": "Typica"}'::jsonb) + RETURNING id INTO lote_uva2_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_ing2_id, lote_uva2_id, 'output', 1180); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('despulpado', NOW() - INTERVAL '14 days', '{}'::jsonb) RETURNING id INTO op_desp2_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('SJO-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '14 days', 870, '{}'::jsonb) RETURNING id INTO lote_prim2_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_desp2_id, lote_uva2_id, 'input', 1180), (op_desp2_id, lote_prim2_id, 'output', 870); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('oreado', NOW() - INTERVAL '13 days', '{}'::jsonb) RETURNING id INTO op_ore2_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('SJO-ORE-001', 'oreado', NOW() - INTERVAL '13 days', 852, '{}'::jsonb) RETURNING id INTO lote_ore2_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_ore2_id, lote_prim2_id, 'input', 870), (op_ore2_id, lote_ore2_id, 'output', 852); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('presecado', NOW() - INTERVAL '10 days', '{}'::jsonb) RETURNING id INTO op_pre2_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('SJO-PRE-001', 'presecado', NOW() - INTERVAL '10 days', 835, '{}'::jsonb) RETURNING id INTO lote_pre2_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_pre2_id, lote_ore2_id, 'input', 852), (op_pre2_id, lote_pre2_id, 'output', 835); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('reposo', NOW() - INTERVAL '7 days', '{}'::jsonb) RETURNING id INTO op_rep2_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('SJO-REP-001', 'reposo', NOW() - INTERVAL '7 days', 830, '{}'::jsonb) RETURNING id INTO lote_rep2_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_rep2_id, lote_pre2_id, 'input', 835), (op_rep2_id, lote_rep2_id, 'output', 830); + + -- Finca 3: Villa Rosa (Caturra) + RAISE NOTICE 'FLUJO 7: Villa Rosa (Caturra) - procesamiento...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('ingreso', NOW() - INTERVAL '14 days', + '{"productor": "Finca Villa Rosa", "variedad": "Caturra Amarillo", "lote_productor": "2024-11-J"}'::jsonb) + RETURNING id INTO op_ing3_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('VRS-UVA-001', 'uva', NOW() - INTERVAL '14 days', 1600, '{"variedad": "Caturra Amarillo"}'::jsonb) + RETURNING id INTO lote_uva3_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_ing3_id, lote_uva3_id, 'output', 1600); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('despulpado', NOW() - INTERVAL '13 days', '{}'::jsonb) RETURNING id INTO op_desp3_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('VRS-PRIM-001', 'despulpado_primera', NOW() - INTERVAL '13 days', 1180, '{}'::jsonb) RETURNING id INTO lote_prim3_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_desp3_id, lote_uva3_id, 'input', 1600), (op_desp3_id, lote_prim3_id, 'output', 1180); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('oreado', NOW() - INTERVAL '12 days', '{}'::jsonb) RETURNING id INTO op_ore3_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('VRS-ORE-001', 'oreado', NOW() - INTERVAL '12 days', 1158, '{}'::jsonb) RETURNING id INTO lote_ore3_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_ore3_id, lote_prim3_id, 'input', 1180), (op_ore3_id, lote_ore3_id, 'output', 1158); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('presecado', NOW() - INTERVAL '9 days', '{}'::jsonb) RETURNING id INTO op_pre3_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('VRS-PRE-001', 'presecado', NOW() - INTERVAL '9 days', 1135, '{}'::jsonb) RETURNING id INTO lote_pre3_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_pre3_id, lote_ore3_id, 'input', 1158), (op_pre3_id, lote_pre3_id, 'output', 1135); + + INSERT INTO operaciones (tipo, fecha, meta) VALUES ('reposo', NOW() - INTERVAL '6 days', '{}'::jsonb) RETURNING id INTO op_rep3_id; + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) VALUES ('VRS-REP-001', 'reposo', NOW() - INTERVAL '6 days', 1130, '{}'::jsonb) RETURNING id INTO lote_rep3_id; + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) VALUES (op_rep3_id, lote_pre3_id, 'input', 1135), (op_rep3_id, lote_rep3_id, 'output', 1130); + + -- Mezcla nivel 1: Trinidad + San José + RAISE NOTICE 'FLUJO 7: Mezcla nivel 1 (Trinidad + San José)...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('mezcla', NOW() - INTERVAL '4 days', '{"nombre_mezcla": "Bourbon-Typica Blend", "nivel": 1}'::jsonb) + RETURNING id INTO op_mezcla1_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('MIX-BT-001', 'reposo', NOW() - INTERVAL '4 days', 1835, '{"mezcla": "Bourbon + Typica"}'::jsonb) + RETURNING id INTO lote_mezcla1_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_mezcla1_id, lote_rep1_id, 'input', 1005), + (op_mezcla1_id, lote_rep2_id, 'input', 830), + (op_mezcla1_id, lote_mezcla1_id, 'output', 1835); + + -- Mezcla nivel 2: (Trinidad+San José) + Villa Rosa = Triple blend + RAISE NOTICE 'FLUJO 7: Mezcla nivel 2 - Triple Blend final...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('mezcla', NOW() - INTERVAL '2 days', + '{"nombre_mezcla": "Triple Blend Premium Plus", "perfil": "Complejo balanceado", "nivel": 2}'::jsonb) + RETURNING id INTO op_mezcla2_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('TRIPLE-REP-001', 'reposo', NOW() - INTERVAL '2 days', 2965, + '{"mezcla": "Bourbon + Typica + Caturra", "perfil": "Triple origen Premium"}'::jsonb) + RETURNING id INTO lote_mezcla2_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_mezcla2_id, lote_mezcla1_id, 'input', 1835), + (op_mezcla2_id, lote_rep3_id, 'input', 1130), + (op_mezcla2_id, lote_mezcla2_id, 'output', 2965); + + -- Secado Premium Plus + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('secado', NOW() - INTERVAL '18 hours', + '{"secadora": "Solar Premium", "temperatura_max": 44, "dias": 9, "humedad_final": 11.0, "proceso": "Secado ultra controlado"}'::jsonb) + RETURNING id INTO op_secado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SEC-TRIPLE-001', 'secado', NOW() - INTERVAL '18 hours', 2935, + '{"origen": "Triple Blend Premium Plus", "humedad_final": 11.0, "calidad": "Pergamino Ultra Premium", "notas": "Balance perfecto multi-origen"}'::jsonb) + RETURNING id INTO lote_secado_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_secado_id, lote_mezcla2_id, 'input', 2965), (op_secado_id, lote_secado_id, 'output', 2935); + +END $$; + + +-- ===================================================== +-- FLUJO 8: MEZCLA DE SEGUNDAS CALIDADES → SECADO COMERCIAL +-- ===================================================== + +DO $$ +DECLARE + op_mezcla_id UUID; + op_oreado_id UUID; + op_presecado_id UUID; + op_secado_id UUID; + + lote_seg1_id UUID; lote_seg2_id UUID; lote_seg3_id UUID; lote_seg4_id UUID; + lote_mezcla_id UUID; lote_ore_id UUID; lote_pre_id UUID; lote_secado_id UUID; +BEGIN + RAISE NOTICE 'FLUJO 8: Recuperando segundas calidades de flujos anteriores...'; + + -- Obtener lotes de segunda de flujos anteriores + SELECT id INTO STRICT lote_seg1_id FROM lotes WHERE codigo = 'ESP-SEG-001' LIMIT 1; + SELECT id INTO STRICT lote_seg2_id FROM lotes WHERE codigo = 'PED-SEG-001' LIMIT 1; + SELECT id INTO STRICT lote_seg3_id FROM lotes WHERE codigo = 'COOP-SEG-001' LIMIT 1; + SELECT id INTO STRICT lote_seg4_id FROM lotes WHERE codigo = 'SRT-SEG-001' LIMIT 1; + + -- Mezcla de segundas + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('mezcla', NOW() - INTERVAL '10 days', + '{"nombre_mezcla": "Blend Comercial", "origen": "Segundas calidades mixtas", "nivel": 1}'::jsonb) + RETURNING id INTO op_mezcla_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('COMERCIAL-SEG-001', 'despulpado_segunda', NOW() - INTERVAL '10 days', 1585, + '{"mezcla": "Segundas combinadas", "destino": "Comercial"}'::jsonb) + RETURNING id INTO lote_mezcla_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES + (op_mezcla_id, lote_seg1_id, 'input', 350), + (op_mezcla_id, lote_seg2_id, 'input', 280), + (op_mezcla_id, lote_seg3_id, 'input', 450), + (op_mezcla_id, lote_seg4_id, 'input', 530), + (op_mezcla_id, lote_mezcla_id, 'output', 1585); + + -- Oreado + RAISE NOTICE 'FLUJO 8: Procesando mezcla comercial...'; + + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('oreado', NOW() - INTERVAL '9 days', '{"patio": 4, "humedad_inicial": 60, "humedad_final": 48, "horas": 10}'::jsonb) + RETURNING id INTO op_oreado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('COMERCIAL-ORE-001', 'oreado', NOW() - INTERVAL '9 days', 1545, '{"humedad": 48}'::jsonb) + RETURNING id INTO lote_ore_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_oreado_id, lote_mezcla_id, 'input', 1585), (op_oreado_id, lote_ore_id, 'output', 1545); + + -- Presecado + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('presecado', NOW() - INTERVAL '6 days', '{"secadora": "Solar 4", "temperatura_max": 45, "dias": 3}'::jsonb) + RETURNING id INTO op_presecado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('COMERCIAL-PRE-001', 'presecado', NOW() - INTERVAL '6 days', 1515, '{"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', 1545), (op_presecado_id, lote_pre_id, 'output', 1515); + + -- Secado Comercial + INSERT INTO operaciones (tipo, fecha, meta) + VALUES ('secado', NOW() - INTERVAL '2 days', + '{"secadora": "Solar 4", "temperatura_max": 50, "dias": 5, "humedad_final": 12.0}'::jsonb) + RETURNING id INTO op_secado_id; + + INSERT INTO lotes (codigo, tipo, fecha_creado, cantidad_kg, meta) + VALUES ('SEC-COMERCIAL-001', 'secado', NOW() - INTERVAL '2 days', 1485, + '{"origen": "Blend Comercial", "humedad_final": 12.0, "calidad": "Pergamino Comercial", "destino": "Mercado local"}'::jsonb) + RETURNING id INTO lote_secado_id; + + INSERT INTO operacion_lotes (operacion_id, lote_id, rol, cantidad_kg) + VALUES (op_secado_id, lote_pre_id, 'input', 1515), (op_secado_id, lote_secado_id, 'output', 1485); + +END $$; + + -- ===================================================== -- RESUMEN DE DATOS CREADOS -- ===================================================== @@ -641,22 +1250,28 @@ BEGIN 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 ' • % lotes creados (15+ fincas + procesamiento completo)', total_lotes; + RAISE NOTICE ' • % operaciones (ingreso → secado con mezclas multinivel)', 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 'Flujos principales (8 grafos complejos):'; + RAISE NOTICE ' 1-4. Flujos iniciales con mezclas (SEC-PREMIUM-001-CORR, SEC-COOP-001)'; + RAISE NOTICE ' 5. Las Nubes + El Paraíso → Blend Exótico → SEC-EXOTIC-001'; + RAISE NOTICE ' 6. Santa Rita → División 3 partes → SEC-SRT-PREM-001 + SEC-SRT-STD-001'; + RAISE NOTICE ' 7. Trinidad + San José + Villa Rosa → Triple Blend → SEC-TRIPLE-001'; + RAISE NOTICE ' 8. Segundas calidades mixtas → SEC-COMERCIAL-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 'Lotes finales (sin hijos) con trazabilidad compleja:'; + RAISE NOTICE ' • SEC-PREMIUM-001-CORR: 3 fincas (Roble+Esperanza+Pedro) - 6 niveles'; + RAISE NOTICE ' • SEC-COOP-001: Cooperativa Sur individual'; + RAISE NOTICE ' • SEC-EXOTIC-001: Geisha + Castillo - Premium Exótico'; + RAISE NOTICE ' • SEC-SRT-PREM-001: Santa Rita Premium (partes A+B)'; + RAISE NOTICE ' • SEC-SRT-STD-001: Santa Rita Estándar (parte C)'; + RAISE NOTICE ' • SEC-TRIPLE-001: Triple origen - Ultra Premium'; + RAISE NOTICE ' • SEC-COMERCIAL-001: Blend segundas calidades'; 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 'Consultar trazabilidad completa de cualquier lote final:'; + RAISE NOTICE ' SELECT * FROM get_trazabilidad((SELECT id FROM lotes WHERE codigo = ''SEC-TRIPLE-001''));'; RAISE NOTICE '═══════════════════════════════════════════════════════'; RAISE NOTICE ''; END $$; diff --git a/nuxt4/server/utils/queries.ts b/nuxt4/server/utils/queries.ts index fc127b6..9450762 100644 --- a/nuxt4/server/utils/queries.ts +++ b/nuxt4/server/utils/queries.ts @@ -58,6 +58,7 @@ export async function getLotes(filtros?: { tipo?: string limit?: number offset?: number + soloFinales?: boolean }): Promise { let sql = 'SELECT * FROM lotes WHERE 1=1' const params: any[] = [] @@ -69,6 +70,15 @@ export async function getLotes(filtros?: { paramCount++ } + // Filtrar solo lotes sin hijos (que no son input de ninguna operación) + if (filtros?.soloFinales) { + sql += ` AND id NOT IN ( + SELECT DISTINCT lote_id + FROM operacion_lotes + WHERE rol = 'input' + )` + } + sql += ' ORDER BY fecha_creado DESC' if (filtros?.limit) {