Zahlungsarten überarbeitet: echtes PayPal, Klarna & eigene Kartenmaske raus

Auf ausdrücklichen Wunsch, mit Fokus auf rechtliche Absicherung:

- Klarna komplett entfernt (hätte eigene Händlerprüfung + Bonitätsprüfungs-
  Pflichten nach der neuen EU-Verbraucherkreditrichtlinie vorausgesetzt).
- Eigene Kreditkarten-Eingabemaske komplett entfernt (wäre PCI-DSS-pflichtig
  gewesen — für einen kleinen Shop praktisch nicht stemmbar). Kartenzahlung
  bleibt möglich: PayPals eigener, PCI-zertifizierter Gast-Checkout bietet
  Kredit-/Debitkarte an, ohne dass Kartendaten je unsere Seite berühren.
- PayPal ist jetzt ECHT server-seitig verifiziert statt dem Browser blind zu
  vertrauen: eigener Cloudflare-Function-Flow (functions/_shared/paypal.js +
  functions/api/paypal/) legt die PayPal-Bestellung server-seitig an, zieht
  die Zahlung nach Bestätigung server-seitig ein und prüft den eingezogenen
  Betrag gegen die Bestellsumme — die Bestellung wird ausschließlich bei
  bestätigter, betragsgleicher Zahlung angelegt. /api/orders lehnt direkte
  PayPal-Bestellungen jetzt ausdrücklich ab (verhindert vorgetäuschte
  "bezahlte" Bestellungen ohne echte Zahlung).
- Neuer, ehrlicherer Bestellstatus "zahlungOffen": Überweisungs-Bestellungen
  starten jetzt so (Geld noch nicht da) statt fälschlich sofort "bezahlt" zu
  heißen — Schutz vor Warenversand, bevor das Geld wirklich angekommen ist.
  Eigene Kachel/Filter/Badge-Farbe in der Verwaltung, Umsatz-/Auswertungs-
  Zahlen zählen "zahlungOffen" bewusst nicht mit.
- Rechtstexte (AGB, Datenschutzerklärung, FAQ, Versand & Zahlung) auf allen
  4 Sprachen aktualisiert: nur noch PayPal + Überweisung erwähnt, inkl. DSGVO-
  Hinweis zur internationalen Datenübertragung an PayPal (Data Privacy
  Framework-Zertifizierung).
- D1-Migration 0003: neue Spalte paypal_order_id (Zahlungsbeleg) + erweiterter
  Status-Wertebereich, auf Live-Datenbank angewendet, bestehende Daten intakt.

Mit echten Testbestellungen lokal verifiziert: Überweisung legt korrekt
"zahlungOffen" an, direkter PayPal-Bypass-Versuch an /api/orders wird
abgelehnt, PayPal-Route meldet sauber "noch nicht eingerichtet" ohne
Zugangsdaten. Checkout-UI zeigt nur noch 2 Zahlungsarten, Bestellknopf ist bei
PayPal ausgeblendet (Zahlung läuft exklusiv über den echten PayPal-Button).

Für den echten Zahlungseingang fehlt noch VanVans eigenes PayPal-Business-
Konto (Client-ID + Secret) — Details in der Vault-Dokumentation.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
qcigano
2026-08-04 01:06:41 +02:00
co-authored by Claude Sonnet 5
parent 98028df4ea
commit 81c175d03c
18 changed files with 1077 additions and 743 deletions
+24 -32
View File
@@ -151,7 +151,7 @@ export const ui = {
"Versandkostenfrei ab 75 € Warenwert (Deutschland), 85 € (Österreich, Luxemburg) bzw. 100 € (Schweiz)", "Der Versand erfolgt erst nach Zahlungseingang",
"Bei Lieferungen in die Schweiz können Schweizer Einfuhrumsatzsteuer und Zollgebühren anfallen, die von dir als Empfänger:in getragen werden",
],
paymentTitle: "💳 Zahlungsarten", paymentItems: ["PayPal", "Klarna", "Kreditkarte (Visa & Mastercard)", "Banküberweisung (Vorkasse)"],
paymentTitle: "💳 Zahlungsarten", paymentItems: ["PayPal", "Kredit-/Debitkarte als Gast über PayPal (Visa & Mastercard)", "Banküberweisung (Vorkasse)"],
todoNote: "Konkrete Versandkosten-Staffel je Land/Warenwert wird ergänzt, sobald VanVan die finalen DHL-Konditionen festgelegt hat.",
},
cart: {
@@ -177,7 +177,7 @@ export const ui = {
},
checkout: {
eyebrow: "Checkout", title: "Bestellung abschließen",
todoNote: "Phase 1 Demo-Checkout. Es findet noch keine echte Zahlung statt. Die vollständige Anbindung an PayPal, Klarna und Banküberweisung sowie die Bestellverwaltung folgen in Phase 2 (Cloudflare Worker + D1, siehe Tech-Stack-Entscheidung im Projekt-Vault).",
todoNote: "PayPal ist technisch fertig angebunden (echte, server-seitig geprüfte Zahlung) — bis ein echtes PayPal-Business-Konto hinterlegt ist, läuft es im kostenlosen PayPal-Testmodus, ohne dass echtes Geld fließt. Banküberweisung ist zu 100 % echt.",
step1: "2. Kontakt & Lieferadresse", email: "E-Mail", firstName: "Vorname", lastName: "Nachname",
street: "Straße & Hausnummer", zip: "PLZ", city: "Ort", country: "Land",
step2: "1. Zahlungsart",
@@ -185,12 +185,10 @@ export const ui = {
revocationPrefix: "Ich habe die", revocationLink: "Widerrufsbelehrung", revocationAnd: "und",
privacyLink: "Datenschutzerklärung", revocationSuffix: "zur Kenntnis genommen.",
bankTransfer: "Banküberweisung (Vorkasse)", orderButton: "Jetzt zahlungspflichtig bestellen", emptyCartAlert: "Dein Warenkorb ist leer.",
creditCard: "Kreditkarte", creditCardSub: "Visa & Mastercard",
payPalHint: "Bezahle sicher und schnell direkt mit deinem PayPal-Konto.",
klarnaHint: "Rechnung, Ratenkauf oder Sofortüberweisung wähle bei Klarna, wie du zahlen möchtest.",
klarnaConnect: "Weiter zu Klarna →", klarnaConnecting: "Verbinde mit Klarna …", klarnaConnected: "Verbindung zu Klarna hergestellt (Demo)",
cardHint: "Deine Kartendaten werden sicher übertragen.", cardNumber: "Kartennummer", cardExpiry: "Gültig bis", cardCvc: "CVC",
bankHintReal: "Bitte überweise den Rechnungsbetrag nach Bestellabschluss an folgendes Konto. Deine Ware wird nach Zahlungseingang verschickt.",
payPalSub: "auch mit Kreditkarte, ohne eigenes Konto",
payPalHint: "Bezahle sicher direkt mit deinem PayPal-Konto oder als Gast per Kredit-/Debitkarte deine Kartendaten laufen dabei ausschließlich über PayPals eigene, gesicherte Seite, nie über unsere.",
payPalCompleteHint: "Schließe deine Bestellung oben über den PayPal-Button ab dort bezahlst du direkt, danach ist deine Bestellung sofort da.",
bankHintReal: "Bitte überweise den Rechnungsbetrag nach Bestellabschluss an folgendes Konto. Deine Ware wird erst nach Zahlungseingang verschickt.",
bankPlaceholder: "Die Bankverbindung wird dir nach Bestelleingang per E-Mail zugesendet.",
bankHolder: "Kontoinhaber:in", bankIban: "IBAN", bankBic: "BIC", bankBankName: "Bank",
shippingHintTitle: "Versandhinweis",
@@ -455,7 +453,7 @@ export const ui = {
"Free shipping from €75 order value (Germany), €85 (Austria, Luxembourg) or €100 (Switzerland)", "Shipping only starts after payment has been received",
"Deliveries to Switzerland may be subject to Swiss import VAT and customs fees, payable by you as the recipient",
],
paymentTitle: "💳 Payment methods", paymentItems: ["PayPal", "Klarna", "Credit card (Visa & Mastercard)", "Bank transfer (prepayment)"],
paymentTitle: "💳 Payment methods", paymentItems: ["PayPal", "Credit/debit card as a guest via PayPal (Visa & Mastercard)", "Bank transfer (prepayment)"],
todoNote: "Concrete shipping-cost tiers per country/order value will be added once VanVan finalizes the DHL terms.",
},
cart: {
@@ -481,7 +479,7 @@ export const ui = {
},
checkout: {
eyebrow: "Checkout", title: "Complete your order",
todoNote: "Phase 1 demo checkout. No real payment is processed yet. Full integration with PayPal, Klarna and bank transfer, plus order management, follow in Phase 2 (Cloudflare Worker + D1, see the tech-stack decision in the project vault).",
todoNote: "PayPal is technically fully connected (real, server-verified payment) — until a real PayPal Business account is set up, it runs in PayPal's free test mode, so no real money moves yet. Bank transfer is 100% real.",
step1: "2. Contact & shipping address", email: "Email", firstName: "First name", lastName: "Last name",
street: "Street & house number", zip: "ZIP code", city: "City", country: "Country",
step2: "1. Payment method",
@@ -489,12 +487,10 @@ export const ui = {
revocationPrefix: "I have taken note of the", revocationLink: "withdrawal notice", revocationAnd: "and",
privacyLink: "privacy policy", revocationSuffix: ".",
bankTransfer: "Bank transfer (prepayment)", orderButton: "Order now, subject to payment", emptyCartAlert: "Your cart is empty.",
creditCard: "Credit card", creditCardSub: "Visa & Mastercard",
payPalHint: "Pay securely and instantly with your PayPal account.",
klarnaHint: "Invoice, installments or instant transfer choose how you'd like to pay with Klarna.",
klarnaConnect: "Continue to Klarna →", klarnaConnecting: "Connecting to Klarna …", klarnaConnected: "Connected to Klarna (demo)",
cardHint: "Your card details are transmitted securely.", cardNumber: "Card number", cardExpiry: "Expiry", cardCvc: "CVC",
bankHintReal: "Please transfer the invoice amount to the following account after completing your order. Your items ship once payment is received.",
payPalSub: "also with credit card, no account needed",
payPalHint: "Pay securely with your PayPal account or as a guest by credit/debit card your card details are handled entirely on PayPal's own secure page, never on ours.",
payPalCompleteHint: "Complete your order via the PayPal button above you pay there directly, and your order is placed right after.",
bankHintReal: "Please transfer the invoice amount to the following account after completing your order. Your items ship only once payment is received.",
bankPlaceholder: "Bank details will be sent to you by email after your order.",
bankHolder: "Account holder", bankIban: "IBAN", bankBic: "BIC", bankBankName: "Bank",
shippingHintTitle: "Shipping note",
@@ -759,7 +755,7 @@ export const ui = {
"Gratisversand ab 75 € Warewärt (Dütschland), 85 € (Öschterrych, Luxemburg) bzw. 100 € (Schwiz)", "Dr Versand geit erscht los, wenn d'Zahlig igange isch",
"Bi Liefrige i d'Schwiz chöi schwyzerischi Iifuehrumsatzsteuer und Zollgebühre afalle, wo du als Empfänger:in trage muesch",
],
paymentTitle: "💳 Zahligsarte", paymentItems: ["PayPal", "Klarna", "Kreditkarte (Visa & Mastercard)", "Banküberwysig (Vorusszahlig)"],
paymentTitle: "💳 Zahligsarte", paymentItems: ["PayPal", "Kredit-/Debitkarte als Gast über PayPal (Visa & Mastercard)", "Banküberwysig (Vorusszahlig)"],
todoNote: "Di gnaui Versandchoschte-Staffle je Land/Warewärt wird ergänzt, sobald VanVan di definitive DHL-Konditione festgleit hät.",
},
cart: {
@@ -785,7 +781,7 @@ export const ui = {
},
checkout: {
eyebrow: "Checkout", title: "Bschtellig abschliesse",
todoNote: "Phase 1 Demo-Checkout. Es git no kei echti Zahlig. D'vollständigi Aabindig a PayPal, Klarna und Banküberwysig sowie d'Bstellverwaltig chöme i Phase 2.",
todoNote: "PayPal isch technisch fertig aabunde (echti, server-seitig gprüefti Zahlig) — bis es echts PayPal-Business-Konto hinterlegt isch, laufts im gratis PayPal-Testmodus, ohni dass echts Gäld flüsst. Banküberwysig isch zu 100 % echt.",
step1: "2. Kontakt & Lieferadrässe", email: "E-Mail", firstName: "Vorname", lastName: "Nachname",
street: "Strasse & Huusnummere", zip: "PLZ", city: "Ort", country: "Land",
step2: "1. Zahligsart",
@@ -793,12 +789,10 @@ export const ui = {
revocationPrefix: "Ich ha d'", revocationLink: "Widerrufsbelehrig", revocationAnd: "und d'",
privacyLink: "Datenschutzerklärig", revocationSuffix: "zur Kenntnis gnoh.",
bankTransfer: "Banküberwysig (Vorusszahlig)", orderButton: "Jetzt zahligspflichtig bstelle", emptyCartAlert: "Din Warenchorb isch leer.",
creditCard: "Kreditkarte", creditCardSub: "Visa & Mastercard",
payPalHint: "Zahl sicher und schnäll dirräkt mit dim PayPal-Konto.",
klarnaHint: "Rächnig, Ratechauf oder Sofortiübrwysig wähl bi Klarna, wie du zahle wosch.",
klarnaConnect: "Wyter zu Klarna →", klarnaConnecting: "Verbindet mit Klarna …", klarnaConnected: "Verbindig zu Klarna hergstellt (Demo)",
cardHint: "Dini Kartedate werde sicher übertreit.", cardNumber: "Kartenummere", cardExpiry: "Gültig bis", cardCvc: "CVC",
bankHintReal: "Bitte überwys dr Rächnigsbetrag nach Bstellabschluss uf das Konto. Dini Ware wird nach Zahligsigang verschickt.",
payPalSub: "au mit Kreditkarte, ohni eigenes Konto",
payPalHint: "Zahl sicher dirräkt mit dim PayPal-Konto oder als Gast mit Kredit-/Debitkarte dini Kartedate laufe dabi nur über PayPals eigeni, gsicherti Site, nie über üsi.",
payPalCompleteHint: "Schliess dini Bstellig obe über de PayPal-Knopf ab dört zahlsch dirräkt, danach isch dini Bstellig sofort da.",
bankHintReal: "Bitte überwys dr Rächnigsbetrag nach Bstellabschluss uf das Konto. Dini Ware wird erst nach Zahligsigang verschickt.",
bankPlaceholder: "D'Bankverbindig wird dir nach Bstelligang per E-Mail zuegschickt.",
bankHolder: "Kontoinhaber:in", bankIban: "IBAN", bankBic: "BIC", bankBankName: "Bank",
shippingHintTitle: "Versandhinwys",
@@ -1063,7 +1057,7 @@ export const ui = {
"Livraison gratuite dès 75 € d'achat (Allemagne), 85 € (Autriche, Luxembourg) ou 100 € (Suisse)", "L'expédition n'a lieu qu'après réception du paiement",
"Pour les livraisons en Suisse, la TVA à l'importation suisse et des frais de douane peuvent s'appliquer, à la charge du/de la destinataire",
],
paymentTitle: "💳 Moyens de paiement", paymentItems: ["PayPal", "Klarna", "Carte bancaire (Visa & Mastercard)", "Virement bancaire (paiement anticipé)"],
paymentTitle: "💳 Moyens de paiement", paymentItems: ["PayPal", "Carte bancaire en tant qu'invité via PayPal (Visa & Mastercard)", "Virement bancaire (paiement anticipé)"],
todoNote: "Le barème précis des frais de port par pays/valeur de commande sera ajouté dès que VanVan aura fixé les conditions DHL définitives.",
},
cart: {
@@ -1089,7 +1083,7 @@ export const ui = {
},
checkout: {
eyebrow: "Paiement", title: "Finaliser la commande",
todoNote: "Phase 1 paiement de démonstration. Aucun paiement réel n'est encore traité. L'intégration complète avec PayPal, Klarna et le virement bancaire, ainsi que la gestion des commandes, suivront en phase 2.",
todoNote: "PayPal est techniquement entièrement connecté (paiement réel, vérifié côté serveur) — tant qu'aucun compte PayPal Business réel n'est configuré, il fonctionne en mode test gratuit de PayPal, sans transfert d'argent réel. Le virement bancaire est 100 % réel.",
step1: "2. Contact & adresse de livraison", email: "E-mail", firstName: "Prénom", lastName: "Nom",
street: "Rue & numéro", zip: "Code postal", city: "Ville", country: "Pays",
step2: "1. Moyen de paiement",
@@ -1097,12 +1091,10 @@ export const ui = {
revocationPrefix: "J'ai pris connaissance de la", revocationLink: "notice de rétractation", revocationAnd: "et de la",
privacyLink: "politique de confidentialité", revocationSuffix: ".",
bankTransfer: "Virement bancaire (paiement anticipé)", orderButton: "Commander avec obligation de paiement", emptyCartAlert: "Votre panier est vide.",
creditCard: "Carte bancaire", creditCardSub: "Visa & Mastercard",
payPalHint: "Payez en toute sécurité et instantanément avec votre compte PayPal.",
klarnaHint: "Facture, paiement en plusieurs fois ou virement instantané choisissez comment payer avec Klarna.",
klarnaConnect: "Continuer vers Klarna →", klarnaConnecting: "Connexion à Klarna …", klarnaConnected: "Connecté à Klarna (démo)",
cardHint: "Vos données de carte sont transmises en toute sécurité.", cardNumber: "Numéro de carte", cardExpiry: "Date d'expiration", cardCvc: "CVC",
bankHintReal: "Veuillez virer le montant de la facture sur le compte suivant après avoir finalisé votre commande. Vos articles sont expédiés dès réception du paiement.",
payPalSub: "aussi par carte bancaire, sans compte",
payPalHint: "Payez en toute sécurité avec votre compte PayPal ou en tant qu'invité par carte bancaire vos données de carte transitent uniquement par le site sécurisé de PayPal, jamais par le nôtre.",
payPalCompleteHint: "Finalisez votre commande via le bouton PayPal ci-dessus vous y payez directement, votre commande est passée juste après.",
bankHintReal: "Veuillez virer le montant de la facture sur le compte suivant après avoir finalisé votre commande. Vos articles ne sont expédiés qu'après réception du paiement.",
bankPlaceholder: "Les coordonnées bancaires vous seront envoyées par e-mail après votre commande.",
bankHolder: "Titulaire du compte", bankIban: "IBAN", bankBic: "BIC", bankBankName: "Banque",
shippingHintTitle: "Remarque sur la livraison",