SEPA-Lastschrift: Technische Details
Technischer Aufbau der SEPA-Lastschrift für Shopware 6.7: Ablauf im Payment-Handler, Services, Tabelle mmd_sepa_mandate, Migrationen, Templates und die Admin- und Storefront-Erweiterungen.
SEPA-Lastschrift: Technische Details
Live Demo: Teste dieses und weitere Plugins live — ohne Installation, ohne Risiko: demo.markus-michalski.net
Ablauf im Payment-Handler
Mmd\SepaPayment\Payment\SepaPaymentHandler erweitert AbstractPaymentHandler und ist als shopware.payment.method registriert. Die Zahlung ist synchron, es gibt keine Weiterleitung. Der Handler unterstützt weder Erstattungen noch wiederkehrende Zahlungen (supports() liefert immer false).
sequenceDiagram
participant K as Kunde
participant H as SepaPaymentHandler
participant S as SepaMandateService
participant D as Datenbank
participant E as EventDispatcher
K->>H: validate - Checkout absenden
H->>H: Bestehendes Mandat prüfen oder IBAN, Kontoinhaber, Zustimmung prüfen
H->>H: IBAN verschlüsseln und im Struct weitergeben
Note over K,H: Bestellung wird angelegt
K->>H: pay
H->>S: Altes aktives Mandat widerrufen
H->>S: createMandate
S->>D: Mandat speichern
H->>E: MandateCreatedEvent
Ablauf in validate():
- Ohne Kunden-ID wird die Zahlung abgebrochen.
- Mit
sepaUseExistingMandate=truemuss ein aktives Mandat des Kunden existieren. - Sonst müssen
sepaIban,sepaAccountHolderundsepaMandateAgreement=truevorhanden und die IBAN gültig sein. Die IBAN wird danach verschlüsselt in einem Struct anpay()übergeben.
Ablauf in pay():
- Bei bestehendem Mandat passiert nichts weiter.
- Sonst lädt der Handler Bestellung und Kunden, widerruft ein vorhandenes aktives Mandat und legt das neue an. Meldet das Anlegen, dass der Kunde schon ein aktives Mandat hat (parallele Anfrage), widerruft der Handler dieses und versucht es einmal erneut.
- Danach löst er das
MandateCreatedEventaus.
Komponenten
| Klasse | Aufgabe |
|---|---|
MmdSepaPayment |
Plugin-Klasse; legt die Zahlungsart an, (de)aktiviert sie und entfernt bei der Deinstallation ohne Datenerhalt Tabelle und Konfiguration |
Service\SepaMandateService |
Anlegen, Ändern, Widerrufen und Lesen von Mandaten |
Service\EncryptionService |
AES-256-GCM-Verschlüsselung der IBAN, Schlüssel per HKDF-SHA256 aus APP_SECRET |
Service\IbanValidator |
Normalisierung, Format-, Längen- und Modulo-97-Prüfung, Maskierung |
Service\MandateReferenceGenerator |
Erzeugt {Präfix}{JJJJMMTT}-{8 Zeichen} |
Service\MandatePdfGenerator |
Rendert das Twig-Template documents/sepa-mandate.html.twig mit dompdf zu einem A4-PDF |
Service\PaymentMethodInstaller |
Legt die Zahlungsart payment_sepa_direct_debit an |
Subscriber\CheckoutSubscriber |
Stellt auf der Bestätigungs- und der Abschlussseite des Checkouts das aktive Mandat samt maskierter IBAN als Seitenerweiterung mmdSepaMandate bereit |
Storefront\Controller\SepaMandateController |
Kundenkonto-Seite, Anlegen, Widerruf, IBAN-Prüfung, PDF-Downloads |
Controller\Api\SepaMandateController |
Admin-Routen für PDF, Widerruf und maskierte IBAN |
Event\MandateCreatedEvent |
Event für andere Plugins |
Die Services sind über die Interfaces in Service\Contract austauschbar, zum Beispiel SepaMandateServiceInterface, IbanValidatorInterface und EncryptionServiceInterface.
Datenbank
Tabelle mmd_sepa_mandate (Entität mmd_sepa_mandate):
| Spalte | Typ | Hinweis |
|---|---|---|
id |
BINARY(16) | Primärschlüssel |
customer_id |
BINARY(16) | Fremdschlüssel auf customer.id, ON DELETE CASCADE |
mandate_reference |
VARCHAR(255) | Eindeutig |
iban |
LONGTEXT | Base64 aus Initialisierungsvektor, Auth-Tag und verschlüsselten Daten |
bic |
VARCHAR(11) | Optional, unverschlüsselt |
account_holder |
VARCHAR(255) | |
status |
VARCHAR(50) | active, revoked, expired; Standard active |
signed_at |
DATETIME(3) | |
revoked_at |
DATETIME(3) | Optional |
created_at, updated_at |
DATETIME(3) |
Indizes: eindeutig auf mandate_reference, normal auf status, auf customer_id und auf (customer_id, status). Die zweite Migration entfernt die ursprüngliche Eindeutigkeit auf customer_id. Mehrere Datensätze pro Kunde sind damit möglich, dass es höchstens ein aktives Mandat gibt, stellt die Anwendungslogik sicher, nicht die Datenbank.
Ablage im System
| Was | Wo |
|---|---|
| Zahlungsart | payment_method, technischer Name payment_sepa_direct_debit, afterOrderEnabled aus, Position 10 |
| Konfiguration | system_config, Schlüssel MmdSepaPayment.config.* |
| Storefront-Texte | Snippet-Dateien mmd-sepa-payment.de-DE.json und mmd-sepa-payment.en-GB.json, Namensraum mmdSepaPayment |
| Admin-Modul | mmd-sepa-mandate, Menüeintrag unter "Bestellungen" |
Storefront und Admin
- Templates: Das Plugin erweitert
payment-method.html.twig(Felder im Checkout), die Seitenleiste des Kundenkontos, die Bestelldetails und die Bestellabschluss-Details. - JavaScript: Das Storefront-Plugin
SepaPaymentFieldsPluginformatiert IBAN und BIC, prüft die IBAN im Browser und übergibt die Felder an das Bestellformular. - Admin: Liste und Detailseite des Moduls
mmd-sepa-mandatemit PDF-Button; der Widerruf in der Detailseite speichert Status und Zeitpunkt über das Repository.
Hinweise
- Die serverseitige Modulo-97-Prüfung nutzt
bcmod()aus der PHP-Erweiterung bcmath. - Der Rate-Limit-Zähler der Route
validate-ibanliegt im Anwendungs-Cache (cache.app).