diff --git a/nuxt4-app/app/components/MetadatosCard.vue b/nuxt4-app/app/components/MetadatosCard.vue new file mode 100644 index 0000000..b8447c9 --- /dev/null +++ b/nuxt4-app/app/components/MetadatosCard.vue @@ -0,0 +1,162 @@ + + + \ No newline at end of file diff --git a/nuxt4-app/app/pages/metadatos.vue b/nuxt4-app/app/pages/metadatos.vue index e09c7f4..30f054d 100644 --- a/nuxt4-app/app/pages/metadatos.vue +++ b/nuxt4-app/app/pages/metadatos.vue @@ -70,41 +70,11 @@
- - - -
-
-
Clave primaria
-
{{ meta.primaryKey || '—' }}
-
-
-
Tamaño aprox.
-
{{ formatSize(meta.approxSizeBytes) }}
-
-
-
Creación desde
-
{{ formatDate(meta.createdAtRange?.from) }}
-
-
-
Creación hasta
-
{{ formatDate(meta.createdAtRange?.to) }}
-
-
- - -
+
@@ -182,24 +152,6 @@ function formatSize(bytes: number | null | undefined): string { return `${size.toFixed(1)} ${units[unitIndex]}` } -function formatDate(value: string | null | undefined): string { - if (!value) { - return '—' - } - - const date = new Date(value) - - if (Number.isNaN(date.getTime())) { - return value - } - - return date.toLocaleString('es-ES', { - year: 'numeric', - month: 'short', - day: 'numeric' - }) -} - function formatNumber(value: number): string { return new Intl.NumberFormat('es-ES').format(value) } diff --git a/nuxt4-app/server/data-sources/anticipos/config.ts b/nuxt4-app/server/data-sources/anticipos/config.ts index 077779d..5f03041 100644 --- a/nuxt4-app/server/data-sources/anticipos/config.ts +++ b/nuxt4-app/server/data-sources/anticipos/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const anticiposConfig: TableConfig = { + name: 'anticipos', table: 'anticipos', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/asistencias/config.ts b/nuxt4-app/server/data-sources/asistencias/config.ts index 7831449..4c2d57d 100644 --- a/nuxt4-app/server/data-sources/asistencias/config.ts +++ b/nuxt4-app/server/data-sources/asistencias/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const asistenciasConfig: TableConfig = { + name: 'asistencias', table: 'asistencias', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/carretas/config.ts b/nuxt4-app/server/data-sources/carretas/config.ts index 7f6c49e..16290b0 100644 --- a/nuxt4-app/server/data-sources/carretas/config.ts +++ b/nuxt4-app/server/data-sources/carretas/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const carretasConfig: TableConfig = { + name: 'carretas', table: 'carretas', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/clientes/config.ts b/nuxt4-app/server/data-sources/clientes/config.ts index 2b6ad92..7dd14dc 100644 --- a/nuxt4-app/server/data-sources/clientes/config.ts +++ b/nuxt4-app/server/data-sources/clientes/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const clientesConfig: TableConfig = { + name: 'clientes', table: 'clientes', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/comercios/config.ts b/nuxt4-app/server/data-sources/comercios/config.ts index 66e0666..c397b96 100644 --- a/nuxt4-app/server/data-sources/comercios/config.ts +++ b/nuxt4-app/server/data-sources/comercios/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const comerciosConfig: TableConfig = { + name: 'comercios', table: 'comercios', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/cupones/config.ts b/nuxt4-app/server/data-sources/cupones/config.ts index 4204b4a..270eaab 100644 --- a/nuxt4-app/server/data-sources/cupones/config.ts +++ b/nuxt4-app/server/data-sources/cupones/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const cuponesConfig: TableConfig = { + name: 'cupones', table: 'cupones', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/depositos/config.ts b/nuxt4-app/server/data-sources/depositos/config.ts index 02941a6..15f2f5d 100644 --- a/nuxt4-app/server/data-sources/depositos/config.ts +++ b/nuxt4-app/server/data-sources/depositos/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const depositosConfig: TableConfig = { + name: 'depositos', table: 'depositos', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/index.ts b/nuxt4-app/server/data-sources/index.ts index dc591ab..dc17ad6 100644 --- a/nuxt4-app/server/data-sources/index.ts +++ b/nuxt4-app/server/data-sources/index.ts @@ -8,7 +8,11 @@ import { depositosConfig } from './depositos/config' import { ingresosConfig } from './ingresos/config' import { pagosAnticipoConfig } from './pagos_anticipo/config' import { rechazosConfig } from './rechazos/config' +import { retencionesConfig } from './retenciones/config' +import { salidasConfig } from './salidas/config' import { tareasRealizadasConfig } from './tareas_realizadas/config' +import { vistaResumenIngresosConfig } from './vista_resumen_ingresos/config' +import { vistaResumenIngresosPorComercioConfig } from './vista_resumen_ingresos_por_comercio/config' import type { TableConfig, TableName } from './types' export const tableConfigs: Record = { @@ -22,7 +26,11 @@ export const tableConfigs: Record = { ingresos: ingresosConfig, pagos_anticipo: pagosAnticipoConfig, rechazos: rechazosConfig, - tareas_realizadas: tareasRealizadasConfig + retenciones: retencionesConfig, + salidas: salidasConfig, + tareas_realizadas: tareasRealizadasConfig, + vista_resumen_ingresos: vistaResumenIngresosConfig, + vista_resumen_ingresos_por_comercio: vistaResumenIngresosPorComercioConfig } export const tableNames = Object.keys(tableConfigs) as TableName[] diff --git a/nuxt4-app/server/data-sources/ingresos/config.ts b/nuxt4-app/server/data-sources/ingresos/config.ts index 5ee58d5..53a9d4a 100644 --- a/nuxt4-app/server/data-sources/ingresos/config.ts +++ b/nuxt4-app/server/data-sources/ingresos/config.ts @@ -1,6 +1,8 @@ import type { TableConfig } from '../types' export const ingresosConfig: TableConfig = { - table: 'ingresos', - primaryKey: 'id' + name: 'ingresos', + table: 'vista_detalle_ingresos', + primaryKey: 'id', + description: 'Datos provenientes de la vista: vista_detalle_ingresos' } diff --git a/nuxt4-app/server/data-sources/pagos_anticipo/config.ts b/nuxt4-app/server/data-sources/pagos_anticipo/config.ts index 7e04173..bced624 100644 --- a/nuxt4-app/server/data-sources/pagos_anticipo/config.ts +++ b/nuxt4-app/server/data-sources/pagos_anticipo/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const pagosAnticipoConfig: TableConfig = { + name: 'pagos_anticipo', table: 'pagos_anticipo', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/rechazos/config.ts b/nuxt4-app/server/data-sources/rechazos/config.ts index bf57179..e07cfdf 100644 --- a/nuxt4-app/server/data-sources/rechazos/config.ts +++ b/nuxt4-app/server/data-sources/rechazos/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const rechazosConfig: TableConfig = { + name: 'rechazos', table: 'rechazos', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/retenciones/config.ts b/nuxt4-app/server/data-sources/retenciones/config.ts new file mode 100644 index 0000000..d162134 --- /dev/null +++ b/nuxt4-app/server/data-sources/retenciones/config.ts @@ -0,0 +1,7 @@ +import type { TableConfig } from '../types' + +export const retencionesConfig: TableConfig = { + name: 'retenciones', + table: 'retenciones', + primaryKey: 'id' +} \ No newline at end of file diff --git a/nuxt4-app/server/data-sources/salidas/config.ts b/nuxt4-app/server/data-sources/salidas/config.ts new file mode 100644 index 0000000..cca9e3c --- /dev/null +++ b/nuxt4-app/server/data-sources/salidas/config.ts @@ -0,0 +1,7 @@ +import type { TableConfig } from '../types' + +export const salidasConfig: TableConfig = { + name: 'salidas', + table: 'salidas', + primaryKey: 'id' +} \ No newline at end of file diff --git a/nuxt4-app/server/data-sources/tareas_realizadas/config.ts b/nuxt4-app/server/data-sources/tareas_realizadas/config.ts index c9c229e..9ceafe7 100644 --- a/nuxt4-app/server/data-sources/tareas_realizadas/config.ts +++ b/nuxt4-app/server/data-sources/tareas_realizadas/config.ts @@ -1,6 +1,7 @@ import type { TableConfig } from '../types' export const tareasRealizadasConfig: TableConfig = { + name: 'tareas_realizadas', table: 'tareas_realizadas', primaryKey: 'id' } diff --git a/nuxt4-app/server/data-sources/types.ts b/nuxt4-app/server/data-sources/types.ts index 2a45352..c2981b4 100644 --- a/nuxt4-app/server/data-sources/types.ts +++ b/nuxt4-app/server/data-sources/types.ts @@ -9,17 +9,24 @@ export type TableName = | 'ingresos' | 'pagos_anticipo' | 'rechazos' + | 'retenciones' + | 'salidas' | 'tareas_realizadas' + | 'vista_detalle_ingresos' + | 'vista_resumen_ingresos' + | 'vista_resumen_ingresos_por_comercio' export type TableTransform = { readonly serializeRow?: (row: Record) => Record } export interface TableConfig { - readonly table: TableName + readonly name: string // Nombre de la datasource (ej: 'ingresos') + readonly table: TableName // Nombre de la tabla real (ej: 'vista_detalle_ingresos') readonly primaryKey?: string readonly defaultSelect?: string readonly transforms?: TableTransform + readonly description?: string } export interface QueryFilter { diff --git a/nuxt4-app/server/data-sources/vista_resumen_ingresos/config.ts b/nuxt4-app/server/data-sources/vista_resumen_ingresos/config.ts new file mode 100644 index 0000000..d601ff1 --- /dev/null +++ b/nuxt4-app/server/data-sources/vista_resumen_ingresos/config.ts @@ -0,0 +1,7 @@ +import type { TableConfig } from '../types' + +export const vistaResumenIngresosConfig: TableConfig = { + name: 'vista_resumen_ingresos', + table: 'vista_resumen_ingresos', + primaryKey: 'id' +} \ No newline at end of file diff --git a/nuxt4-app/server/data-sources/vista_resumen_ingresos_por_comercio/config.ts b/nuxt4-app/server/data-sources/vista_resumen_ingresos_por_comercio/config.ts new file mode 100644 index 0000000..418f68d --- /dev/null +++ b/nuxt4-app/server/data-sources/vista_resumen_ingresos_por_comercio/config.ts @@ -0,0 +1,7 @@ +import type { TableConfig } from '../types' + +export const vistaResumenIngresosPorComercioConfig: TableConfig = { + name: 'vista_resumen_ingresos_por_comercio', + table: 'vista_resumen_ingresos_por_comercio', + primaryKey: 'id' +} \ No newline at end of file diff --git a/nuxt4-app/server/services/table-service.ts b/nuxt4-app/server/services/table-service.ts index 5fa077a..ddc6401 100644 --- a/nuxt4-app/server/services/table-service.ts +++ b/nuxt4-app/server/services/table-service.ts @@ -39,6 +39,13 @@ export async function fetchAllTablesMetadata() { tableNames.map((name) => fetchTableMetadata(name)) ) + // Log any errors for debugging + results.forEach((result, index) => { + if (result.status === 'rejected') { + console.error(`Failed to fetch metadata for table ${tableNames[index]}:`, result.reason) + } + }) + return results .filter((result): result is PromiseFulfilledResult>> => result.status === 'fulfilled' @@ -47,66 +54,84 @@ export async function fetchAllTablesMetadata() { } export async function fetchTableMetadata(tableName: string, options?: MetadataOptions) { - const config = getTableConfig(tableName) + try { + const config = getTableConfig(tableName) - if (!config) { - throw createError({ statusCode: 404, statusMessage: `Tabla ${tableName} no encontrada` }) - } + if (!config) { + throw createError({ statusCode: 404, statusMessage: `Tabla ${tableName} no encontrada` }) + } - const supabase = getSupabaseClient() + const supabase = getSupabaseClient() - const baseSelect = config.defaultSelect ?? '*' + const baseSelect = config.defaultSelect ?? '*' - const countPromise = supabase - .from(config.table) - .select(baseSelect, { head: true, count: 'exact' }) - const samplePromise = applyParsedQuery( - supabase.from(config.table).select(baseSelect), - options?.parsedQuery ?? null - ) - .limit(1) + const samplePromise = applyParsedQuery( + supabase.from(config.table).select(baseSelect), + options?.parsedQuery ?? null + ) + .limit(1) - const earliestPromise = supabase - .from(config.table) - .select('created_at') - .order('created_at', { ascending: true }) - .limit(1) + // Try to get created_at range, but don't fail if the column doesn't exist + const earliestPromise = supabase + .from(config.table) + .select('created_at') + .order('created_at', { ascending: true }) + .limit(1) - const latestPromise = supabase - .from(config.table) - .select('created_at') - .order('created_at', { ascending: false }) - .limit(1) + const latestPromise = supabase + .from(config.table) + .select('created_at') + .order('created_at', { ascending: false }) + .limit(1) - const [{ count, error: countError }, { data: sampleData, error: sampleError }, earliest, latest] = - await Promise.all([countPromise, samplePromise, earliestPromise, latestPromise]) + const [sampleResult, earliestResult, latestResult] = + await Promise.all([samplePromise, earliestPromise, latestPromise]) - if (countError) { - throw createError({ statusCode: 500, statusMessage: countError.message }) - } + const { data: sampleData, error: sampleError } = sampleResult - if (sampleError) { - throw createError({ statusCode: 500, statusMessage: sampleError.message }) - } + // Handle created_at queries that may fail for views without this column + const earliest = earliestResult.error ? { data: null } : earliestResult + const latest = latestResult.error ? { data: null } : latestResult - const sampleSet = Array.isArray(sampleData) ? sampleData : [] - const sampleRow = serializeRow(sampleSet[0] ?? null, config) - const columnNames = sampleRow ? Object.keys(sampleRow) : [] - const approxRowSize = sampleRow ? JSON.stringify(sampleRow).length : 0 - const approxSizeBytes = count && approxRowSize ? approxRowSize * count : null + if (sampleError) { + console.error(`Error fetching sample for ${config.table}:`, { + message: sampleError.message, + details: sampleError.details, + hint: sampleError.hint, + code: sampleError.code, + full: sampleError + }) + const errorMsg = sampleError.message || sampleError.hint || sampleError.details || sampleError.code || 'Error desconocido al obtener muestra' + throw createError({ statusCode: 500, statusMessage: errorMsg }) + } - return { - table: config.table, - primaryKey: config.primaryKey ?? 'id', - rowCount: count ?? 0, - approxSizeBytes, - columns: columnNames, - createdAtRange: { - from: earliest.data?.[0]?.created_at ?? null, - to: latest.data?.[0]?.created_at ?? null - }, - sampleRow, - lastRefreshed: new Date().toISOString() + const sampleSet = Array.isArray(sampleData) ? sampleData : [] + const sampleRow = serializeRow(sampleSet[0] ?? null, config) + const columnNames = sampleRow ? Object.keys(sampleRow) : [] + const approxRowSize = sampleRow ? JSON.stringify(sampleRow).length : 0 + const approxSizeBytes = null // We'll calculate this from in-memory data + + return { + name: config.name, + table: config.table, + primaryKey: config.primaryKey ?? 'id', + rowCount: 0, // Will be calculated from in-memory data + approxSizeBytes, + columns: columnNames, + createdAtRange: { + from: earliest.data?.[0]?.created_at ?? null, + to: latest.data?.[0]?.created_at ?? null + }, + sampleRow, + lastRefreshed: new Date().toISOString(), + description: config.description + } + } catch (error: any) { + console.error(`Unexpected error in fetchTableMetadata for ${tableName}:`, error) + throw createError({ + statusCode: 500, + statusMessage: error?.message || error?.toString() || 'Error inesperado al obtener metadatos' + }) } }