/* ===================================================================== routes/paypal.js — POST /api/paypal/create-order + /api/paypal/capture-order. 1:1 portiert aus functions/api/paypal/create-order.js + capture-order.js. Der entscheidende Sicherheits- Schritt bleibt unverändert: die Bestellung wird erst NACH server-seitig bei PayPal bestätigter Zahlung angelegt, mit Betragsabgleich (Toleranz 0,02 €). ===================================================================== */ import { Router } from "express"; import { paypalKonfiguriert, erstellePaypalBestellung, erfassePaypalZahlung } from "../lib/paypal.js"; import { erstelleBestellung } from "../lib/bestellung-erstellen.js"; export const paypalRouter = Router(); const BETRAG_TOLERANZ_EURO = 0.02; paypalRouter.post("/api/paypal/create-order", async (req, res) => { if (!paypalKonfiguriert()) { return res.status(503).json({ ok: false, error: "PayPal ist auf dieser Seite noch nicht eingerichtet (fehlende Zugangsdaten). Bitte eine andere Zahlungsart wählen.", }); } const body = req.body || {}; const summe = Number(body.summe); if (!Number.isFinite(summe) || summe <= 0) { return res.status(400).json({ ok: false, error: "Ungültiger Betrag." }); } try { const paypalOrderId = await erstellePaypalBestellung(summe); return res.json({ ok: true, id: paypalOrderId }); } catch (err) { return res.status(502).json({ ok: false, error: err instanceof Error ? err.message : "PayPal-Bestellung fehlgeschlagen." }); } }); paypalRouter.post("/api/paypal/capture-order", async (req, res) => { if (!paypalKonfiguriert()) { return res.status(503).json({ ok: false, error: "PayPal ist auf dieser Seite noch nicht eingerichtet." }); } const body = req.body || {}; const paypalOrderId = typeof body.paypalOrderId === "string" ? body.paypalOrderId.trim() : ""; if (!paypalOrderId) { return res.status(400).json({ ok: false, error: "Fehlende PayPal-Bestell-ID." }); } const summe = Number(body.summe); if (!Number.isFinite(summe) || summe <= 0) { return res.status(400).json({ ok: false, error: "Ungültige Bestellsumme." }); } const zahlung = await erfassePaypalZahlung(paypalOrderId); if (!zahlung.ok) { return res.status(402).json({ ok: false, error: `Zahlung konnte nicht bestätigt werden: ${zahlung.error}` }); } if (Math.abs(zahlung.betragEuro - summe) > BETRAG_TOLERANZ_EURO) { return res.status(402).json({ ok: false, error: `Der bei PayPal gezahlte Betrag (${zahlung.betragEuro.toFixed(2)} €) stimmt nicht mit der Bestellsumme (${summe.toFixed(2)} €) überein.`, }); } const ergebnis = await erstelleBestellung({ ...body, zahlungsart: "paypal" }, { status: "bezahlt", paypalOrderId }); if (!ergebnis.ok) { return res.status(500).json({ ok: false, error: `Deine Zahlung wurde erfolgreich bei PayPal abgebucht (Beleg-ID: ${zahlung.captureId}), aber die Bestellung konnte nicht gespeichert werden. Bitte kontaktiere uns mit dieser Beleg-ID, damit wir das von Hand nachtragen — bitte NICHT erneut bezahlen.`, }); } return res.status(201).json({ ok: true, id: ergebnis.id, bestellnummer: ergebnis.bestellnummer }); });