Handling SEPA Direct Payment
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
/**
|
||||
* Zustandslose Helfer für die SEPA-Gläubiger-Identifikationsnummer (Creditor Identifier).
|
||||
*
|
||||
* Aufbau nach EPC262-08: Ländercode, zwei Prüfziffern, drei Zeichen Geschäftsbereichskennung, dann die
|
||||
* nationale Kennung. In Deutschland vergibt die Bundesbank sie mit 18 Zeichen (`DE98ZZZ09999999999`).
|
||||
*
|
||||
* Die Prüfziffer ist der Teil, auf den es ankommt: Eine Lastschriftdatei mit falscher Gläubiger-ID lehnt
|
||||
* die Bank als Ganzes ab -- und zwar erst beim Hochladen, wenn die Vorabankündigungen schon verschickt
|
||||
* sind.
|
||||
*/
|
||||
final class CreditorId
|
||||
{
|
||||
/** Länge der Gläubiger-ID je Ländercode, soweit sie national festgelegt ist. */
|
||||
private const array LENGTHS = [
|
||||
'DE' => 18,
|
||||
];
|
||||
|
||||
/** Leerzeichen raus, Großbuchstaben -- die kanonische Form, die gespeichert wird. */
|
||||
public static function normalize(string $creditorId): string
|
||||
{
|
||||
return strtoupper(preg_replace('/\s+/', '', $creditorId) ?? '');
|
||||
}
|
||||
|
||||
public static function isValid(string $creditorId): bool
|
||||
{
|
||||
$creditorId = self::normalize($creditorId);
|
||||
|
||||
if (preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]{3}[A-Z0-9]{1,28}$/', $creditorId) !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$expected = self::LENGTHS[substr($creditorId, 0, 2)] ?? null;
|
||||
if ($expected !== null && strlen($creditorId) !== $expected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::checksum($creditorId) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mod 97-10 wie bei der IBAN, aber ohne die Geschäftsbereichskennung (Stellen 5 bis 7): Sie darf
|
||||
* der Gläubiger frei wählen, ohne dass sich die Prüfziffer ändert. Geprüft wird deshalb die nationale
|
||||
* Kennung, gefolgt von Ländercode und Prüfziffern; Buchstaben zählen als Position + 9 (A = 10 … Z = 35).
|
||||
*/
|
||||
private static function checksum(string $creditorId): int
|
||||
{
|
||||
$rearranged = substr($creditorId, 7) . substr($creditorId, 0, 4);
|
||||
|
||||
$remainder = 0;
|
||||
foreach (str_split($rearranged) as $char) {
|
||||
$value = ctype_digit($char) ? $char : (string) (ord($char) - 55);
|
||||
|
||||
foreach (str_split($value) as $digit) {
|
||||
$remainder = ($remainder * 10 + (int) $digit) % 97;
|
||||
}
|
||||
}
|
||||
|
||||
return $remainder;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user