Add IBAN and BIC validation with custom hooks; update localization messages and cache timestamps

This commit is contained in:
2026-01-23 16:20:26 +01:00
parent 15ecc7068f
commit e1a7158931
7 changed files with 290 additions and 5 deletions

View File

@@ -0,0 +1,95 @@
<?php
namespace Espo\Custom\Hooks\CBankverbindungen;
use Espo\ORM\Entity;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Utils\Language;
class BankdatenValidation
{
private $language;
public function __construct(Language $language)
{
$this->language = $language;
}
public function beforeSave(Entity $entity, array $options): void
{
// IBAN-Normalisierung und Validierung
$iban = $entity->get('iban');
if ($iban !== null && $iban !== '') {
// IBAN normalisieren: Leerzeichen entfernen und Großbuchstaben
$ibanClean = strtoupper(str_replace(' ', '', $iban));
$entity->set('iban', $ibanClean);
// Mathematische IBAN-Prüfung mit Modulo-97
if (!$this->validateIban($ibanClean)) {
$message = $this->language->translateLabel('invalidIbanChecksum', 'messages', 'CBankverbindungen');
throw new BadRequest($message);
}
}
// BIC-Normalisierung und Validierung
$bic = $entity->get('bic');
if ($bic !== null && $bic !== '') {
// BIC normalisieren: Leerzeichen entfernen und Großbuchstaben
$bicClean = strtoupper(str_replace(' ', '', $bic));
$entity->set('bic', $bicClean);
// BIC-Format prüfen: 8 oder 11 Zeichen
$bicLength = strlen($bicClean);
if ($bicLength !== 8 && $bicLength !== 11) {
$message = $this->language->translateLabel('invalidBicLength', 'messages', 'CBankverbindungen');
throw new BadRequest($message);
}
// BIC-Format prüfen: Regex
if (!preg_match('/^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/', $bicClean)) {
$message = $this->language->translateLabel('invalidBicFormat', 'messages', 'CBankverbindungen');
throw new BadRequest($message);
}
}
}
private function validateIban(string $iban): bool
{
// IBAN-Länge prüfen (mindestens 15 Zeichen)
if (strlen($iban) < 15) {
return false;
}
// IBAN umstellen: erste 4 Zeichen ans Ende
$rearranged = substr($iban, 4) . substr($iban, 0, 4);
// Buchstaben in Zahlen umwandeln (A=10, B=11, ..., Z=35)
$numeric = '';
for ($i = 0; $i < strlen($rearranged); $i++) {
$char = $rearranged[$i];
if (ctype_alpha($char)) {
$numeric .= (string)(ord($char) - ord('A') + 10);
} else {
$numeric .= $char;
}
}
// Modulo-97-Prüfung
return $this->bcmod($numeric, '97') === '1';
}
private function bcmod(string $number, string $modulus): string
{
// Für große Zahlen: Modulo in Schritten berechnen
$take = 9;
$mod = '';
do {
$a = (int)($mod . substr($number, 0, $take));
$number = substr($number, $take);
$mod = (string)($a % (int)$modulus);
} while (strlen($number) > 0);
return $mod;
}
}

View File

@@ -48,5 +48,10 @@
"unclean": "Abweichungen",
"failed": "Fehlgeschlagen"
}
},
"messages": {
"invalidIbanChecksum": "Die eingegebene IBAN ist ungueltig. Bitte pruefen Sie die Nummer auf Tippfehler.",
"invalidBicLength": "Der BIC/SWIFT-Code muss 8 oder 11 Zeichen lang sein.",
"invalidBicFormat": "Der eingegebene BIC/SWIFT-Code hat ein ungueltiges Format. Beispiel: COBADEFFXXX"
}
}
}

View File

@@ -37,5 +37,10 @@
"unclean": "Discrepancies",
"failed": "Failed"
}
},
"messages": {
"invalidIbanChecksum": "The entered IBAN is invalid. Please check for typos.",
"invalidBicLength": "The BIC/SWIFT code must be 8 or 11 characters long.",
"invalidBicFormat": "The entered BIC/SWIFT code has an invalid format. Example: COBADEFFXXX"
}
}

View File

@@ -19,7 +19,6 @@
"type": "varchar",
"required": false,
"maxLength": 11,
"pattern": "/^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/i",
"tooltip": true,
"isCustom": true
},

View File

@@ -1,3 +1,3 @@
{
"beforeSaveApiScript": "// IBAN-Validierung mit Modulo-97-Algorithmus\nif (iban != null && iban != '') {\n // Leerzeichen entfernen für Validierung\n $ibanClean = string\\replace(iban, ' ', '');\n \n // Mathematische IBAN-Prüfung\n if (!iban\\validate($ibanClean)) {\n recordService\\throwBadRequest('Ungültige IBAN: Die Prüfziffer ist mathematisch falsch. Bitte überprüfen Sie die eingegebene IBAN.');\n }\n}"
"beforeSaveApiScript": ""
}