Markus Michalski FAQ

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.

English Version

Zurück zur Übersicht

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():

  1. Ohne Kunden-ID wird die Zahlung abgebrochen.
  2. Mit sepaUseExistingMandate=true muss ein aktives Mandat des Kunden existieren.
  3. Sonst müssen sepaIban, sepaAccountHolder und sepaMandateAgreement=true vorhanden und die IBAN gültig sein. Die IBAN wird danach verschlüsselt in einem Struct an pay() übergeben.

Ablauf in pay():

  1. Bei bestehendem Mandat passiert nichts weiter.
  2. 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.
  3. Danach löst er das MandateCreatedEvent aus.

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

Hinweise