+
{{ expenses.length }} expenses • €{{ totalAmount.toFixed(2) }}
-
+
+
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+ +{{ expense.Receipt.length - 1 }}
+
+
+
+
+
+ mdi-receipt-text-outline
+ No receipt
+
+
+
+
+
+
+
+ {{ expense['Establishment Name'] || 'Unknown Merchant' }}
+
+
+
+
+ {{ expense.Price }}
+
+ (≈ ${{ expense.PriceUSD.toFixed(2) }})
+
+
+
+
+
+
+ {{ expense.Category || 'Other' }}
+
+
+
+
+ {{ expense['Payment Method'] || 'Unknown' }}
+
+
+
+
+
+ mdi-calendar-clock
+ {{ formatDateTime(expense.Time) }}
+
+
+
+
+ mdi-account
+ {{ expense.Payer }}
+
+
+
+
+ {{ getContentsPreview(expense) }}
+
+
+
+
+
+
-
-
- +{{ expense.Receipt.length - 1 }}
-
+
-
-
-
-
- No receipt
-
-
-
-
-
-
- {{ expense['Establishment Name'] || 'Unknown' }}
-
-
-
- {{ expense.DisplayPrice || expense.Price }}
-
-
-
-
-
- {{ formatDateTime(expense.Time) }}
-
-
-
-
- {{ expense.Contents.length > 50 ? expense.Contents.substring(0, 50) + '...' : expense.Contents }}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
-
-
-
- No expenses found
-
-
- No expenses match the current filters
-
-
+
+
+ mdi-receipt
+ No expenses found
+
+ No expenses match the current filters
+
+
+
diff --git a/server/api/create-expense.ts b/server/api/create-expense.ts
new file mode 100644
index 0000000..94c504e
--- /dev/null
+++ b/server/api/create-expense.ts
@@ -0,0 +1,79 @@
+import { requireSalesOrAdmin } from '@/server/utils/auth';
+import { getNocoDbConfiguration } from '@/server/utils/nocodb';
+import type { Expense } from '@/utils/types';
+
+export default defineEventHandler(async (event) => {
+ try {
+ // Ensure only sales/admin users can create expenses
+ await requireSalesOrAdmin(event);
+
+ const body = await readBody(event);
+ console.log('[create-expense] Creating expense with data:', body);
+
+ // Validate required fields
+ const requiredFields = ['Establishment Name', 'Price', 'Category', 'Payer', 'Time'];
+ for (const field of requiredFields) {
+ if (!body[field]) {
+ throw createError({
+ statusCode: 400,
+ statusMessage: `Missing required field: ${field}`
+ });
+ }
+ }
+
+ // Get NocoDB configuration
+ const config = getNocoDbConfiguration();
+ const expenseTableId = "mxfcefkk4dqs6uq"; // Expense table ID from nocodb.ts
+
+ // Prepare expense data for NocoDB
+ const expenseData = {
+ "Establishment Name": body["Establishment Name"],
+ Price: body.Price,
+ Category: body.Category,
+ Payer: body.Payer,
+ Time: body.Time,
+ Contents: body.Contents || null,
+ "Payment Method": body["Payment Method"] || "Card",
+ currency: body.currency || "EUR",
+ Paid: body.Paid || false
+ };
+
+ console.log('[create-expense] Sending to NocoDB:', expenseData);
+
+ // Create the expense in NocoDB
+ const response = await $fetch
(`${config.url}/api/v2/tables/${expenseTableId}/records`, {
+ method: 'POST',
+ headers: {
+ 'xc-token': config.token,
+ 'Content-Type': 'application/json'
+ },
+ body: expenseData
+ });
+
+ console.log('[create-expense] Expense created successfully:', response.Id);
+
+ return response;
+
+ } catch (error: any) {
+ console.error('[create-expense] Failed to create expense:', error);
+
+ if (error.statusCode === 403) {
+ throw createError({
+ statusCode: 403,
+ statusMessage: 'Access denied. This feature requires sales team or administrator privileges.'
+ });
+ }
+
+ if (error.statusCode === 400) {
+ throw createError({
+ statusCode: 400,
+ statusMessage: error.statusMessage
+ });
+ }
+
+ throw createError({
+ statusCode: 500,
+ statusMessage: 'Failed to create expense. Please try again later.'
+ });
+ }
+});