|
|
|
|
@@ -838,31 +838,40 @@ export const updateBerth = async (id: string, data: Partial<Berth>): Promise<Ber
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Expense functions
|
|
|
|
|
// Expense functions with resilient HTTP handling
|
|
|
|
|
export const getExpenses = async (filters?: ExpenseFilters) => {
|
|
|
|
|
console.log('[nocodb.getExpenses] Fetching expenses from NocoDB...', filters);
|
|
|
|
|
|
|
|
|
|
const startTime = Date.now();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const params: any = { limit: 1000 };
|
|
|
|
|
|
|
|
|
|
// Build filter conditions
|
|
|
|
|
// Build filter conditions (fixed date logic)
|
|
|
|
|
if (filters?.startDate && filters?.endDate) {
|
|
|
|
|
params.where = `(Time,gte,${filters.startDate})~and(Time,lte,${filters.endDate})`;
|
|
|
|
|
// Ensure dates are in YYYY-MM-DD format
|
|
|
|
|
const startDate = filters.startDate.includes('T') ? filters.startDate.split('T')[0] : filters.startDate;
|
|
|
|
|
const endDate = filters.endDate.includes('T') ? filters.endDate.split('T')[0] : filters.endDate;
|
|
|
|
|
|
|
|
|
|
console.log('[nocodb.getExpenses] Date filter:', { startDate, endDate });
|
|
|
|
|
params.where = `(Time,gte,${startDate})~and(Time,lte,${endDate})`;
|
|
|
|
|
} else if (filters?.startDate) {
|
|
|
|
|
params.where = `(Time,gte,${filters.startDate})`;
|
|
|
|
|
const startDate = filters.startDate.includes('T') ? filters.startDate.split('T')[0] : filters.startDate;
|
|
|
|
|
params.where = `(Time,gte,${startDate})`;
|
|
|
|
|
} else if (filters?.endDate) {
|
|
|
|
|
params.where = `(Time,lte,${filters.endDate})`;
|
|
|
|
|
const endDate = filters.endDate.includes('T') ? filters.endDate.split('T')[0] : filters.endDate;
|
|
|
|
|
params.where = `(Time,lte,${endDate})`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add payer filter
|
|
|
|
|
if (filters?.payer) {
|
|
|
|
|
const payerFilter = `(Payer,eq,${filters.payer})`;
|
|
|
|
|
const payerFilter = `(Payer,eq,${encodeURIComponent(filters.payer)})`;
|
|
|
|
|
params.where = params.where ? `${params.where}~and${payerFilter}` : payerFilter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add category filter
|
|
|
|
|
if (filters?.category) {
|
|
|
|
|
const categoryFilter = `(Category,eq,${filters.category})`;
|
|
|
|
|
const categoryFilter = `(Category,eq,${encodeURIComponent(filters.category)})`;
|
|
|
|
|
params.where = params.where ? `${params.where}~and${categoryFilter}` : categoryFilter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -870,29 +879,64 @@ export const getExpenses = async (filters?: ExpenseFilters) => {
|
|
|
|
|
params.sort = '-Time';
|
|
|
|
|
|
|
|
|
|
console.log('[nocodb.getExpenses] Request params:', params);
|
|
|
|
|
console.log('[nocodb.getExpenses] Request URL:', createTableUrl(Table.Expense));
|
|
|
|
|
|
|
|
|
|
// Use regular $fetch with better error handling
|
|
|
|
|
const result = await $fetch<ExpensesResponse>(createTableUrl(Table.Expense), {
|
|
|
|
|
headers: {
|
|
|
|
|
"xc-token": getNocoDbConfiguration().token,
|
|
|
|
|
"Content-Type": "application/json"
|
|
|
|
|
},
|
|
|
|
|
params
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('[nocodb.getExpenses] Successfully fetched expenses, count:', result.list?.length || 0);
|
|
|
|
|
console.log('[nocodb.getExpenses] Request duration:', Date.now() - startTime, 'ms');
|
|
|
|
|
|
|
|
|
|
// Transform expenses to add computed price numbers
|
|
|
|
|
if (result.list && Array.isArray(result.list)) {
|
|
|
|
|
result.list = result.list.map(expense => ({
|
|
|
|
|
...expense,
|
|
|
|
|
// Parse price string to number for calculations
|
|
|
|
|
PriceNumber: parseFloat(expense.Price.replace(/[€$,]/g, '')) || 0
|
|
|
|
|
PriceNumber: parseFloat(expense.Price?.replace(/[€$,]/g, '') || '0') || 0
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
console.error('[nocodb.getExpenses] Error fetching expenses:', error);
|
|
|
|
|
console.error('[nocodb.getExpenses] Error details:', error instanceof Error ? error.message : 'Unknown error');
|
|
|
|
|
console.error('[nocodb.getExpenses] =========================');
|
|
|
|
|
console.error('[nocodb.getExpenses] EXPENSE FETCH FAILED');
|
|
|
|
|
console.error('[nocodb.getExpenses] Duration:', Date.now() - startTime, 'ms');
|
|
|
|
|
console.error('[nocodb.getExpenses] Error type:', error.constructor?.name || 'Unknown');
|
|
|
|
|
console.error('[nocodb.getExpenses] Error status:', error.statusCode || error.status || 'Unknown');
|
|
|
|
|
console.error('[nocodb.getExpenses] Error message:', error.message || 'Unknown error');
|
|
|
|
|
console.error('[nocodb.getExpenses] Error data:', error.data);
|
|
|
|
|
console.error('[nocodb.getExpenses] Full error:', JSON.stringify(error, null, 2));
|
|
|
|
|
console.error('[nocodb.getExpenses] =========================');
|
|
|
|
|
|
|
|
|
|
// Provide more specific error messages
|
|
|
|
|
if (error.statusCode === 401 || error.status === 401) {
|
|
|
|
|
throw createError({
|
|
|
|
|
statusCode: 401,
|
|
|
|
|
statusMessage: 'Authentication failed when accessing expense database. Please check your access permissions.'
|
|
|
|
|
});
|
|
|
|
|
} else if (error.statusCode === 403 || error.status === 403) {
|
|
|
|
|
throw createError({
|
|
|
|
|
statusCode: 403,
|
|
|
|
|
statusMessage: 'Access denied to expense database. This feature requires appropriate privileges.'
|
|
|
|
|
});
|
|
|
|
|
} else if (error.statusCode === 404 || error.status === 404) {
|
|
|
|
|
throw createError({
|
|
|
|
|
statusCode: 404,
|
|
|
|
|
statusMessage: 'Expense database table not found. Please contact your administrator.'
|
|
|
|
|
});
|
|
|
|
|
} else if (error.code === 'NETWORK_ERROR' || error.code === 'TIMEOUT') {
|
|
|
|
|
throw createError({
|
|
|
|
|
statusCode: 503,
|
|
|
|
|
statusMessage: 'Expense database is temporarily unavailable. Please try again in a moment.'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|