Automatische Verbuchung von PayPal-Zahlungen per Mail-Weiterleitung

Mandanten leiten ihre PayPal-Benachrichtigungsmails an ein zentrales
IMAP-Postfach weiter. Die Zuordnung zum Mandanten erfolgt ueber
Plus-Adressierung (zahlungen+<token>@...), der Token wird pro Mandant
erzeugt und im Backend angezeigt.

- Parser fuer PayPal-Eingangsmails, tolerant gegenueber falsch kodierten
  Waehrungssymbolen und HTML-Struktur weitergeleiteter Mails
- Gutgeschrieben wird der Nettobetrag, also was tatsaechlich ankam
  (bei Waren & Dienstleistungen nach Abzug der PayPal-Gebuehr)
- Deduplizierung ueber den Transaktionscode, damit doppelt weitergeleitete
  Mails nicht doppelt buchen
- Eindeutiger Namens-Match bucht automatisch, alles andere landet in einer
  Warteschlange zur manuellen Zuordnung
- Absenderpruefung gegen paypal.de/.com, da weitergeleitete Mails keine
  gueltige SPF/DKIM-Signatur mehr haben
- IMAP-Zugang ausschliesslich ueber Server-/Env-Einstellungen, nicht pro
  Mandant konfigurierbar

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 18:33:49 +02:00
co-authored by Claude Opus 4.8
parent c16b105f00
commit ea7d9a4714
7 changed files with 868 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
-- Automatischer PayPal-Abgleich per weitergeleiteter Benachrichtigungsmail.
--
-- Jeder Mandant bekommt einen eindeutigen Token fuer die Plus-Adresse
-- (z. B. zahlungen+<token>@domain). Der Admin richtet eine Weiterleitung von
-- PayPal an diese Adresse ein; der Token ordnet die Mail eindeutig dem
-- Mandanten zu. Der Token ist nicht sensibel und wird bei Bedarf erzeugt.
ALTER TABLE tenants
ADD COLUMN paypal_inbox_token VARCHAR(32) NULL AFTER slug,
ADD UNIQUE KEY uq_tenants_paypal_inbox_token (paypal_inbox_token);
-- Erkannte PayPal-Zahlungen: Dedup ueber den global eindeutigen
-- Transaktionscode und gleichzeitig Warteschlange fuer nicht eindeutig
-- zuordenbare Zahlungen (participant_id IS NULL, status 'unmatched').
CREATE TABLE IF NOT EXISTS paypal_payments (
id INT AUTO_INCREMENT PRIMARY KEY,
tenant_id INT NOT NULL,
transaction_code VARCHAR(40) NOT NULL,
payer_name VARCHAR(255) NOT NULL DEFAULT '',
note VARCHAR(255) NULL,
gross_cents INT NOT NULL DEFAULT 0,
fee_cents INT NULL,
net_cents INT NOT NULL DEFAULT 0,
paid_at DATE NULL,
participant_id INT NULL,
ledger_entry_id INT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'unmatched',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_paypal_payments_txn (transaction_code),
KEY idx_paypal_payments_tenant_status (tenant_id, status),
CONSTRAINT fk_paypal_payments_tenant
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
CONSTRAINT fk_paypal_payments_participant
FOREIGN KEY (participant_id) REFERENCES participants(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;