Belegupload nach Freigabe und Bezahlt-Logik korrigieren
This commit is contained in:
@@ -576,7 +576,8 @@ export async function POST(_: Request, { params }: Context) {
|
|||||||
data: {
|
data: {
|
||||||
proofUrl: asNullableString(rollback.previousProofUrl),
|
proofUrl: asNullableString(rollback.previousProofUrl),
|
||||||
invoiceDate: asDate(rollback.previousInvoiceDate, "Vorheriges Rechnungsdatum"),
|
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;
|
break;
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ export async function POST(request: Request, { params }: Context) {
|
|||||||
data: {
|
data: {
|
||||||
proofUrl,
|
proofUrl,
|
||||||
invoiceDate,
|
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,
|
previousDocumentedAt: expense.documentedAt?.toISOString() ?? null,
|
||||||
nextProofUrl: updatedExpense.proofUrl,
|
nextProofUrl: updatedExpense.proofUrl,
|
||||||
nextInvoiceDate: updatedExpense.invoiceDate?.toISOString() ?? null,
|
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.reduce((sum, budget) => sum + getApprovedSpend(budget.expenses), 0),
|
||||||
[group.budgets]
|
[group.budgets]
|
||||||
);
|
);
|
||||||
|
const paidSpend = useMemo(
|
||||||
|
() => group.budgets.reduce((sum, budget) => sum + getPaidSpend(budget.expenses), 0),
|
||||||
|
[group.budgets]
|
||||||
|
);
|
||||||
const pendingSpend = useMemo(
|
const pendingSpend = useMemo(
|
||||||
() => group.budgets.reduce((sum, budget) => sum + getPendingSpend(budget.expenses), 0),
|
() => group.budgets.reduce((sum, budget) => sum + getPendingSpend(budget.expenses), 0),
|
||||||
[group.budgets]
|
[group.budgets]
|
||||||
@@ -340,6 +344,12 @@ export function BudgetColumn({
|
|||||||
label={`Freigegeben: ${formatCurrency(approvedSpend)}`}
|
label={`Freigegeben: ${formatCurrency(approvedSpend)}`}
|
||||||
sx={{ ...wrappingChipSx, width: "fit-content" }}
|
sx={{ ...wrappingChipSx, width: "fit-content" }}
|
||||||
/>
|
/>
|
||||||
|
<Chip
|
||||||
|
icon={<CheckCircleRoundedIcon />}
|
||||||
|
label={`Bezahlt: ${formatCurrency(paidSpend)}`}
|
||||||
|
color="info"
|
||||||
|
sx={{ ...wrappingChipSx, width: "fit-content" }}
|
||||||
|
/>
|
||||||
<Chip
|
<Chip
|
||||||
icon={<ReceiptLongRoundedIcon />}
|
icon={<ReceiptLongRoundedIcon />}
|
||||||
label={`Geplant: ${formatCurrency(pendingSpend)}`}
|
label={`Geplant: ${formatCurrency(pendingSpend)}`}
|
||||||
@@ -391,12 +401,13 @@ export function BudgetColumn({
|
|||||||
const draft = getDraft(budget);
|
const draft = getDraft(budget);
|
||||||
const isEditing = editingBudgetId === budget.id;
|
const isEditing = editingBudgetId === budget.id;
|
||||||
const budgetApproved = getApprovedSpend(budget.expenses);
|
const budgetApproved = getApprovedSpend(budget.expenses);
|
||||||
|
const budgetPaid = getPaidSpend(budget.expenses);
|
||||||
const budgetPending = getPendingSpend(budget.expenses);
|
const budgetPending = getPendingSpend(budget.expenses);
|
||||||
const budgetReleasedByPayments = getPaidSpend(budget.expenses);
|
const budgetReleasedByPayments = getPaidSpend(budget.expenses);
|
||||||
const budgetReleasedTotal = budget.releasedAmount + budgetReleasedByPayments;
|
const budgetReleasedTotal = budget.releasedAmount + budgetReleasedByPayments;
|
||||||
const budgetCommitted = budgetApproved + budgetPending;
|
const budgetCommitted = budgetApproved + budgetPending;
|
||||||
const budgetRemaining = budget.totalBudget - budgetCommitted;
|
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 =
|
const cumulativePercent =
|
||||||
budget.totalBudget > 0 ? Math.min((budgetCommitted / budget.totalBudget) * 100, 100) : 0;
|
budget.totalBudget > 0 ? Math.min((budgetCommitted / budget.totalBudget) * 100, 100) : 0;
|
||||||
const releasedPercent =
|
const releasedPercent =
|
||||||
@@ -485,7 +496,7 @@ export function BudgetColumn({
|
|||||||
position: "absolute",
|
position: "absolute",
|
||||||
insetInline: 0,
|
insetInline: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
height: `${approvedPercent}%`,
|
height: `${paidPercent}%`,
|
||||||
backgroundColor: budget.colorCode,
|
backgroundColor: budget.colorCode,
|
||||||
transition: "height 220ms ease"
|
transition: "height 220ms ease"
|
||||||
}}
|
}}
|
||||||
@@ -512,6 +523,12 @@ export function BudgetColumn({
|
|||||||
label={`Freigegeben: ${formatCurrency(budgetApproved)}`}
|
label={`Freigegeben: ${formatCurrency(budgetApproved)}`}
|
||||||
sx={{ ...wrappingChipSx, width: "fit-content", bgcolor: alpha(budget.colorCode, 0.14) }}
|
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
|
<Chip
|
||||||
icon={<ReceiptLongRoundedIcon />}
|
icon={<ReceiptLongRoundedIcon />}
|
||||||
label={`Geplant: ${formatCurrency(budgetPending)}`}
|
label={`Geplant: ${formatCurrency(budgetPending)}`}
|
||||||
@@ -630,6 +647,7 @@ export function BudgetColumn({
|
|||||||
: [];
|
: [];
|
||||||
const isRecurringSeries = expense.recurrence === "MONTHLY";
|
const isRecurringSeries = expense.recurrence === "MONTHLY";
|
||||||
const isRecurringExpanded = expandedRecurringExpenses[expense.id] ?? false;
|
const isRecurringExpanded = expandedRecurringExpenses[expense.id] ?? false;
|
||||||
|
const canUploadProof = expense.creator.id === viewer.id || canDocumentExpense(viewer.role);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -844,7 +862,7 @@ export function BudgetColumn({
|
|||||||
{!expense.paidAt &&
|
{!expense.paidAt &&
|
||||||
expense.approvalStatus === "APPROVED" &&
|
expense.approvalStatus === "APPROVED" &&
|
||||||
!expense.proofUrl &&
|
!expense.proofUrl &&
|
||||||
canDocumentExpense(viewer.role) ? (
|
canUploadProof ? (
|
||||||
<Stack direction={{ xs: "column", sm: "row" }} gap={1} alignItems={{ sm: "center" }}>
|
<Stack direction={{ xs: "column", sm: "row" }} gap={1} alignItems={{ sm: "center" }}>
|
||||||
<TextField
|
<TextField
|
||||||
label="Rechnungsdatum"
|
label="Rechnungsdatum"
|
||||||
@@ -910,7 +928,6 @@ export function BudgetColumn({
|
|||||||
}
|
}
|
||||||
|
|
||||||
await onUploadProof(expense.id, proofFile, invoiceDate);
|
await onUploadProof(expense.id, proofFile, invoiceDate);
|
||||||
await onMarkPaid(expense.id);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Rechnung abgeben und bezahlt setzen
|
Rechnung abgeben und bezahlt setzen
|
||||||
|
|||||||
@@ -769,6 +769,11 @@ export function DashboardShell({
|
|||||||
})
|
})
|
||||||
)) as { proofUrl: string };
|
)) as { proofUrl: string };
|
||||||
|
|
||||||
|
setMessage({ type: "success", text: "Rechnung wurde abgegeben und die Ausgabe ist jetzt bezahlt." });
|
||||||
|
startTransition(() => {
|
||||||
|
router.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
return result.proofUrl;
|
return result.proofUrl;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const text = error instanceof Error ? error.message : "Beleg konnte nicht hochgeladen werden.";
|
const text = error instanceof Error ? error.message : "Beleg konnte nicht hochgeladen werden.";
|
||||||
|
|||||||
Reference in New Issue
Block a user