feat: Stripe Embedded Checkout statt Weiterleitung zu checkout.stripe.com
Bezahlt wird jetzt direkt auf /checkout: die Checkout-Session laeuft mit ui_mode "embedded_page", das Zahlungsformular ist ein Stripe-iframe (PCI SAQ A bleibt). PayPal, Karte, SEPA und Klarna kommen weiterhin dynamisch aus dem Dashboard. - Zahlungsschritt ersetzt das Formular; "Zurueck zu deinen Angaben" gibt Sitzung und Bestand sofort frei (POST /api/checkout/cancel) und behaelt alle Eingaben, Turnstile wird neu geladen - Rueckkehrseite prueft serverseitig bei Stripe und gleicht die Sitzung mit der eigenen Bestellung ab; bei abgebrochener PayPal-Zahlung wird dieselbe Sitzung erneut eingebettet - Erneuter Versuch und Abbruch sind per HttpOnly-Cookie an den bestellenden Browser gebunden, die session_id in der URL allein reicht nicht - Alte /checkout/cancel?ref= Links aendern per GET nichts mehr - CSP um die Stripe-Hosts fuer Embedded Checkout und 3-D-Secure erweitert - STRIPE_PUBLISHABLE_KEY zur Laufzeit gelesen (kein NEXT_PUBLIC_), mit Preflight-Pruefung auf pk_live und Schutz gegen versehentliche sk_/rk_ Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
6ac7cc5d1f
commit
4ee5bafe20
28 files changed
+1272
-179
No files matched your search
@@ -1415,15 +1415,23 @@ export const de: Dictionary = {
|
||||
save: "Passwort speichern",
|
||||
},
|
||||
checkoutSuccessPage: {
|
||||
pendingEyebrow: "Bestellung vorgemerkt",
|
||||
pendingEyebrow: "Zahlung in Bearbeitung",
|
||||
successEyebrow: "Vielen Dank",
|
||||
pendingTitle: "Deine Bestellung ist eingegangen.",
|
||||
successTitle: "Deine Bestellung wurde bestätigt.",
|
||||
orderNumberLabel: "Bestellnummer",
|
||||
pendingText: "Die Zahlungsabwicklung war kurzfristig nicht erreichbar. Wir melden uns per E-Mail bei dir, um die Zahlung abzuschließen.",
|
||||
pendingText: "Deine Zahlung wird noch bestätigt (bei SEPA-Lastschrift kann das einige Werktage dauern). Sobald sie eingegangen ist, bekommst du eine Bestätigung per E-Mail.",
|
||||
successText: "Wir bereiten dein Glas Wabenhain-Honig mit Sorgfalt vor. Sobald deine Zahlung eingegangen ist, senden wir dir eine Bestätigung per E-Mail (bei SEPA-Lastschrift kann das einige Werktage dauern).",
|
||||
continueShopping: "Weiter stöbern",
|
||||
trackOrder: "Bestellung verfolgen",
|
||||
openEyebrow: "Zahlung nicht abgeschlossen",
|
||||
openTitle: "Das hat leider nicht geklappt.",
|
||||
openText: "Die Zahlung wurde abgebrochen oder abgelehnt, es wurde nichts abgebucht. Deine Bestellung ist noch für dich reserviert — versuche es einfach erneut, gern auch mit einer anderen Zahlungsart.",
|
||||
cancelPayment: "Bestellung abbrechen",
|
||||
notCompletedEyebrow: "Nicht abgeschlossen",
|
||||
notCompletedTitle: "Diese Bestellung wurde nicht bezahlt.",
|
||||
notCompletedText: "Die Zahlung ist abgelaufen oder wurde abgebrochen, es wurde nichts abgebucht. Dein Warenkorb ist noch gefüllt, du kannst jederzeit neu bestellen.",
|
||||
backToCart: "Zurück zum Warenkorb",
|
||||
},
|
||||
checkoutCancelPage: {
|
||||
eyebrow: "Abgebrochen",
|
||||
@@ -1433,6 +1441,13 @@ export const de: Dictionary = {
|
||||
backToCart: "Zurück zum Warenkorb",
|
||||
},
|
||||
checkoutPage: {
|
||||
paymentHeading: "Zahlung",
|
||||
paymentBack: "Zurück zu deinen Angaben",
|
||||
paymentCancelling: "Einen Moment…",
|
||||
paymentCancelError: "Das hat gerade nicht geklappt. Bitte versuche es noch einmal.",
|
||||
paymentLoading: "Sichere Zahlung wird geladen…",
|
||||
paymentLoadError: "Das Zahlungsformular konnte nicht geladen werden. Ein Werbeblocker kann das verhindern.",
|
||||
paymentUnavailable: "Die Zahlung ist gerade nicht verfügbar. Bitte versuche es später erneut oder melde dich bei uns.",
|
||||
eyebrow: "Checkout",
|
||||
emptyCart: "Dein Warenkorb ist leer",
|
||||
yourDetails: "Deine Daten",
|
||||
@@ -1474,7 +1489,7 @@ export const de: Dictionary = {
|
||||
submitting: "Wird verarbeitet…",
|
||||
placeOrder: "Kostenpflichtig bestellen",
|
||||
paymentMethodsNote:
|
||||
"Zahlungsmethoden: PayPal, Kreditkarte, Apple Pay, Google Pay, SEPA-Lastschrift, Klarna, bereitgestellt über Stripe.",
|
||||
"Im nächsten Schritt bezahlst du sicher direkt hier auf der Seite: PayPal, Kreditkarte, SEPA-Lastschrift oder Klarna, abgewickelt über Stripe.",
|
||||
yourOrderHeading: "Deine Bestellung",
|
||||
shippingWithCount: (count) => `Versand (${count} Stück)`,
|
||||
shippingPickup: "Versand (Abholung)",
|
||||
|
||||
@@ -1401,15 +1401,23 @@ export const en: Dictionary = {
|
||||
save: "Save password",
|
||||
},
|
||||
checkoutSuccessPage: {
|
||||
pendingEyebrow: "Order Received",
|
||||
pendingEyebrow: "Payment Processing",
|
||||
successEyebrow: "Thank You",
|
||||
pendingTitle: "Your order has been received.",
|
||||
successTitle: "Your order has been confirmed.",
|
||||
orderNumberLabel: "Order number",
|
||||
pendingText: "Payment processing was briefly unreachable. We'll email you to complete the payment.",
|
||||
pendingText: "Your payment is still being confirmed (this can take a few business days for SEPA direct debit). We'll email you as soon as it arrives.",
|
||||
successText: "We're carefully preparing your jar of Wabenhain honey. As soon as your payment arrives, we'll send you a confirmation by email (this can take a few business days for SEPA direct debit).",
|
||||
continueShopping: "Keep browsing",
|
||||
trackOrder: "Track order",
|
||||
openEyebrow: "Payment Not Completed",
|
||||
openTitle: "That didn't work, unfortunately.",
|
||||
openText: "The payment was cancelled or declined and nothing was charged. Your order is still reserved for you — just try again, with another payment method if you like.",
|
||||
cancelPayment: "Cancel order",
|
||||
notCompletedEyebrow: "Not Completed",
|
||||
notCompletedTitle: "This order was not paid.",
|
||||
notCompletedText: "The payment expired or was cancelled and nothing was charged. Your cart is still filled, so you can order again at any time.",
|
||||
backToCart: "Back to cart",
|
||||
},
|
||||
checkoutCancelPage: {
|
||||
eyebrow: "Cancelled",
|
||||
@@ -1419,6 +1427,13 @@ export const en: Dictionary = {
|
||||
backToCart: "Back to cart",
|
||||
},
|
||||
checkoutPage: {
|
||||
paymentHeading: "Payment",
|
||||
paymentBack: "Back to your details",
|
||||
paymentCancelling: "One moment…",
|
||||
paymentCancelError: "That didn't work just now. Please try again.",
|
||||
paymentLoading: "Loading secure payment…",
|
||||
paymentLoadError: "The payment form could not be loaded. An ad blocker can prevent this.",
|
||||
paymentUnavailable: "Payment is currently unavailable. Please try again later or get in touch with us.",
|
||||
eyebrow: "Checkout",
|
||||
emptyCart: "Your cart is empty",
|
||||
yourDetails: "Your Details",
|
||||
@@ -1460,7 +1475,7 @@ export const en: Dictionary = {
|
||||
submitting: "Processing…",
|
||||
placeOrder: "Place order",
|
||||
paymentMethodsNote:
|
||||
"Payment methods: PayPal, credit card, Apple Pay, Google Pay, SEPA direct debit, Klarna, provided via Stripe.",
|
||||
"In the next step you pay securely right here on this page: PayPal, credit card, SEPA direct debit or Klarna, processed by Stripe.",
|
||||
yourOrderHeading: "Your Order",
|
||||
shippingWithCount: (count) => `Shipping (${count} item${count === 1 ? "" : "s"})`,
|
||||
shippingPickup: "Shipping (pickup)",
|
||||
|
||||
Reference in new issue
Block a user