import { METABASE_QUERIES } from '../../config/metabase-queries' /** * Execute all informe comercios queries in parallel * Returns data for the Informe de Comercios page */ export default defineEventHandler(async (event) => { const body = await readBody(event) const { fecha_desde = null, fecha_hasta = null, incluir_anulados = false, cliente_ids = [], tipos = [], comercio_ids = [], granularidad = 'dia' } = body try { // First, get all cards to find our informe comercios queries const allCards = await getMetabaseCards('all') // Find our informe comercios queries by name using centralized config const queryNames = METABASE_QUERIES.informe_comercios const cards: Record = {} for (const [key, name] of Object.entries(queryNames)) { const card = allCards.find((c: any) => c.name === name) if (!card) { console.warn(`[Informe Comercios] Query not found: ${name}`) } else { cards[key] = card } } // Build parameters array for Metabase queries const buildParameters = (includeGranularidad: boolean = false) => { const params = [ { type: 'text', target: ['variable', ['template-tag', 'fecha_desde']], value: fecha_desde || '' }, { type: 'text', target: ['variable', ['template-tag', 'fecha_hasta']], value: fecha_hasta || '' }, { type: 'boolean', target: ['variable', ['template-tag', 'incluir_anulados']], value: incluir_anulados } ] // Solo agregar filtros opcionales si tienen valores (no vacíos) if (cliente_ids && Array.isArray(cliente_ids) && cliente_ids.length > 0) { params.push({ type: 'number', target: ['variable', ['template-tag', 'cliente_ids']], value: cliente_ids }) } if (tipos && Array.isArray(tipos) && tipos.length > 0) { params.push({ type: 'text', target: ['variable', ['template-tag', 'tipos']], value: tipos }) } if (comercio_ids && Array.isArray(comercio_ids) && comercio_ids.length > 0) { params.push({ type: 'number', target: ['variable', ['template-tag', 'comercio_ids']], value: comercio_ids }) } if (includeGranularidad) { params.push({ type: 'text', target: ['variable', ['template-tag', 'granularidad']], value: granularidad }) } return params } const standardParams = buildParameters(false) const serieTemporalParams = buildParameters(true) const emptyParams: any[] = [] // Para opciones_filtros que no requiere parámetros // Execute all queries in parallel with error handling const executeWithErrorHandling = async (name: string, cardId: number | undefined, parameters: any[], defaultValue: any) => { if (!cardId) { console.warn(`[Informe Comercios] No card ID for ${name}`) return defaultValue } try { console.log(`[Informe Comercios] Executing query: ${name} (ID: ${cardId})`) const result = await executeCardQuery(cardId, parameters) console.log(`[Informe Comercios] Query ${name} returned ${result.data?.rows?.length || 0} rows`) return result } catch (error: any) { console.error(`[Informe Comercios] Error executing ${name}:`, error.message) return defaultValue } } const [ listaComercio, totalesMonetarios, totalesPeso, topComercios, serieTemporal, opcionesFiltros, contadores, detalleIngresos ] = await Promise.all([ executeWithErrorHandling('lista_comercios', cards.lista_comercios?.id, standardParams, { data: { rows: [], cols: [] } }), executeWithErrorHandling('totales_monetarios', cards.totales_monetarios?.id, standardParams, { data: { rows: [[]], cols: [] } }), executeWithErrorHandling('totales_peso', cards.totales_peso?.id, standardParams, { data: { rows: [[]], cols: [] } }), executeWithErrorHandling('top_comercios', cards.top_comercios?.id, standardParams, { data: { rows: [], cols: [] } }), executeWithErrorHandling('serie_temporal', cards.serie_temporal?.id, serieTemporalParams, { data: { rows: [], cols: [] } }), executeWithErrorHandling('opciones_filtros', cards.opciones_filtros?.id, emptyParams, { data: { rows: [[]], cols: [] } }), executeWithErrorHandling('contadores', cards.contadores?.id, standardParams, { data: { rows: [[]], cols: [] } }), executeWithErrorHandling('detalle_ingresos', cards.detalle_ingresos?.id, standardParams, { data: { rows: [], cols: [] } }) ]) // Transform Metabase responses to objects for easier frontend consumption const transformSingleRow = (result: any) => { if (!result.data?.rows?.[0] || !result.data?.cols) return {} const row = result.data.rows[0] const cols = result.data.cols const obj: any = {} cols.forEach((col: any, index: number) => { obj[col.name] = row[index] }) return obj } const transformMultipleRows = (result: any) => { if (!result.data?.rows || !result.data?.cols) return [] const cols = result.data.cols return result.data.rows.map((row: any[]) => { const obj: any = {} cols.forEach((col: any, index: number) => { obj[col.name] = row[index] }) return obj }) } // Return all data in a structured format return { listaComercio: transformMultipleRows(listaComercio), totalesMonetarios: transformSingleRow(totalesMonetarios), totalesPeso: transformSingleRow(totalesPeso), topComercios: transformMultipleRows(topComercios), serieTemporal: transformMultipleRows(serieTemporal), opcionesFiltros: transformSingleRow(opcionesFiltros), contadores: transformSingleRow(contadores), detalleIngresos: transformMultipleRows(detalleIngresos) } } catch (error: any) { console.error('[API] Failed to execute informe comercios queries:', error) throw createError({ statusCode: error.statusCode || 500, statusMessage: error.statusMessage || 'Failed to execute informe comercios queries' }) } })