Send a dedicated email for a switched Überweisung payment, not the full order-confirmation

New sendPaymentSwitchedEmail() — sent instead of sendOrderConfirmationEmail()
when confirmPaymentEmail.ts sees order.paymentSwitchedAt set. Resending the
full order-confirmation (with its invoice re-attached) after a payment-method
switch read like a brand-new purchase; this is a short, dedicated "Zahlung
erhalten" confirmation instead, matching the order-status-email shape.

Also bumps @einfach-produktiv/invoicing to 0.2.8, fixing a font-path bug
that broke every invoice PDF render inside the Payload backend specifically.
This commit is contained in:
Marco
2026-07-30 11:04:27 +00:00
parent 2e537bc78d
commit f0b2d21989
7 changed files with 85 additions and 7 deletions
+19 -3
View File
@@ -1,4 +1,4 @@
import { sendOrderConfirmationEmail, type OrderConfirmationEmailData } from "../orderEmail";
import { sendOrderConfirmationEmail, sendPaymentSwitchedEmail, type OrderConfirmationEmailData } from "../orderEmail";
import { sendCriticalAlert } from "../alertAdmin";
// The `order` snapshot returned by the backend's confirm-payment endpoint
@@ -9,7 +9,13 @@ import { sendCriticalAlert } from "../alertAdmin";
// templates), so it returns everything needed here instead of the
// frontend needing an authenticated order-read path it doesn't otherwise
// have (ORDER_SERVICE_SECRET only ever authorizes *creating* an order).
export type ConfirmPaymentOrderSnapshot = OrderConfirmationEmailData & { customerEmail: string };
export type ConfirmPaymentOrderSnapshot = OrderConfirmationEmailData & {
customerEmail: string;
// Present only when this payment came from switchPaymentToStripe.ts (an
// existing Überweisung order moved to Stripe) — see this function's own
// branch below.
paymentSwitchedAt?: string;
};
// Called from both the real Stripe webhook route and its PAYMENT_TEST_MODE
// test-confirm sibling, right after confirm-payment reports success (and
@@ -17,10 +23,20 @@ export type ConfirmPaymentOrderSnapshot = OrderConfirmationEmailData & { custome
// this). Mirrors exactly what app/api/checkout/route.ts already does for
// a manual/Überweisung order today, just triggered from the payment
// webhook instead of the checkout request itself for gated methods.
//
// A payment-method switch (paymentSwitchedAt set) sends a short dedicated
// "Zahlung erhalten" confirmation instead — the customer already got the
// full order-confirmation email (with its invoice) when they originally
// placed the Überweisung order; resending that same email here would read
// as a second, brand-new purchase.
export async function sendConfirmedPaymentEmail(order: ConfirmPaymentOrderSnapshot): Promise<void> {
const { customerEmail, ...emailData } = order;
try {
await sendOrderConfirmationEmail(emailData, customerEmail);
if (order.paymentSwitchedAt) {
await sendPaymentSwitchedEmail(order.orderNumber, customerEmail);
} else {
await sendOrderConfirmationEmail(emailData, customerEmail);
}
} catch (err) {
sendCriticalAlert("Bestätigungs-Mail konnte nach Zahlungsbestätigung nicht gesendet werden", {
orderNumber: order.orderNumber,