Live Demo: Teste dieses und weitere Plugins live — ohne Installation, ohne Risiko: demo.markus-michalski.net
Das Plugin bietet anderen Plugins drei Anknüpfungspunkte: ein Event bei neuen Mandaten, einen Service für den Zugriff auf Mandate und HTTP-Routen für Admin und Storefront.
| Eigenschaft | Wert |
|---|---|
| Event-Name | mmd.sepa_payment.mandate.created |
| Klasse | Mmd\SepaPayment\Event\MandateCreatedEvent |
| Konstante | MandateCreatedEvent::EVENT_NAME |
Das Event wird ausgelöst, nachdem ein neues Mandat beim Abschluss einer Bestellung gespeichert wurde. Es wird nicht ausgelöst, wenn ein bestehendes Mandat wiederverwendet wird, und nicht, wenn ein Kunde sein Mandat auf der Kundenkonto-Seite anlegt.
Das Event wird unter seinem Namen ausgelöst. Abonniere deshalb den String
mmd.sepa_payment.mandate.created, ein Abonnement über den Klassennamen wird nicht ausgelöst.
| Methode | Rückgabe | Beschreibung |
|---|---|---|
getMandateId() |
string |
UUID des neuen Mandats |
getCustomerId() |
string |
UUID des Kunden |
getOrderId() |
string |
UUID der Bestellung, bei der das Mandat entstanden ist |
getContext() |
Context |
Shopware-Kontext |
getMandate() |
?SepaMandateEntity |
Das gespeicherte Mandat; die IBAN darin ist verschlüsselt |
<?php
namespace MyPlugin\Subscriber;
use Mmd\SepaPayment\Event\MandateCreatedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class SepaMandateSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'mmd.sepa_payment.mandate.created' => 'onMandateCreated',
];
}
public function onMandateCreated(MandateCreatedEvent $event): void
{
$mandate = $event->getMandate();
if ($mandate === null) {
return;
}
// Beispiel: Mandatsdaten an ein ERP-System übergeben
$reference = $mandate->getMandateReference();
$holder = $mandate->getAccountHolder();
$orderId = $event->getOrderId();
}
}
Soll dein Plugin das SEPA-Plugin nur optional unterstützen, verwende den Event-Namen als String und tippe den Parameter als object, damit keine harte Abhängigkeit auf die Event-Klasse besteht:
public function onMandateCreated(object $event): void
{
$mandateId = $event->getMandateId();
}
Mmd\SepaPayment\Service\Contract\SepaMandateServiceInterface ist als Service registriert (Alias auf SepaMandateService) und kann per Konstruktor injiziert werden.
| Methode | Rückgabe | Beschreibung |
|---|---|---|
createMandate(string $customerId, array $data, Context $context) |
string |
Legt ein Mandat an und gibt dessen ID zurück. $data: iban, accountHolder, optional bic. Wirft InvalidArgumentException bei ungültiger IBAN, ungültigem Kontoinhaber oder BIC und RuntimeException, wenn der Kunde schon ein aktives Mandat hat. Löst kein Event aus. |
updateMandate(string $mandateId, array $data, Context $context) |
void |
Ändert bic und accountHolder. Die IBAN lässt sich nicht ändern. |
revokeMandate(string $mandateId, Context $context) |
void |
Setzt den Status auf revoked und trägt revokedAt ein. Das Mandat bleibt als Datensatz erhalten. |
getMandateByCustomerId(string $customerId, Context $context, bool $activeOnly = true) |
?SepaMandateEntity |
Mandat eines Kunden. Mit activeOnly = false auch widerrufene; bei mehreren Treffern ist die Reihenfolge nicht festgelegt. |
getMandateById(string $mandateId, Context $context) |
?SepaMandateEntity |
Mandat per UUID |
hasActiveMandate(string $customerId, Context $context) |
bool |
Hat der Kunde ein aktives Mandat? |
getDecryptedIban(SepaMandateEntity $mandate) |
string |
Entschlüsselte IBAN. Wirft RuntimeException, wenn die Entschlüsselung scheitert, etwa nach einem geänderten APP_SECRET. |
getMaskedIban(SepaMandateEntity $mandate) |
string |
Maskierte IBAN im Format Ländercode, Prüfziffern, ****, letzte vier Zeichen, zum Beispiel DE89****3000 |
Die Entität SepaMandateEntity bietet unter anderem getMandateReference(), getAccountHolder(), getBic(), getStatus(), getSignedAt(), getRevokedAt(), getCustomerId() sowie isActive() und isRevoked(). getIban() liefert nur die verschlüsselte IBAN. getMaskedIban() an der Entität wirft immer eine Exception, nutze stattdessen den Service.
use Mmd\SepaPayment\Service\Contract\SepaMandateServiceInterface;
use Shopware\Core\Framework\Context;
class MyService
{
public function __construct(
private readonly SepaMandateServiceInterface $mandateService,
) {
}
public function describe(string $customerId, Context $context): ?array
{
$mandate = $this->mandateService->getMandateByCustomerId($customerId, $context);
if ($mandate === null) {
return null;
}
return [
'reference' => $mandate->getMandateReference(),
'ibanMasked' => $this->mandateService->getMaskedIban($mandate),
'accountHolder' => $mandate->getAccountHolder(),
'signedAt' => $mandate->getSignedAt(),
];
}
}
Die entschlüsselte IBAN ist eine personenbezogene Bankverbindung. Rufe
getDecryptedIban()nur auf, wenn du sie wirklich brauchst, und schreibe sie nicht in Logs.
Alle Routen liegen im API-Scope und verlangen eine Admin-Anmeldung.
| Methode | Pfad | Privileg | Antwort |
|---|---|---|---|
| GET | /api/_action/mmd-sepa-mandate/{mandateId}/pdf |
mmd_sepa_mandate.viewer |
PDF-Datei; 404 mit {"error": "Mandate not found"} |
| POST | /api/_action/mmd-sepa-mandate/{mandateId}/revoke |
mmd_sepa_mandate.editor |
{"success": true}; 404 wenn unbekannt, 400 wenn das Mandat nicht aktiv ist |
| GET | /api/_action/mmd-sepa-mandate/{mandateId}/masked-iban |
mmd_sepa_mandate.viewer |
{"maskedIban": "DE89****3000"}; 404 wenn unbekannt |
Das Plugin registriert die Privilegien
mmd_sepa_mandate.viewerundmmd_sepa_mandate.editornicht in der Rollenverwaltung des Admins. Die Routen sind deshalb nur für Administratoren mit Vollzugriff nutzbar.
Zusätzlich ist die Entität mmd_sepa_mandate über die Standard-Entity-API des Admins erreichbar.
| Methode | Pfad | Routenname | Zweck |
|---|---|---|---|
| GET | /account/sepa-mandate |
frontend.account.sepa.mandate |
Mandatsseite (Login nötig) |
| POST | /account/sepa-mandate/create |
frontend.account.sepa.mandate.create |
Mandat anlegen (Login nötig) |
| POST | /account/sepa-mandate/revoke |
frontend.account.sepa.mandate.revoke |
Aktives Mandat widerrufen (Login nötig) |
| POST | /account/sepa-mandate/validate-iban |
frontend.account.sepa.mandate.validate-iban |
Gibt {"valid": true} oder {"valid": false} zurück; Login nötig, XHR; höchstens 10 Anfragen pro Minute und IP, danach 429 |
| GET | /account/sepa-mandate/download |
frontend.account.sepa.mandate.download |
PDF des eigenen Mandats (Login nötig) |
| GET | /sepa-mandate/download/{orderId} |
frontend.sepa.mandate.download.order |
PDF über die Bestellung; Besitzer oder deepLinkCode als Query-Parameter |
Das mitgelieferte Checkout-Skript ruft die Route validate-iban nicht auf, es prüft die IBAN im Browser.
Das Plugin speichert keine Verknüpfung zwischen Bestellung und Mandat. Das Mandat gehört zum Kunden. Die Bestellung erfährst du nur im MandateCreatedEvent über getOrderId().
Das Event eignet sich, um Mandatsdaten an eigene Systeme zu melden, etwa an ein ERP, ein CRM oder eine Buchhaltung, oder um eine Benachrichtigung auszulösen. Solche Integrationen liefert das Plugin nicht mit, du baust sie über das Event selbst.