diff --git a/nuxt4-app/app/pages/comparativa-cosechas.vue b/nuxt4-app/app/pages/comparativa-cosechas.vue index 2908caa..31157d9 100644 --- a/nuxt4-app/app/pages/comparativa-cosechas.vue +++ b/nuxt4-app/app/pages/comparativa-cosechas.vue @@ -1,15 +1,326 @@ diff --git a/nuxt4-app/server/api/metabase/comparativa-cosechas.post.ts b/nuxt4-app/server/api/metabase/comparativa-cosechas.post.ts new file mode 100644 index 0000000..bdc5b67 --- /dev/null +++ b/nuxt4-app/server/api/metabase/comparativa-cosechas.post.ts @@ -0,0 +1,127 @@ +import { METABASE_QUERIES } from '../../config/metabase-queries' + +/** + * Execute all comparativa cosechas queries in parallel + * Returns data for the Comparativa de Cosechas page + */ +export default defineEventHandler(async (event) => { + const body = await readBody(event) + + const { cosechas_ids = [], incluir_anulados = false } = body + + try { + // First, get all cards to find our comparativa queries + const allCards = await getMetabaseCards('all') + + // Find our comparativa queries by name using centralized config + const queryNames = METABASE_QUERIES.comparativa + + const cards: Record = {} + + console.log('[Comparativa] Available cards:', allCards.map((c: any) => ({ id: c.id, name: c.name }))) + console.log('[Comparativa] Looking for queries:', queryNames) + + for (const [key, name] of Object.entries(queryNames)) { + const card = allCards.find((c: any) => c.name === name) + if (!card) { + console.warn(`[Comparativa] Query not found: ${name}`) + } else { + console.log(`[Comparativa] Found card ${key}: ${name} (ID: ${card.id})`) + cards[key] = card + } + } + + console.log('[Comparativa] Cards to execute:', Object.keys(cards)) + + // Build parameters array for Metabase queries + // Las queries SQL nativas usan template-tags de tipo 'text' para arrays + const parameters = [ + { + type: 'text', + target: ['variable', ['template-tag', 'cosechas_ids']], + value: cosechas_ids + }, + { + type: 'boolean', + target: ['variable', ['template-tag', 'incluir_anulados']], + value: incluir_anulados + } + ] + + // Execute all queries in parallel with error handling + const executeWithErrorHandling = async (name: string, cardId: number | undefined, defaultValue: any) => { + if (!cardId) { + console.warn(`[Comparativa] No card ID for ${name}`) + return defaultValue + } + + try { + console.log(`[Comparativa] Executing query: ${name} (ID: ${cardId}) with params:`, JSON.stringify(parameters)) + const result = await executeCardQuery(cardId, parameters) + console.log(`[Comparativa] Query ${name} result:`, { + hasData: !!result.data, + rowsLength: result.data?.rows?.length || 0, + colsLength: result.data?.cols?.length || 0, + firstRow: result.data?.rows?.[0] || null + }) + return result + } catch (error: any) { + console.error(`[Comparativa] Error executing ${name}:`, error.message, error.stack) + return defaultValue + } + } + + const [ + datosDiariosCompletos, + totalesPorCosecha, + datosAcumuladosPorDia, + metadataCosechas + ] = await Promise.all([ + executeWithErrorHandling('datosDiariosCompletos', cards.datos_diarios_completos?.id, { data: { rows: [], cols: [] } }), + executeWithErrorHandling('totalesPorCosecha', cards.totales_por_cosecha?.id, { data: { rows: [], cols: [] } }), + executeWithErrorHandling('datosAcumuladosPorDia', cards.datos_acumulados_por_dia?.id, { data: { rows: [], cols: [] } }), + executeWithErrorHandling('metadataCosechas', cards.metadata_cosechas?.id, { data: { rows: [], cols: [] } }) + ]) + + // Transform Metabase responses to objects for easier frontend consumption + const transformMultipleRows = (result: any) => { + console.log('[Comparativa] transformMultipleRows input:', { + hasData: !!result.data, + hasRows: !!result.data?.rows, + hasCols: !!result.data?.cols, + rowsLength: result.data?.rows?.length + }) + + if (!result.data?.rows || !result.data?.cols) { + console.warn('[Comparativa] transformMultipleRows: Missing data, rows, or cols') + return [] + } + + const cols = result.data.cols + const transformed = result.data.rows.map((row: any[]) => { + const obj: any = {} + cols.forEach((col: any, index: number) => { + obj[col.name] = row[index] + }) + return obj + }) + + console.log('[Comparativa] transformMultipleRows output:', transformed.length, 'rows') + return transformed + } + + // Return all data in a structured format + return { + datosDiariosCompletos: transformMultipleRows(datosDiariosCompletos), + totalesPorCosecha: transformMultipleRows(totalesPorCosecha), + datosAcumuladosPorDia: transformMultipleRows(datosAcumuladosPorDia), + metadataCosechas: transformMultipleRows(metadataCosechas) + } + } catch (error: any) { + console.error('[API] Failed to execute comparativa queries:', error) + throw createError({ + statusCode: error.statusCode || 500, + statusMessage: error.statusMessage || 'Failed to execute comparativa queries' + }) + } +}) diff --git a/nuxt4-app/server/config/metabase-queries.ts b/nuxt4-app/server/config/metabase-queries.ts index caf6b7e..57287b8 100644 --- a/nuxt4-app/server/config/metabase-queries.ts +++ b/nuxt4-app/server/config/metabase-queries.ts @@ -33,6 +33,16 @@ export const METABASE_QUERIES = { serie_temporal: 'Informe Ingresos - Serie Temporal Acumulada', opciones_filtros: 'Informe Ingresos - Opciones de Filtros', contadores: 'Informe Ingresos - Contadores de Filtros' + }, + + /** + * Queries para Comparativa de Cosechas + */ + comparativa: { + datos_diarios_completos: 'comparativa_datos_diarios_completos', + totales_por_cosecha: 'comparativa_totales_por_cosecha', + datos_acumulados_por_dia: 'comparativa_datos_acumulados_por_dia', + metadata_cosechas: 'comparativa_metadata_cosechas' } } as const @@ -42,3 +52,4 @@ export const METABASE_QUERIES = { export type MetabaseQueryCategory = keyof typeof METABASE_QUERIES export type PanoramaQueryKey = keyof typeof METABASE_QUERIES.panorama export type InformeQueryKey = keyof typeof METABASE_QUERIES.informe +export type ComparativaQueryKey = keyof typeof METABASE_QUERIES.comparativa