Reflect Orders.paymentStatus's new meaning for Überweisung orders
- switch-to-stripe eligibility gained paymentStatus !== "paid" — an order an admin already marked paid by hand must never also be switchable to Stripe. - PaymentStatusBadge: "Offen" now renders in the same red/subtle style as a failed status (was neutral grey) — worth visually flagging, now that it's a real tracked state rather than a permanent placeholder.
This commit is contained in:
@@ -2036,6 +2036,42 @@ Full plan for an n8n-driven blog-post content-automation pipeline (not yet
|
||||
built) lives in the Payload backend repo's `docs/blog-automation-plan.md`,
|
||||
not duplicated here since it changes independently of this frontend.
|
||||
|
||||
**Switching an unpaid Überweisung order to Stripe.** New "Zahlungsart
|
||||
ändern" button on `/konto/bestellungen/[orderNumber]`, shown when an order
|
||||
is still `paymentProvider: 'manual'`, `status: 'received'`,
|
||||
`paymentStatus` not yet `'paid'`, and an active Stripe payment method
|
||||
exists. `POST /api/account/orders/[orderNumber]/switch-to-stripe` creates
|
||||
a real PaymentIntent (`app/lib/payments`, same code checkout itself uses)
|
||||
and hands it to the backend's `switchPaymentToStripeEndpoint`. Reuses
|
||||
`PaymentStep` (checkout's own Stripe collection UI) and
|
||||
`/checkout/verarbeitung`'s polling page — both now take a
|
||||
`returnContext`/`context` prop/param so payment confirmation lands back
|
||||
on the order page instead of clearing the cart and redirecting to
|
||||
`/bestellbestaetigung`, which would be wrong for an order that was
|
||||
already placed and confirmed.
|
||||
|
||||
Also: a payment status badge (Offen/Bezahlt/…) next to the existing
|
||||
fulfillment status badge, on both the order list (`/konto/bestellungen`)
|
||||
and the detail page — "Offen" renders in the same red/subtle-background
|
||||
style as a failed status, not the neutral grey the fulfillment status
|
||||
badge uses for its own "in progress" states, since an unpaid order is
|
||||
worth visually flagging. A one-line mention of the switch option was
|
||||
added to the Vorkasse unpaid notice in the order-confirmation email,
|
||||
shown only when `hasOnlinePaymentOption` is true (an active Stripe method
|
||||
actually exists).
|
||||
|
||||
**Fixed the email-preview page** (`/email-preview/[type]`) — it rendered
|
||||
the email HTML (a full `<body>...</body>` fragment) via
|
||||
`dangerouslySetInnerHTML` into a plain `<div>`, nesting it inside the
|
||||
page's own already-existing `<body>` — invalid HTML the browser silently
|
||||
mangled, which is why the preview looked broken (wrong background/
|
||||
padding/font). Now renders via `<iframe srcDoc>`, giving the email its
|
||||
own real document context. Also added a second sample fixture
|
||||
(`SAMPLE_ORDER_MANUAL`) with a toggle, since `SAMPLE_ORDER` alone always
|
||||
had `isManualPayment: false` — the Vorkasse/Überweisung branch (and its
|
||||
new switch-option mention) was never previewable in the admin at all
|
||||
before this.
|
||||
|
||||
## Deployment
|
||||
|
||||
- **Dockerfile**: 3-stage build (`deps` → `builder` → `runner`) with
|
||||
|
||||
@@ -21,8 +21,10 @@ export async function POST(request: Request, { params }: { params: Promise<{ ord
|
||||
if (!order) return NextResponse.json({ ok: false, reason: "Bestellung nicht gefunden." }, { status: 404 });
|
||||
|
||||
// Same eligibility the backend endpoint re-checks authoritatively —
|
||||
// checked here too for a friendly error instead of a bare 409.
|
||||
if (order.paymentProvider !== "manual" || order.status !== "received") {
|
||||
// checked here too for a friendly error instead of a bare 409. An admin
|
||||
// can mark an Überweisung order paid by hand (Orders.ts's paymentStatus
|
||||
// field) — that order must never also be switched to Stripe.
|
||||
if (order.paymentProvider !== "manual" || order.status !== "received" || order.paymentStatus === "paid") {
|
||||
return NextResponse.json({ ok: false, reason: "Die Zahlungsart kann für diese Bestellung gerade nicht geändert werden." }, { status: 400 });
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ export default async function KontoBestellungDetailPage({ params }: { params: Pr
|
||||
const canSwitchPayment =
|
||||
order.paymentProvider === "manual" &&
|
||||
order.status === "received" &&
|
||||
order.paymentStatus !== "paid" &&
|
||||
groupPaymentMethodsForCheckout(await getPaymentMethods()).some((m) => m.provider === "stripe");
|
||||
|
||||
return (
|
||||
|
||||
@@ -14,8 +14,8 @@ const LABEL: Record<string, string> = {
|
||||
};
|
||||
|
||||
const STYLES: Record<string, string> = {
|
||||
not_applicable: "bg-bg-muted text-text-muted",
|
||||
pending: "bg-bg-muted text-text-muted",
|
||||
not_applicable: "bg-red-50 text-red-600",
|
||||
pending: "bg-red-50 text-red-600",
|
||||
paid: "bg-success-subtle text-success",
|
||||
failed: "bg-red-50 text-red-600",
|
||||
refunded: "bg-bg-muted text-text-light",
|
||||
|
||||
Reference in New Issue
Block a user