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
+30 -4
View File
@@ -1709,6 +1709,7 @@ a:focus-visible, button:focus-visible {
}
@media (prefers-reduced-motion: reduce) { .order-card, .order-card::after { animation: none; } }
.order-card-zahlungOffen { --status-color: #e08a3c; }
.order-card-bezahlt { --status-color: #9b7fd6; }
.order-card-bearbeitung { --status-color: #e3b23c; }
.order-card-versandVorbereitet { --status-color: #e3b23c; }
@@ -1718,6 +1719,7 @@ a:focus-visible, button:focus-visible {
.order-status { display: inline-flex; align-items: center; gap: 0.4em; }
.order-status::before { font-size: 0.95em; }
.order-status-zahlungOffen::before { content: "⏳"; }
.order-status-bezahlt::before { content: "💳"; }
.order-status-bearbeitung::before { content: "⚙️"; }
.order-status-versandVorbereitet::before { content: "📦"; }
@@ -1725,6 +1727,7 @@ a:focus-visible, button:focus-visible {
.order-status-abgeschlossen::before { content: "✅"; }
.order-status-storniert::before { content: "❌"; }
.order-status-zahlungOffen { background: color-mix(in srgb, #e08a3c 30%, transparent); border-color: color-mix(in srgb, #e08a3c 55%, transparent); color: #ffd9ae; }
.order-status-bezahlt { background: color-mix(in srgb, #9b7fd6 32%, transparent); border-color: color-mix(in srgb, #9b7fd6 55%, transparent); color: #d9cdf5; }
.order-status-bearbeitung { background: color-mix(in srgb, #e3b23c 30%, transparent); border-color: color-mix(in srgb, #e3b23c 55%, transparent); color: #f6dda0; }
.order-status-versandVorbereitet { background: color-mix(in srgb, #e3b23c 30%, transparent); border-color: color-mix(in srgb, #e3b23c 55%, transparent); color: #f6dda0; }
@@ -2368,10 +2371,33 @@ a:focus-visible, button:focus-visible {
.pay-connect-btn[disabled] { opacity: 0.75; cursor: default; }
.pay-connect-status { margin: 0.7em 0 0; font-size: 0.88rem; color: var(--c-accent); font-weight: 600; }
/* Inline-Kartenformular (Kreditkarte) */
.card-fields { display: grid; gap: 0.7rem; }
.card-fields label { display: block; font-size: 0.8rem; color: var(--c-text-muted); margin-bottom: 0.3rem; }
.card-fields input { font-variant-numeric: tabular-nums; letter-spacing: 0.03em; }
/* Kleine Visa/Mastercard-Hinweis-Badges direkt neben "PayPal" — zeigt, dass Kartenzahlung über
den PayPal-Gast-Checkout ebenfalls möglich ist (Kartendaten laufen dabei komplett über PayPals
eigene, PCI-DSS-zertifizierte Oberfläche, nie über unsere Seite — siehe Recherche zur
Kreditkarten-Rechtslage: eine eigene Karten-Eingabemaske wäre PCI-DSS-pflichtig und für einen
kleinen Shop praktisch nicht stemmbar). */
.pay-sub-cards { display: inline-flex; align-items: center; gap: 0.3em; margin-left: 0.5em; vertical-align: middle; }
.pay-sub-cards .mini-card { width: 26px; height: 18px; border-radius: 4px; }
.pay-sub-cards .mini-card svg { width: 16px; height: auto; }
/* Der große "Jetzt zahlungspflichtig bestellen"-Knopf gehört NUR zur Überweisung (Vorkasse) —
bei PayPal läuft die Zahlung ausschließlich über die echten PayPal-Smart-Buttons oben (siehe
#paypal-button-container), die selbst die Bestellung auslösen, sobald die Zahlung bei PayPal
bestätigt ist. Der Knopf würde bei ausgewähltem PayPal sonst fälschlich eine "Bestellung ohne
Zahlung" ermöglichen — deshalb hier komplett ausgeblendet, kein Fallback, keine Ausnahme. */
#checkout-form:has(input[name="pay"][value="paypal"]:checked) #order-submit-btn { display: none; }
#checkout-form:has(input[name="pay"][value="paypal"]:checked) #order-submit-hint { display: block; }
#order-submit-hint {
display: none;
margin: 0 0 1rem;
padding: 0.9em 1.1em;
border-radius: var(--radius-m);
border: 1px solid color-mix(in srgb, var(--c-accent) 35%, transparent);
background: color-mix(in srgb, var(--c-accent) 8%, transparent);
font-size: 0.88rem;
color: var(--c-text-muted);
text-align: center;
}
/* Bankverbindung (Vorkasse) — echte, direkt aus dem Adminbereich gespeiste Kontodaten. */
.bank-details {