Belegupload nach Freigabe und Bezahlt-Logik korrigieren
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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" }}
|
||||
/>
|
||||
<Chip
|
||||
icon={<CheckCircleRoundedIcon />}
|
||||
label={`Bezahlt: ${formatCurrency(paidSpend)}`}
|
||||
color="info"
|
||||
sx={{ ...wrappingChipSx, width: "fit-content" }}
|
||||
/>
|
||||
<Chip
|
||||
icon={<ReceiptLongRoundedIcon />}
|
||||
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) }}
|
||||
/>
|
||||
<Chip
|
||||
icon={<CheckCircleRoundedIcon />}
|
||||
label={`Bezahlt: ${formatCurrency(budgetPaid)}`}
|
||||
color="info"
|
||||
sx={{ ...wrappingChipSx, width: "fit-content" }}
|
||||
/>
|
||||
<Chip
|
||||
icon={<ReceiptLongRoundedIcon />}
|
||||
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 (
|
||||
<Box
|
||||
@@ -844,7 +862,7 @@ export function BudgetColumn({
|
||||
{!expense.paidAt &&
|
||||
expense.approvalStatus === "APPROVED" &&
|
||||
!expense.proofUrl &&
|
||||
canDocumentExpense(viewer.role) ? (
|
||||
canUploadProof ? (
|
||||
<Stack direction={{ xs: "column", sm: "row" }} gap={1} alignItems={{ sm: "center" }}>
|
||||
<TextField
|
||||
label="Rechnungsdatum"
|
||||
@@ -910,7 +928,6 @@ export function BudgetColumn({
|
||||
}
|
||||
|
||||
await onUploadProof(expense.id, proofFile, invoiceDate);
|
||||
await onMarkPaid(expense.id);
|
||||
}}
|
||||
>
|
||||
Rechnung abgeben und bezahlt setzen
|
||||
|
||||
@@ -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.";
|
||||
|
||||
Reference in New Issue
Block a user