PayPal-Mailabruf: Parken statt Buchen, echter Probelauf, Regressionstest

Die Mail-Verarbeitung ignorierte bisher die PayPal-Schalter: eingehende
Zahlungen wurden auch dann automatisch gutgeschrieben, wenn der Betreiber
die Funktion gesperrt oder der Mandant PayPal abgeschaltet hatte. Jetzt
wird die Zahlung in dem Fall geparkt - gespeichert, aber ohne Buchung.
Wegwerfen liesse eine echte Zahlung unbemerkt verschwinden, buchen
widersprache der Abschaltung; die Zuordnungsseite bleibt fuer offene
Zahlungen ja erreichbar.

--dry-run war bisher irrefuehrend: es liess die Verarbeitung samt Buchung
laufen und uebersprang nur das Setzen des Gelesen-Flags - ausgerechnet beim
ersten Testlauf haette es also echtes Geld verbucht. Der Probelauf nutzt
jetzt paypal_preview(), das nichts schreibt und meldet, was passieren
wuerde (would_book/would_queue/would_park/duplicate).

scripts/check-paypal-inbox-flow.php deckt die Kette ohne IMAP ab:
Absenderpruefung, Token, Parser, Zuordnung, Netto-Buchung, Dedup, beide
Park-Faelle und die Schreibfreiheit der Vorschau.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 20:43:58 +02:00
co-authored by Claude Opus 5
parent 7df9c1fb4e
commit 9f9e4c7cd0
5 changed files with 329 additions and 8 deletions
+18
View File
@@ -186,3 +186,21 @@ weiterhin ausschließlich seinen eigenen Mandanten. Ein zweiter,
eingeloggter, aber nicht privilegierter Testnutzer bekommt auf
`backoffice.php` korrekt `403 Forbidden`. Alle Testdaten anschließend
vollständig entfernt.
## Eingehende PayPal-Mails bei abgeschalteter Funktion
Stand: 2026-08-21. Die Mail-Verarbeitung
(`scripts/fetch-paypal-payments.php``paypal_reconcile()`) prüft
dieselben zwei Ebenen wie das Menü. Ist PayPal für den Mandanten
abgeschaltet — vom Betreiber (`paypal_inbox`) oder vom Mandanten selbst
(`paypal_enabled`) —, wird eine eingehende Zahlung **geparkt**: sie wird
gespeichert (Status `unmatched`, Ergebnis `parked`), aber nicht
automatisch gutgeschrieben.
- **Warum nicht wegwerfen:** eine echte Zahlung würde unbemerkt
verschwinden; das Geld ist ja trotzdem angekommen.
- **Warum nicht buchen:** es soll gerade nichts über PayPal laufen — die
Entscheidung gehört dem Mandanten.
- Die Zuordnungsseite bleibt für offene Zahlungen erreichbar (siehe
`paypal_inbox_accessible()`), der Mandant sieht die geparkte Zahlung
also und kann sie zuordnen oder abhaken.
+30
View File
@@ -236,6 +236,36 @@ dieselbe Mailbox zustellen** (Catch-All), damit die pro Mandant
generierten Adressen `zahlungen+<token>@…` ankommen. IMAP-Zugangsdaten in
`env.local.php` eintragen und die `imap`-Extension auf dem Host prüfen.
### Erster Testlauf
`scripts/fetch-paypal-payments.php --dry-run` fasst nichts an: es meldet
Verbindung, erkannten Mandanten und was mit jeder Mail passieren *würde*
(`would_book` / `would_queue` / `would_park` / `duplicate`), speichert
aber nichts, bucht nichts und markiert keine Mail als gelesen. Erst der
Lauf ohne `--dry-run` verbucht.
Reihenfolge für die Inbetriebnahme:
1. Eingangsadresse des Mandanten holen — sie steht auf
`paypal-zuordnung.php` („PayPal-Zahlungen").
2. Eine echte PayPal-Zahlungsmail dorthin weiterleiten.
3. Task mit `--dry-run` auslösen, Ausgabe kontrollieren.
4. Task ohne `--dry-run` auslösen, Ergebnis in der App prüfen
(Journal-Vorschau bzw. Warteschlange).
5. Erst danach den Task auf den regelmäßigen Takt stellen.
Ohne IMAP lässt sich die Verarbeitung auch mit einer gespeicherten Mail
prüfen:
```
php scripts/fetch-paypal-payments.php --file=mail.html \
--recipient=zahlungen+<token>@kaffeeliste.de --from=service@paypal.de [--dry-run]
```
Die Verarbeitungskette selbst (Absenderprüfung, Token, Parser, Zuordnung,
Buchung, Dedup, Parken) deckt `scripts/check-paypal-inbox-flow.php` als
Regressionstest ab — alles außer der IMAP-Verbindung.
## Deploy-Ablauf für ein Update
1. Lokal committen und pushen.