133 lines
5.0 KiB
PHP
133 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\EventPaymentModules\Modules;
|
|
|
|
use App\EventPaymentModules\AbstractEventPaymentModule;
|
|
use App\EventPaymentModules\DTO\CreateInvoiceRequest;
|
|
use App\Models\PaymentMethod;
|
|
use App\Support\CreditorId;
|
|
use App\Support\Iban;
|
|
|
|
/**
|
|
* SEPA-Basislastschrift -- der Beitrag wird auf Grundlage eines Mandats vom Konto der zahlenden Person
|
|
* eingezogen.
|
|
*
|
|
* Eine Schnittstelle zur Bank gibt es nicht: mareike erzeugt eine Lastschriftdatei (pain.008), die im
|
|
* Online-Banking hochgeladen wird. Bis dahin bleibt der Beitrag offen.
|
|
*
|
|
* Das Gläubigerkonto kommt aus den Bankdaten des Stammes (wie bei der Überweisung, synchronisiert in
|
|
* {@see \App\Domains\Admin\Actions\UpdateTenantPayment\UpdateTenantPaymentAction}); dazu kommen die
|
|
* Gläubiger-ID und der Vorlauf bis zum Einzug.
|
|
*/
|
|
class SepaDirectDebitPaymentModule extends AbstractEventPaymentModule
|
|
{
|
|
public const string OPTION_CREDITOR_ID = 'creditor_id';
|
|
public const string OPTION_PRE_NOTIFICATION_DAYS = 'pre_notification_days';
|
|
|
|
/**
|
|
* Untergrenze des Vorlaufs: ein Bankarbeitstag, den die Bank für eine Basislastschrift braucht,
|
|
* plus der Tag, an dem die Datei hochgeladen wird.
|
|
*/
|
|
public const int MIN_PRE_NOTIFICATION_DAYS = 2;
|
|
|
|
/** Obergrenze: die gesetzliche Standardfrist der Vorabankündigung -- mehr verkürzt nichts mehr. */
|
|
public const int MAX_PRE_NOTIFICATION_DAYS = 14;
|
|
|
|
public static function slug(): string
|
|
{
|
|
return PaymentMethod::PAYMENT_SEPA_DIRECT_DEBIT;
|
|
}
|
|
|
|
public function defaultName(): string
|
|
{
|
|
return 'SEPA-Lastschrift';
|
|
}
|
|
|
|
public function defaultDescription(): ?string
|
|
{
|
|
return 'Der Beitrag wird auf Grundlage eines SEPA-Lastschriftmandats vom angegebenen Konto eingezogen.';
|
|
}
|
|
|
|
public function defaultConfiguration(): array
|
|
{
|
|
return [
|
|
'icon' => 'file-signature',
|
|
self::OPTION_PRE_NOTIFICATION_DAYS => 5,
|
|
];
|
|
}
|
|
|
|
public function getOptions(): array
|
|
{
|
|
$fromTenant = 'Wird aus den Bankdaten des Stammes übernommen.';
|
|
|
|
return [
|
|
['name' => 'account_owner', 'label' => 'Kontoinhaber', 'type' => 'string', 'required' => true, 'hint' => $fromTenant],
|
|
['name' => 'iban', 'label' => 'IBAN', 'type' => 'string', 'required' => true, 'hint' => $fromTenant],
|
|
['name' => 'bic', 'label' => 'BIC', 'type' => 'string', 'required' => false, 'hint' => $fromTenant],
|
|
[
|
|
'name' => self::OPTION_CREDITOR_ID,
|
|
'label' => 'Gläubiger-ID',
|
|
'type' => 'string',
|
|
'required' => true,
|
|
'hint' => 'Die Gläubiger-Identifikationsnummer wird kostenlos bei der Deutschen Bundesbank beantragt '
|
|
. '(glaeubiger-id.bundesbank.de), z. B. DE98ZZZ09999999999.',
|
|
],
|
|
[
|
|
'name' => self::OPTION_PRE_NOTIFICATION_DAYS,
|
|
'label' => 'Vorlauf bis zum Einzug (Tage)',
|
|
'type' => 'number',
|
|
'required' => true,
|
|
'hint' => sprintf(
|
|
'So viele Tage nach dem Erzeugen der Lastschriftdatei wird eingezogen (%d bis %d). '
|
|
. 'Die Frist steht als verkürzte Vorabankündigung im Mandatstext.',
|
|
self::MIN_PRE_NOTIFICATION_DAYS,
|
|
self::MAX_PRE_NOTIFICATION_DAYS,
|
|
),
|
|
],
|
|
['name' => 'icon', 'label' => 'Symbol', 'type' => 'icon', 'required' => false],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Ein Fehler in diesen Werten fiele sonst erst der Bank auf -- beim Hochladen der Datei, wenn die
|
|
* Vorabankündigungen schon verschickt sind.
|
|
*/
|
|
public function configurationErrors(array $config): array
|
|
{
|
|
$errors = [];
|
|
|
|
$iban = (string) ($config['iban'] ?? '');
|
|
if ($iban !== '' && !Iban::isValid($iban)) {
|
|
$errors['iban'] = 'Die IBAN ist ungültig.';
|
|
}
|
|
|
|
$creditorId = (string) ($config[self::OPTION_CREDITOR_ID] ?? '');
|
|
if ($creditorId !== '' && !CreditorId::isValid($creditorId)) {
|
|
$errors[self::OPTION_CREDITOR_ID] = 'Die Gläubiger-ID ist ungültig.';
|
|
}
|
|
|
|
$days = $config[self::OPTION_PRE_NOTIFICATION_DAYS] ?? '';
|
|
if ($days !== '' && $days !== null) {
|
|
$valid = filter_var($days, FILTER_VALIDATE_INT, ['options' => [
|
|
'min_range' => self::MIN_PRE_NOTIFICATION_DAYS,
|
|
'max_range' => self::MAX_PRE_NOTIFICATION_DAYS,
|
|
]]);
|
|
|
|
if ($valid === false) {
|
|
$errors[self::OPTION_PRE_NOTIFICATION_DAYS] = sprintf(
|
|
'Der Vorlauf muss eine ganze Zahl von %d bis %d Tagen sein.',
|
|
self::MIN_PRE_NOTIFICATION_DAYS,
|
|
self::MAX_PRE_NOTIFICATION_DAYS,
|
|
);
|
|
}
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
protected function invoiceClosingStatement(CreateInvoiceRequest $request): string
|
|
{
|
|
return sprintf('Der Betrag von %s wird per SEPA-Lastschrift eingezogen.', $request->amount->toString());
|
|
}
|
|
}
|