Las queries de Metabase tienen fecha_desde y fecha_hasta como parametros requeridos con valores por defecto. Cuando se envia null, Metabase rechaza la query. Ahora usamos los defaults cuando no se especifican fechas.
147 lines
5.3 KiB
TypeScript
147 lines
5.3 KiB
TypeScript
/**
|
|
* Execute all panorama queries in parallel
|
|
* Returns data for the Panorama Facturador page
|
|
*/
|
|
export default defineEventHandler(async (event) => {
|
|
const body = await readBody(event)
|
|
|
|
const { fecha_desde = null, fecha_hasta = null, incluir_anulados = false } = body
|
|
|
|
try {
|
|
// First, get all cards to find our panorama queries
|
|
const allCards = await getMetabaseCards('all')
|
|
|
|
// Find our panorama queries by name
|
|
const queryNames = [
|
|
'panorama_totales_financieros_principales',
|
|
'panorama_totales_ingreso_compra',
|
|
'panorama_totales_monetarios',
|
|
'panorama_totales_verde',
|
|
'panorama_secos_vendidos',
|
|
'panorama_rechazos_subproductos',
|
|
'panorama_serie_temporal_diaria',
|
|
'panorama_top_clientes',
|
|
'panorama_conteo_registros'
|
|
]
|
|
|
|
const cards: Record<string, any> = {}
|
|
|
|
for (const name of queryNames) {
|
|
const card = allCards.find((c: any) => c.name === name)
|
|
if (!card) {
|
|
console.warn(`[Panorama] Query not found: ${name}`)
|
|
} else {
|
|
cards[name] = card
|
|
}
|
|
}
|
|
|
|
// Build parameters array for Metabase queries
|
|
// IMPORTANTE: Si los parámetros son null, usar los valores por defecto de Metabase
|
|
// En este caso, las queries usan los defaults: fecha_desde="2025-09-10", fecha_hasta="2025-10-14"
|
|
const parameters = [
|
|
{
|
|
type: 'date/single',
|
|
target: ['variable', ['template-tag', 'fecha_desde']],
|
|
value: fecha_desde || '2025-09-10' // Usar default si es null
|
|
},
|
|
{
|
|
type: 'date/single',
|
|
target: ['variable', ['template-tag', 'fecha_hasta']],
|
|
value: fecha_hasta || '2025-10-14' // Usar default si es null
|
|
},
|
|
{
|
|
type: 'category',
|
|
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(`[Panorama] No card ID for ${name}`)
|
|
return defaultValue
|
|
}
|
|
|
|
try {
|
|
console.log(`[Panorama] Executing query: ${name} (ID: ${cardId})`)
|
|
const result = await executeCardQuery(cardId, parameters)
|
|
console.log(`[Panorama] Query ${name} returned ${result.data?.rows?.length || 0} rows`)
|
|
return result
|
|
} catch (error: any) {
|
|
console.error(`[Panorama] Error executing ${name}:`, error.message)
|
|
return defaultValue
|
|
}
|
|
}
|
|
|
|
const [
|
|
financieros,
|
|
ingresoCompra,
|
|
monetarios,
|
|
verde,
|
|
secosVendidos,
|
|
rechazos,
|
|
serieTemporal,
|
|
topClientes,
|
|
conteos
|
|
] = await Promise.all([
|
|
executeWithErrorHandling('financieros', cards['panorama_totales_financieros_principales']?.id, { data: { rows: [[0, 0, 0]], cols: [] } }),
|
|
executeWithErrorHandling('ingresoCompra', cards['panorama_totales_ingreso_compra']?.id, { data: { rows: [[]], cols: [] } }),
|
|
executeWithErrorHandling('monetarios', cards['panorama_totales_monetarios']?.id, { data: { rows: [[]], cols: [] } }),
|
|
executeWithErrorHandling('verde', cards['panorama_totales_verde']?.id, { data: { rows: [[]], cols: [] } }),
|
|
executeWithErrorHandling('secosVendidos', cards['panorama_secos_vendidos']?.id, { data: { rows: [[]], cols: [] } }),
|
|
executeWithErrorHandling('rechazos', cards['panorama_rechazos_subproductos']?.id, { data: { rows: [], cols: [] } }),
|
|
executeWithErrorHandling('serieTemporal', cards['panorama_serie_temporal_diaria']?.id, { data: { rows: [], cols: [] } }),
|
|
executeWithErrorHandling('topClientes', cards['panorama_top_clientes']?.id, { data: { rows: [], cols: [] } }),
|
|
executeWithErrorHandling('conteos', cards['panorama_conteo_registros']?.id, { data: { rows: [[0, 0, 0, 0]], 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 {
|
|
financieros: transformSingleRow(financieros),
|
|
ingresoCompra: transformSingleRow(ingresoCompra),
|
|
monetarios: transformSingleRow(monetarios),
|
|
verde: transformSingleRow(verde),
|
|
secosVendidos: transformSingleRow(secosVendidos),
|
|
rechazos: transformMultipleRows(rechazos),
|
|
serieTemporal: transformMultipleRows(serieTemporal),
|
|
topClientes: transformMultipleRows(topClientes),
|
|
conteos: transformSingleRow(conteos)
|
|
}
|
|
} catch (error: any) {
|
|
console.error('[API] Failed to execute panorama queries:', error)
|
|
throw createError({
|
|
statusCode: error.statusCode || 500,
|
|
statusMessage: error.statusMessage || 'Failed to execute panorama queries'
|
|
})
|
|
}
|
|
})
|