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

181
README.md
View File

@@ -241,6 +241,187 @@ EspoCRM verwendet ein hierarchisches Mehrsprachen-System mit **en_US als Basis-F
- Teste Tooltips nach jedem Rebuild in beiden Sprachen
- Bei neuen Feldern: erst i18n-Dateien vollständig ausfüllen, dann Rebuild
## Formula-Scripts und Custom PHP-Erweiterungen
EspoCRM bietet mächtige Erweiterungsmöglichkeiten durch Formula-Scripts und Custom PHP-Funktionen. Diese ermöglichen Validierungen, Berechnungen und Business-Logik direkt beim Speichern von Datensätzen.
### Formula-Scripts: Grundlagen
**WICHTIG: Dateistruktur**
**FALSCH** - Formula in entityDefs:
```json
// custom/Espo/Custom/Resources/metadata/entityDefs/Entity.json
{
"fields": {...},
"formula": {
"beforeSaveApiScript": "..." // FUNKTIONIERT NICHT!
}
}
```
**RICHTIG** - Separate Formula-Datei:
```json
// custom/Espo/Custom/Resources/metadata/formula/Entity.json
{
"beforeSaveApiScript": "if (field != null) { ... }"
}
```
### Verfügbare Formula-Script-Typen
1. **`beforeSaveApiScript`** - Wird vor dem Speichern ausgeführt (UI + API, ab v7.5+)
2. **`beforeSaveCustomScript`** - Nur bei internen Saves (ohne API)
3. **`afterSaveScript`** - Nach dem Speichern
**Verwendung**: Validierungen, Berechnungen, Daten-Transformation vor dem Speichern
### Verfügbare Formula-Funktionen
**String-Funktionen:**
- `string\concatenate(str1, str2)` - Strings verbinden
- `string\replace(text, search, replace)` - Ersetzen
- `string\substring(text, start, length)` - Teilstring
- `string\length(text)` - Länge
- `string\test(text, pattern)` - Regex-Test
- ⚠️ **NICHT verfügbar**: `string\isEmpty()` → Verwende `field != null && field != ''`
**Logik:**
- `if (condition) { ... }`
- `&&`, `||`, `!` (AND, OR, NOT)
- `==`, `!=`, `>`, `<`, `>=`, `<=`
**Fehlerbehandlung:**
- `recordService\throwBadRequest('Fehlermeldung')` - Speichern abbrechen mit Fehlermeldung
### Custom Formula-Funktionen erstellen
Beispiel: IBAN-Validierung mit Modulo-97-Algorithmus
**1. PHP-Klasse erstellen:**
Pfad: `custom/Espo/Custom/Classes/FormulaFunctions/IbanGroup/ValidateType.php`
```php
<?php
namespace Espo\Custom\Classes\FormulaFunctions\IbanGroup;
use Espo\Core\Formula\Functions\BaseFunction;
use Espo\Core\Formula\ArgumentList;
class ValidateType extends BaseFunction
{
public function process(ArgumentList $args)
{
if (count($args) < 1) {
return false;
}
$iban = $this->evaluate($args[0]);
if (!$iban || !is_string($iban)) {
return false;
}
// IBAN-Validierungs-Logik hier
// ... (siehe ValidateType.php für vollständige Implementierung)
return $remainder === 1; // Modulo-97-Check
}
}
```
**2. Funktion registrieren:**
Pfad: `custom/Espo/Custom/Resources/metadata/app/formula.json`
```json
{
"functionList": [
"__APPEND__",
{
"name": "iban\\validate",
"insertText": "iban\\validate(IBAN)"
}
],
"functionClassNameMap": {
"iban\\validate": "Espo\\Custom\\Classes\\FormulaFunctions\\IbanGroup\\ValidateType"
}
}
```
**3. Funktion verwenden:**
Pfad: `custom/Espo/Custom/Resources/metadata/formula/CBankverbindungen.json`
```json
{
"beforeSaveApiScript": "if (iban != null && iban != '') {\n $ibanClean = string\\replace(iban, ' ', '');\n if (!iban\\validate($ibanClean)) {\n recordService\\throwBadRequest('Ungültige IBAN!');\n }\n}"
}
```
### Wichtige Hinweise zur Formula-Entwicklung
**Namespace-Struktur:**
- Verzeichnis: `custom/Espo/Custom/Classes/FormulaFunctions/{GroupName}/`
- Namespace: `Espo\Custom\Classes\FormulaFunctions\{GroupName}`
- Klassenname: `{FunctionName}Type` (z.B. `ValidateType`)
- Muss `BaseFunction` erweitern
**Funktionsnamen:**
- Format: `group\functionName` (z.B. `iban\validate`, `string\replace`)
- Backslash `\` wird verwendet (nicht `::` oder `/`)
**Häufige Fehler:**
| Fehler | Symptom | Lösung |
|--------|---------|--------|
| Formula in entityDefs statt formula/ | Script wird nicht ausgeführt | Separate `formula/{Entity}.json` erstellen |
| `string\isEmpty()` verwendet | Error: "Unknown function" | Verwende `field != null && field != ''` |
| Falsche Namespace-Struktur | Funktion nicht gefunden | Prüfe Namespace, Klassenname, Pfad |
| Funktion nicht registriert | "Unknown function" | Eintrag in `app/formula.json` erstellen |
| Keine `__APPEND__` in functionList | Überschreibt Core-Funktionen | Immer `"__APPEND__"` als erstes Element |
### Debugging von Formula-Scripts
**Logs prüfen:**
```bash
tail -n 100 /var/www/html/data/logs/espo-*.log | grep -i "formula\|error"
```
**Häufige Fehlermeldungen:**
- `Unknown function: xxx` → Funktion existiert nicht oder nicht registriert
- `Error 500` → Syntax-Fehler im Formula-Script oder PHP-Fehler
- `validationFailure``throwBadRequest()` wurde aufgerufen
**Test-Workflow:**
1. Formula-Script schreiben
2. Rebuild ausführen: `bash custom/scripts/check_and_rebuild.sh`
3. Cache leeren (falls nötig): `rm -rf data/cache/*`
4. Testdaten speichern und Logs prüfen
### Best Practices
**Empfohlen:**
- Separate Formula-Dateien pro Entity in `metadata/formula/`
- Wiederverwendbare Logik in Custom PHP-Funktionen auslagern
- Aussagekräftige Fehlermeldungen mit `throwBadRequest()`
- Null-Checks vor Operationen: `field != null && field != ''`
- Code kommentieren für spätere Wartung
**Vermeiden:**
- Formula-Scripts in `entityDefs` ablegen
- Nicht-existente String-Funktionen wie `isEmpty()`
- Komplexe Logik direkt in Formula (besser: PHP-Funktion)
- Fehlende Registrierung in `app/formula.json`
### Beispiel-Anwendungsfälle
1. **Validierung**: IBAN-Check, Email-Format, Telefonnummern
2. **Berechnung**: Gesamtpreise, Datumsberechnungen, Provisionen
3. **Daten-Transformation**: Großbuchstaben, Formatierungen, Normalisierungen
4. **Business Rules**: Status-Überprüfungen, Pflichtfeld-Logik, Abhängigkeiten
3. Auslösen von Änderungen und Rebuild-Prozess
Was Änderungen auslösen: