import { requireSalesOrAdmin } from '@/server/utils/auth'; import { getExpenses, getCurrentMonthExpenses } from '@/server/utils/nocodb'; import { processExpenseWithCurrency } from '@/server/utils/currency'; import type { ExpenseFilters } from '@/utils/types'; export default defineEventHandler(async (event) => { try { await requireSalesOrAdmin(event); const query = getQuery(event); // If no date filters provided, default to current month if (!query.startDate && !query.endDate) { console.log('[get-expenses] No date filters provided, defaulting to current month'); try { const result = await getCurrentMonthExpenses(); // Process expenses with currency conversion const processedExpenses = await Promise.all( result.list.map((expense: any) => processExpenseWithCurrency(expense)) ); return { ...result, list: processedExpenses }; } catch (dbError: any) { console.error('[get-expenses] Database error (current month):', dbError); if (dbError.statusCode === 403) { throw createError({ statusCode: 503, statusMessage: 'Expense database is currently unavailable. Please contact your administrator or try again later.' }); } throw createError({ statusCode: 500, statusMessage: 'Unable to fetch expense data. Please try again later.' }); } } // Build filters from query parameters const filters: ExpenseFilters = {}; if (query.startDate && typeof query.startDate === 'string') { filters.startDate = query.startDate; } if (query.endDate && typeof query.endDate === 'string') { filters.endDate = query.endDate; } if (query.payer && typeof query.payer === 'string') { filters.payer = query.payer; } if (query.category && typeof query.category === 'string') { filters.category = query.category as any; // Cast to ExpenseCategory } console.log('[get-expenses] Fetching expenses with filters:', filters); try { const result = await getExpenses(filters); // Process expenses with currency conversion const processedExpenses = await Promise.all( result.list.map((expense: any) => processExpenseWithCurrency(expense)) ); // Add formatted dates const transformedExpenses = processedExpenses.map(expense => ({ ...expense, FormattedDate: new Date(expense.Time).toLocaleDateString(), FormattedTime: new Date(expense.Time).toLocaleTimeString() })); // Calculate summary with USD totals const usdTotal = transformedExpenses.reduce((sum, e) => sum + (e.PriceUSD || e.PriceNumber || 0), 0); const originalTotal = transformedExpenses.reduce((sum, e) => sum + (e.PriceNumber || 0), 0); return { expenses: transformedExpenses, PageInfo: result.PageInfo, totalCount: result.PageInfo?.totalRows || transformedExpenses.length, summary: { total: originalTotal, // Original currency total (mixed currencies) totalUSD: usdTotal, // USD converted total count: transformedExpenses.length, uniquePayers: [...new Set(transformedExpenses.map(e => e.Payer))].length, currencies: [...new Set(transformedExpenses.map(e => e.currency))].filter(Boolean) } }; } catch (dbError: any) { console.error('[get-expenses] Database error (filtered):', dbError); if (dbError.statusCode === 403) { throw createError({ statusCode: 503, statusMessage: 'Expense database is currently unavailable. Please contact your administrator or try again later.' }); } throw createError({ statusCode: 500, statusMessage: 'Unable to fetch expense data. Please try again later.' }); } } catch (authError: any) { if (authError.statusCode === 403) { throw createError({ statusCode: 403, statusMessage: 'Access denied. This feature requires sales team or administrator privileges.' }); } throw authError; } });