diff --git a/src/app/api/audit-logs/[id]/restore/route.ts b/src/app/api/audit-logs/[id]/restore/route.ts
index 5ad6128..659d35e 100644
--- a/src/app/api/audit-logs/[id]/restore/route.ts
+++ b/src/app/api/audit-logs/[id]/restore/route.ts
@@ -576,7 +576,8 @@ export async function POST(_: Request, { params }: Context) {
data: {
proofUrl: asNullableString(rollback.previousProofUrl),
invoiceDate: asDate(rollback.previousInvoiceDate, "Vorheriges Rechnungsdatum"),
- documentedAt: asDate(rollback.previousDocumentedAt, "Vorheriger Dokumentationszeitpunkt")
+ documentedAt: asDate(rollback.previousDocumentedAt, "Vorheriger Dokumentationszeitpunkt"),
+ paidAt: asDate(rollback.previousPaidAt, "Vorheriger Bezahlt-Zeitpunkt")
}
});
break;
diff --git a/src/app/api/expenses/[id]/proof/route.ts b/src/app/api/expenses/[id]/proof/route.ts
index 992d5dd..50b13c0 100644
--- a/src/app/api/expenses/[id]/proof/route.ts
+++ b/src/app/api/expenses/[id]/proof/route.ts
@@ -81,7 +81,8 @@ export async function POST(request: Request, { params }: Context) {
data: {
proofUrl,
invoiceDate,
- documentedAt: expense.documentedAt ?? new Date()
+ documentedAt: expense.documentedAt ?? new Date(),
+ paidAt: expense.paidAt ?? new Date()
}
});
@@ -103,7 +104,9 @@ export async function POST(request: Request, { params }: Context) {
previousDocumentedAt: expense.documentedAt?.toISOString() ?? null,
nextProofUrl: updatedExpense.proofUrl,
nextInvoiceDate: updatedExpense.invoiceDate?.toISOString() ?? null,
- nextDocumentedAt: updatedExpense.documentedAt?.toISOString() ?? null
+ nextDocumentedAt: updatedExpense.documentedAt?.toISOString() ?? null,
+ previousPaidAt: expense.paidAt?.toISOString() ?? null,
+ nextPaidAt: updatedExpense.paidAt?.toISOString() ?? null
}
}
});
diff --git a/src/components/dashboard/budget-column.tsx b/src/components/dashboard/budget-column.tsx
index d98d2e6..6dac4d6 100644
--- a/src/components/dashboard/budget-column.tsx
+++ b/src/components/dashboard/budget-column.tsx
@@ -186,6 +186,10 @@ export function BudgetColumn({
() => group.budgets.reduce((sum, budget) => sum + getApprovedSpend(budget.expenses), 0),
[group.budgets]
);
+ const paidSpend = useMemo(
+ () => group.budgets.reduce((sum, budget) => sum + getPaidSpend(budget.expenses), 0),
+ [group.budgets]
+ );
const pendingSpend = useMemo(
() => group.budgets.reduce((sum, budget) => sum + getPendingSpend(budget.expenses), 0),
[group.budgets]
@@ -340,6 +344,12 @@ export function BudgetColumn({
label={`Freigegeben: ${formatCurrency(approvedSpend)}`}
sx={{ ...wrappingChipSx, width: "fit-content" }}
/>
+ }
+ label={`Bezahlt: ${formatCurrency(paidSpend)}`}
+ color="info"
+ sx={{ ...wrappingChipSx, width: "fit-content" }}
+ />
}
label={`Geplant: ${formatCurrency(pendingSpend)}`}
@@ -391,12 +401,13 @@ export function BudgetColumn({
const draft = getDraft(budget);
const isEditing = editingBudgetId === budget.id;
const budgetApproved = getApprovedSpend(budget.expenses);
+ const budgetPaid = getPaidSpend(budget.expenses);
const budgetPending = getPendingSpend(budget.expenses);
const budgetReleasedByPayments = getPaidSpend(budget.expenses);
const budgetReleasedTotal = budget.releasedAmount + budgetReleasedByPayments;
const budgetCommitted = budgetApproved + budgetPending;
const budgetRemaining = budget.totalBudget - budgetCommitted;
- const approvedPercent = budget.totalBudget > 0 ? Math.min((budgetApproved / budget.totalBudget) * 100, 100) : 0;
+ const paidPercent = budget.totalBudget > 0 ? Math.min((budgetPaid / budget.totalBudget) * 100, 100) : 0;
const cumulativePercent =
budget.totalBudget > 0 ? Math.min((budgetCommitted / budget.totalBudget) * 100, 100) : 0;
const releasedPercent =
@@ -485,7 +496,7 @@ export function BudgetColumn({
position: "absolute",
insetInline: 0,
bottom: 0,
- height: `${approvedPercent}%`,
+ height: `${paidPercent}%`,
backgroundColor: budget.colorCode,
transition: "height 220ms ease"
}}
@@ -512,6 +523,12 @@ export function BudgetColumn({
label={`Freigegeben: ${formatCurrency(budgetApproved)}`}
sx={{ ...wrappingChipSx, width: "fit-content", bgcolor: alpha(budget.colorCode, 0.14) }}
/>
+ }
+ label={`Bezahlt: ${formatCurrency(budgetPaid)}`}
+ color="info"
+ sx={{ ...wrappingChipSx, width: "fit-content" }}
+ />
}
label={`Geplant: ${formatCurrency(budgetPending)}`}
@@ -630,6 +647,7 @@ export function BudgetColumn({
: [];
const isRecurringSeries = expense.recurrence === "MONTHLY";
const isRecurringExpanded = expandedRecurringExpenses[expense.id] ?? false;
+ const canUploadProof = expense.creator.id === viewer.id || canDocumentExpense(viewer.role);
return (
Rechnung abgeben und bezahlt setzen
diff --git a/src/components/dashboard/dashboard-shell.tsx b/src/components/dashboard/dashboard-shell.tsx
index 501987c..e226ac4 100644
--- a/src/components/dashboard/dashboard-shell.tsx
+++ b/src/components/dashboard/dashboard-shell.tsx
@@ -769,6 +769,11 @@ export function DashboardShell({
})
)) as { proofUrl: string };
+ setMessage({ type: "success", text: "Rechnung wurde abgegeben und die Ausgabe ist jetzt bezahlt." });
+ startTransition(() => {
+ router.refresh();
+ });
+
return result.proofUrl;
} catch (error) {
const text = error instanceof Error ? error.message : "Beleg konnte nicht hochgeladen werden.";