1120 lines
41 KiB
Markdown
1120 lines
41 KiB
Markdown
KI-basierte Bearbeitung von EspoCRM: Struktur und Funktionsweise
|
||
|
||
## Inhaltsverzeichnis
|
||
1. [Überblick](#überblick)
|
||
2. [Relevante Dateipfade und Verzeichnisstruktur](#1-relevante-dateipfade-und-verzeichnisstruktur)
|
||
3. [Workflow-Verwaltung](#workflow-verwaltung)
|
||
4. [Auslösen von Änderungen und Rebuild-Prozess](#auslösen-von-änderungen-und-rebuild-prozess)
|
||
|
||
## Überblick
|
||
|
||
Unter der Annahme, dass die KI direkten Zugriff auf das Dateisystem des EspoCRM-Servers hat (z. B. via SSH, API-Integration oder lokales Scripting), kann sie EspoCRM modifizieren, indem sie JSON-basierte Metadata-Dateien bearbeitet. EspoCRM ist modular aufgebaut und speichert Konfigurationen für Entitäten, Felder, Beziehungen, Views und Layouts in diesen Dateien. Änderungen erfolgen idealerweise im custom/-Verzeichnis, um Core-Dateien nicht zu überschreiben und Upgrades zu erleichtern. Die KI würde Dateien lesen, parsen (z. B. als JSON), modifizieren und speichern – gefolgt von einem Rebuild-Prozess, um die Änderungen anzuwenden.
|
||
|
||
EspoCRM basiert auf PHP (Backend) und Backbone.js (Frontend), mit einer rekursiven Merging-Mechanik: Custom-Dateien überschreiben oder erweitern Core-Definitionen. Keine integrierte KI-Schnittstelle existiert, aber mit Dateizugriff kann die KI automatisierte Anpassungen vornehmen, z. B. Felder hinzufügen, Views anpassen oder Beziehungen definieren. Nachfolgend detaillierte Infos basierend auf der offiziellen Dokumentation und Community-Beiträgen.
|
||
|
||
### Custom Scripts & Tools
|
||
|
||
**Workflow-Verwaltung:**
|
||
- `custom/scripts/workflow_manager.php` - Zentrale Schnittstelle für Workflow-Verwaltung (Import/Export/List/Delete)
|
||
- `custom/scripts/check_and_rebuild.sh` - Validierungs- und Rebuild-Script
|
||
|
||
**Workflow-Definitionen:**
|
||
- `custom/workflows/*.json` - Versionierte Workflow-Definitionen (Simple & BPM)
|
||
- `custom/workflows/README.md` - Workflow-Format-Dokumentation
|
||
1. Relevante Dateipfade und Verzeichnisstruktur
|
||
|
||
Alle relevanten Dateien liegen im JSON-Format und werden in einer hierarchischen Struktur organisiert. Die KI sollte immer im custom/Espo/Custom/Resources/metadata/-Ordner arbeiten, da Änderungen hier persistent sind und nicht bei Updates verloren gehen. Core-Dateien (z. B. unter application/Espo/Resources/metadata/) dienen als Referenz, aber sollten nicht modifiziert werden.
|
||
|
||
Hauptverzeichnis für Customizations: custom/Espo/Custom/Resources/
|
||
Unterordner: metadata/ (für Definitionsdateien wie entityDefs, clientDefs).
|
||
Weitere Unterordner: layouts/ (für UI-Layouts), i18n/ (für Übersetzungen, falls relevant).
|
||
Spezifische Dateitypen und Pfade:
|
||
entityDefs/{EntityType}.json: Definiert Entitäten (z. B. Account, Contact oder custom wie Project). Pfad: custom/Espo/Custom/Resources/metadata/entityDefs/Account.json.
|
||
Kontrolliert: Felder, Beziehungen (Links), Indizes, Collections (z. B. Sortierung in Listen).
|
||
clientDefs/{EntityType}.json: Definiert Frontend-Konfigurationen für Entitäten. Pfad: custom/Espo/Custom/Resources/metadata/clientDefs/Account.json.
|
||
Kontrolliert: Views (z. B. Edit-View), Controller, Modelle, Setup-Handler für dynamische UI-Anpassungen.
|
||
layouts/{EntityType}/{LayoutType}.json: Definiert UI-Layouts (z. B. Detail-View, List-View). Pfad: custom/Espo/Custom/Resources/layouts/Account/detail.json.
|
||
LayoutTypes: detail, list, edit, kanban, etc.
|
||
fields/{FieldType}.json: Globale Feld-Definitionen (z. B. für Address oder Phone). Pfad: custom/Espo/Custom/Resources/metadata/fields/address.json.
|
||
Kontrolliert: Feldtypen, Views für spezifische Felder (z. B. custom View für Phone mit Click-to-Call).
|
||
scopes/{EntityType}.json: Definiert Entity-Scopes (z. B. ob eine Entität importierbar ist). Pfad: custom/Espo/Custom/Resources/metadata/scopes/Project.json.
|
||
Andere (weniger häufig): aclDefs/ für Zugriffsrechte, selectDefs/ für Filter, recordDefs/ für Record-spezifische Logik.
|
||
|
||
Falls die KI ein neues Modul erstellt: custom/Espo/Modules/{ModuleName}/Resources/metadata/ – ähnliche Struktur, aber modular getrennt.
|
||
docs.espocrm.com
|
||
2. Dateiformate und JSON-Strukturen
|
||
|
||
Alle Dateien sind im JSON-Format. Die KI muss gültiges JSON parsen und schreiben (z. B. mit Bibliotheken wie json in Python). Strukturen sind hierarchisch: Objekte für Felder/Links, Arrays für Optionen/Listen.
|
||
|
||
entityDefs/{EntityType}.json (Format-Beispiel für eine Entität wie Account):
|
||
JSON
|
||
|
||
{
|
||
"fields": {
|
||
"name": {
|
||
"type": "varchar",
|
||
"required": true,
|
||
"len": 255
|
||
},
|
||
"status": {
|
||
"type": "enum",
|
||
"options": ["Active", "Inactive"],
|
||
"default": "Active"
|
||
},
|
||
"employeeCount": {
|
||
"type": "int"
|
||
}
|
||
},
|
||
"links": {
|
||
"account": {
|
||
"type": "belongsTo",
|
||
"entity": "Account",
|
||
"foreign": "projects"
|
||
},
|
||
"teams": {
|
||
"type": "hasMany",
|
||
"entity": "Team",
|
||
"relationName": "EntityTeam"
|
||
}
|
||
},
|
||
"collection": {
|
||
"sortBy": "createdAt",
|
||
"asc": false,
|
||
"boolFilters": ["onlyMy"]
|
||
},
|
||
"indexes": {
|
||
"name": {
|
||
"columns": ["name"]
|
||
}
|
||
}
|
||
}
|
||
|
||
Felder (fields): Schlüssel = Feldname, Wert = Objekt mit type (z. B. varchar, enum, link), required (bool), options (Array für Enums), etc.
|
||
Links: Beziehungen (belongsTo für 1:1, hasMany für 1:N, etc.).
|
||
Collection: Für Listen-Views (Sortierung, Filter).
|
||
Auslösen: Hinzufügen eines Felds triggert bei Rebuild eine Datenbankänderung (neue Spalte in der Tabelle). Beziehungen erstellen Middle-Tables bei Many-to-Many.
|
||
**WICHTIG - Bidirektionale Relationships**: Bei hasMany-Relationships (z. B. viele Contacts zu einer Entität) müssen **beide Seiten** definiert werden:
|
||
- In Entität A: Link mit `relationName` und `foreign` (zeigt auf Link-Namen in Entität B)
|
||
- In Entität B (z. B. Contact): Link mit **derselben** `relationName` und `foreign` (zeigt auf Link-Namen in Entität A)
|
||
- Beispiel: `CVmhMietverhltnis` hat Link `contactsMietverhltnis` mit relationName `cVmhMietverhltnisContact`; `Contact` hat Link `cVmhMietverhltnisesContact` mit derselben relationName und foreign `contactsMietverhltnis`.
|
||
- Fehlt eine Seite, gibt EspoCRM 404-Fehler "Link does not exist" zurück.
|
||
docs.espocrm.com
|
||
|
||
clientDefs/{EntityType}.json (Format-Beispiel):
|
||
JSON
|
||
|
||
{
|
||
"controller": "controllers/record",
|
||
"collection": "collection",
|
||
"model": "model",
|
||
"views": {
|
||
"list": "views/record/list",
|
||
"detail": "views/record/detail",
|
||
"edit": "views/record/edit"
|
||
},
|
||
"recordViews": {
|
||
"list": "views/record/list",
|
||
"kanban": "custom:views/record/kanban"
|
||
},
|
||
"viewSetupHandlers": {
|
||
"record/detail": ["custom:handlers/my-detail-handler"]
|
||
}
|
||
}
|
||
|
||
Views/RecordViews: Pfade zu JS-Views (z. B. "custom:views/account/detail" für custom View).
|
||
ViewSetupHandlers: Arrays von Handlern für dynamische Anpassungen (z. B. Feld-Updates).
|
||
Auslösen: Ändert Frontend-Rendering (z. B. neue View-Modi wie Kanban).
|
||
forum.espocrm.com
|
||
|
||
layouts/{EntityType}/detail.json (Format-Beispiel für Detail-View):
|
||
JSON
|
||
|
||
[
|
||
{
|
||
"label": "Overview",
|
||
"rows": [
|
||
[
|
||
{"name": "name"},
|
||
{"name": "assignedUser"}
|
||
],
|
||
[
|
||
{"name": "description"}
|
||
]
|
||
]
|
||
},
|
||
{
|
||
"label": "Details",
|
||
"rows": [
|
||
[{"name": "createdAt"}]
|
||
]
|
||
}
|
||
]
|
||
|
||
Arrays von Panels (Objekte mit label und rows), rows sind Arrays von Zellen (Objekte mit name für Felder).
|
||
Auslösen: Ändert Feldanordnung in Views; unterstützt Parameter wie width, notSortable.
|
||
docs.espocrm.com
|
||
|
||
Spezielle Features:
|
||
APPEND: In Arrays als erstes Element einfügen, um bestehende Werte zu erweitern (z. B. options: ["APPEND", "NewOption"]).
|
||
layoutAvailabilityList: Array für Feld-Sichtbarkeit in Layouts (z. B. ["list", "detail"]).
|
||
layoutIgnoreList: Zu ignorierende Layouts.
|
||
|
||
## Internationalisierung (i18n) und Tooltips
|
||
|
||
**KRITISCH: Mehrsprachige Tooltip-Verwaltung**
|
||
|
||
EspoCRM verwendet ein hierarchisches Mehrsprachen-System mit **en_US als Basis-Fallback**:
|
||
|
||
1. **Sprachpriorität**: en_US → aktuelle Sprache (z.B. de_DE)
|
||
2. **Problem**: Tooltips in en_US überschreiben Tooltips in anderen Sprachen
|
||
3. **Lösung**: Tooltips MÜSSEN in ALLEN Sprachen definiert werden
|
||
|
||
### Beispiel für korrektes Tooltip-Setup:
|
||
|
||
**entityDefs/{Entity}.json:**
|
||
```json
|
||
{
|
||
"fields": {
|
||
"iban": {
|
||
"type": "varchar",
|
||
"tooltip": true // Aktiviert Tooltip-Anzeige
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**i18n/de_DE/{Entity}.json:**
|
||
```json
|
||
{
|
||
"fields": {
|
||
"iban": "IBAN"
|
||
},
|
||
"tooltips": {
|
||
"iban": "Internationale Bankkontonummer im Format DE89..."
|
||
}
|
||
}
|
||
```
|
||
|
||
**i18n/en_US/{Entity}.json:**
|
||
```json
|
||
{
|
||
"fields": {
|
||
"iban": "IBAN"
|
||
},
|
||
"tooltips": {
|
||
"iban": "International Bank Account Number in format DE89..."
|
||
}
|
||
}
|
||
```
|
||
|
||
### Häufige Fehler:
|
||
|
||
❌ **FALSCH** - Unvollständige en_US-Datei:
|
||
```json
|
||
{
|
||
"fields": [],
|
||
"tooltips": {
|
||
"iban": "iban2" // Überschreibt deutschen Tooltip!
|
||
}
|
||
}
|
||
```
|
||
|
||
✅ **RICHTIG** - Vollständige Definitionen in beiden Sprachen:
|
||
- Alle Felder in `fields` definieren
|
||
- Alle Tooltips in `tooltips` definieren
|
||
- Konsistente Struktur über alle Sprachen
|
||
|
||
### Debugging von Tooltip-Problemen:
|
||
|
||
1. **Symptom**: Tooltip zeigt nur Feldnamen (z.B. "iban" statt vollständiger Beschreibung)
|
||
2. **Ursache**: Fehlerhafte oder fehlende Definition in `i18n/en_US/{Entity}.json`
|
||
3. **Prüfung**:
|
||
- Existiert `i18n/en_US/{Entity}.json`?
|
||
- Enthält es fehlerhafte Tooltip-Definitionen?
|
||
- Sind alle Tooltips konsistent über alle Sprachen?
|
||
4. **Lösung**: Vervollständige en_US-Datei mit korrekten englischen Übersetzungen
|
||
|
||
### Best Practices:
|
||
|
||
- Erstelle **immer** sowohl de_DE als auch en_US Übersetzungen
|
||
- Verwende beschreibende Tooltips mit Beispielen und Format-Hinweisen
|
||
- 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:
|
||
Datei-Änderungen: Werden bei Merging berücksichtigt – rekursiv, also überschreiben Customs Core.
|
||
Datenbank-Effekte: Neue Felder/Links in entityDefs erzeugen Tabellen/Spalten (bei Rebuild).
|
||
Frontend-Effekte: clientDefs/Layouts ändern UI sofort nach Rebuild (z. B. neue Panels, Views).
|
||
Fehlerquellen: Ungültiges JSON oder falsche Typen können zu Fehlern führen (z. B. fehlende required-Felder).
|
||
|
||
## Workflow-Verwaltung
|
||
|
||
EspoCRM bietet zwei Arten von Workflows für Automatisierung:
|
||
|
||
### Simple Workflows (Regel-basiert)
|
||
- Trigger-basierte Workflows für einfache Automationen
|
||
- **Trigger-Typen:**
|
||
- `afterRecordSaved` - Nach Erstellen oder Aktualisieren
|
||
- `afterRecordCreated` - Nur nach Erstellen
|
||
- `afterRecordUpdated` - Nur nach Aktualisieren
|
||
- `manual` - Manuell ausgeführt
|
||
- `scheduled` - Zeitgesteuert
|
||
- **Bedingungen:**
|
||
- Vergleiche: `equals`, `notEquals`, `greaterThan`, `lessThan`, `contains`, `isEmpty`
|
||
- Änderungen: `changed`, `notChanged`, `wasEqual`
|
||
- **Aktionen:**
|
||
- `sendEmail` - E-Mail versenden
|
||
- `createEntity` - Record erstellen
|
||
- `updateEntity` - Record aktualisieren
|
||
- `relateTo` / `unrelateFrom` - Verknüpfungen
|
||
- `createNotification` - Benachrichtigung
|
||
|
||
### BPM Flowcharts (Komplex)
|
||
- Visuelle Workflows mit BPMN 2.0-Standard
|
||
- Start-Events: Signal, Conditional, Timer
|
||
- Gateways (Exclusive, Inclusive, Parallel), Tasks, End-Events
|
||
- Für komplexe, mehrstufige Geschäftsprozesse
|
||
|
||
### Workflow-Dateien
|
||
Workflow-Definitionen werden im Ordner `custom/workflows/` als JSON abgelegt:
|
||
- **`custom/workflows/*.json`** - Workflow-Definitionen (Simple oder BPM)
|
||
- **`custom/workflows/README.md`** - Dokumentation zu Formaten und Verwendung
|
||
|
||
### Workflow Manager Script
|
||
**Zentrale Schnittstelle:** `custom/scripts/workflow_manager.php`
|
||
|
||
Dieses Script ermöglicht die Verwaltung aller Workflows (Simple und BPM) über die Kommandozeile.
|
||
|
||
**Unterstützte Funktionen:**
|
||
- ✓ Kategorisierung von Workflows
|
||
- ✓ Import/Export mit Kategorie-Namen
|
||
- ✓ Übersichtliche Darstellung nach Kategorien
|
||
- ✓ Unterstützung für beide Workflow-Typen (Simple & BPM)
|
||
|
||
#### Verfügbare Aktionen
|
||
|
||
**1. Alle Workflows auflisten**
|
||
```bash
|
||
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php list
|
||
```
|
||
Zeigt beide Workflow-Typen (BPM Flowcharts und Simple Workflows) mit Status, ID, Name und Entity.
|
||
|
||
**2. Workflow-Details anzeigen**
|
||
```bash
|
||
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php read <workflow-id>
|
||
```
|
||
Gibt alle Details eines Workflows als JSON aus.
|
||
|
||
**3. Workflow importieren**
|
||
```bash
|
||
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php import /var/www/html/custom/workflows/workflow.json
|
||
```
|
||
Importiert einen Workflow aus einer JSON-Datei. Unterstützt sowohl Simple Workflows als auch BPM Flowcharts. Erstellt automatisch eine neue ID.
|
||
|
||
**4. Workflow exportieren**
|
||
```bash
|
||
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php export <workflow-id> /var/www/html/custom/workflows/exported.json
|
||
```
|
||
Exportiert einen Workflow in eine JSON-Datei für Backup oder Migration.
|
||
|
||
**5. Workflow löschen**
|
||
```bash
|
||
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php delete <workflow-id>
|
||
```
|
||
Löscht einen Workflow (mit Bestätigung). Funktioniert für beide Workflow-Typen.
|
||
|
||
### JSON-Formate
|
||
|
||
#### Simple Workflow Format
|
||
```json
|
||
{
|
||
"type": "simple",
|
||
"name": "workflow-name",
|
||
"entity_type": "EntityName",
|
||
"trigger_type": "afterRecordSaved",
|
||
"is_active": true,
|
||
"description": "Beschreibung der Funktion",
|
||
"category": "Kategorie-Name",
|
||
"conditions_all": [
|
||
{
|
||
"comparison": "equals",
|
||
"fieldToCompare": "fieldName",
|
||
"value": "expectedValue",
|
||
"subjectType": "value"
|
||
}
|
||
],
|
||
"conditions_any": [],
|
||
"conditions_formula": null,
|
||
"actions": [
|
||
{
|
||
"type": "sendEmail",
|
||
"from": "specifiedEmailAddress",
|
||
"fromEmailAddress": "sender@example.com",
|
||
"to": "targetEntity",
|
||
"emailTemplateId": null,
|
||
"doNotStore": false
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Wichtige Felder:**
|
||
- `category` - **NEU:** Name der Workflow-Kategorie (optional, für bessere Organisation)
|
||
- `comparison` - Vergleichsoperator (siehe Bedingungen oben)
|
||
- `fieldToCompare` - Feldname für Bedingung
|
||
- `subjectType` - Typ des Vergleichswerts (`value`, `field`, etc.)
|
||
- `from` / `to` - E-Mail-Empfänger (`targetEntity`, `specifiedEmailAddress`, `system`)
|
||
|
||
#### BPM Flowchart Format
|
||
```json
|
||
{
|
||
"type": "bpm",
|
||
"name": "flowchart-name",
|
||
"target_type": "EntityName",
|
||
"is_active": true,
|
||
"description": "Beschreibung",
|
||
"data": {
|
||
"list": [
|
||
{
|
||
"type": "eventStartSignal",
|
||
"id": "start1",
|
||
"signalName": "@signalName"
|
||
}
|
||
]
|
||
},
|
||
"elements_data_hash": {},
|
||
"event_start_all_id_list": []
|
||
}
|
||
```
|
||
|
||
### Best Practices
|
||
|
||
1. **Versionierung:** Workflows als JSON-Dateien im `custom/workflows/` Verzeichnis versionieren
|
||
2. **Naming Convention:** Beschreibende Namen mit Präfix (z.B. `vmh-erstberatung-abschliessen.json`)
|
||
3. **Testen:** Nach Import immer über Admin-Interface testen
|
||
4. **Backup:** Regelmäßig Export für wichtige Workflows durchführen
|
||
5. **Dokumentation:** Description-Feld aussagekräftig füllen
|
||
|
||
### Beispiel-Workflows
|
||
|
||
**`custom/workflows/vmh-erstberatung-abschliessen.json`**
|
||
- Sendet E-Mail bei Status-Wechsel zu "Warte auf Mandatierung"
|
||
- Trigger: afterRecordSaved
|
||
- Bedingungen: Status = "Warte auf Mandatierung" UND Status hat sich geändert
|
||
- Aktion: E-Mail an targetEntity senden
|
||
|
||
**Anwendungsbeispiel:**
|
||
```bash
|
||
# Alle Workflows exportieren (Backup)
|
||
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php list | grep ID | \
|
||
awk '{print $3}' | while read id; do
|
||
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php export "${id%,}" \
|
||
"/var/www/html/custom/workflows/backup-${id%,}.json"
|
||
done
|
||
|
||
# Workflow aus Datei (re-)importieren
|
||
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php import \
|
||
/var/www/html/custom/workflows/vmh-erstberatung-abschliessen.json
|
||
```
|
||
|
||
### Workflow-Entwicklung mit KI
|
||
|
||
Für KI-gestützte Workflow-Erstellung:
|
||
1. Workflow-Definition im `custom/workflows/` Verzeichnis als JSON ablegen
|
||
2. Mit `import` Befehl in EspoCRM einspielen
|
||
3. Im Admin-Interface testen und bei Bedarf anpassen
|
||
4. Mit `export` Befehl aktualisierten Workflow sichern
|
||
5. JSON-Datei im Repository committen
|
||
Rebuild auslösen:
|
||
Manuell: Administration > Clear Cache & Rebuild (löscht Caches und merged Metadata neu).
|
||
Programmatisch (für KI): Die KI kann den Cache-Ordner löschen (data/cache/) oder ein PHP-Skript ausführen, das den Rebuild triggert (z. B. via EspoCRMs CLI: php command.php Rebuild). Keine direkte API, aber machbar mit Dateizugriff (z. B. exec("php rebuild.php")).
|
||
Effekt: Mergt alle Metadata, aktualisiert DB-Schema, cached Views. Ohne Rebuild bleiben Änderungen unsichtbar.
|
||
docs.espocrm.com
|
||
|
||
4. Best Practices für KI-Implementation
|
||
|
||
Workflow: 1. Datei lesen/parsen. 2. Modifizieren (z. B. Feld hinzufügen). 3. Validieren (JSON-Schema prüfen). 4. Speichern. 5. Rebuild triggern.
|
||
Sicherheit: Backups erstellen, Änderungen loggen. Vermeide Core-Änderungen.
|
||
Automatisierung: KI könnte Skripte generieren (z. B. Python mit json und os für Dateizugriff) oder direkt integriert werden (z. B. in einem Custom-Modul mit PHP-Aufrufen).
|
||
Grenzen: Keine out-of-the-box Automatisierung in Docs; Community erwähnt Skripte für Massen-Edits, aber nichts KI-spezifisch.
|
||
|
||
5. Projektziele und Zukunftsvision: "Vermieterhelden"
|
||
|
||
Das Projekt "Vermieterhelden" ist ein maßgeschneidertes Backend-System auf Basis von EspoCRM für eine Anwaltskanzlei, spezialisiert auf die Durchführung und Verwaltung von immobilienrechtlichen Klagen (z. B. Räumungsklagen, Mietinkasso). Der aktuelle Fokus liegt auf der strukturierten Verwaltung von Stammdaten (Entitäten wie Mietverhältnisse, Mietobjekte, Beteiligte, Dokumente und Klagen) und der Abbildung von rechtlichen Workflows (z. B. automatisierte Tasks bei Statusänderungen, Fristen-Überwachung).
|
||
|
||
Zukünftige Ziele:
|
||
- **Customer Portal**: Integration eines Mandanten-Portals, damit Klienten (Mieter/Vermieter) selbst auf relevante Daten zugreifen können (z. B. Status von Klagen, Dokumente hochladen). Dies nutzt EspoCRMs eingebaute Portal-Funktionalität für Self-Service.
|
||
- **KI-Integration über Middleware**: Automatisierung von Prozessen via Webhooks und externer Middleware. Beispiele:
|
||
- Automatische Analyse von Dokumenten (z. B. Verträge scannen und Felder extrahieren).
|
||
- Intelligente Fristen-Erinnerungen basierend auf rechtlichen Regeln (z. B. Kündigungsfristen berechnen).
|
||
- Workflow-Optimierung (z. B. Vorschläge für nächste Schritte in Klage-Prozessen).
|
||
- Die KI soll über APIs/Webhooks angebunden werden, ohne EspoCRMs Core zu modifizieren, um Stabilität zu wahren.
|
||
- **Erweiterte Features**: Mehrsprachigkeit, Mandanten-Isolation für mehrere Kanzlei-Teams, Integration mit externen Systemen (z. B. Gerichts-APIs, Buchhaltung).
|
||
|
||
Die KI kann diese Ziele unterstützen, indem sie JSON-Strukturen analysiert, Änderungen vorschlägt (z. B. neue Felder für Compliance) und Workflows modelliert. Das System soll skalierbar und benutzerfreundlich sein, um die Effizienz in der Rechtsbranche zu steigern.
|
||
|
||
6. Bearbeitung von Entitäten und Layouts
|
||
|
||
Um EspoCRM anzupassen, bearbeite JSON-Dateien im custom/-Verzeichnis. Änderungen bleiben bei Updates erhalten, da sie Core-Dateien nicht überschreiben.
|
||
|
||
Entitäten bearbeiten:
|
||
Pfad: custom/Espo/Custom/Resources/metadata/entityDefs/{EntityType}.json (z. B. CVmhErstgespraech.json).
|
||
Struktur: JSON-Objekt mit "fields" (Felder definieren), "links" (Beziehungen), "collection" (Sortierung/Filter), "indexes" (Performance).
|
||
Beispiel: Feld hinzufügen – Füge in "fields" ein neues Objekt ein, z. B. {"type": "varchar", "required": true}.
|
||
Beispiel: Feld entfernen – Lösche den entsprechenden Schlüssel aus "fields".
|
||
Hinweis: Änderungen wirken sich auf die Datenbank aus (z. B. neue Spalten bei Rebuild).
|
||
|
||
Layouts bearbeiten:
|
||
Pfad: custom/Espo/Custom/Resources/layouts/{EntityType}/{LayoutType}.json (z. B. detail.json für Detail-View).
|
||
Struktur: Array von Panels, jedes mit "label" und "rows" (Arrays von Zellen mit {"name": "feldname"}).
|
||
Beispiel: Feld hinzufügen – Füge {"name": "neuesFeld"} in eine "rows"-Zeile ein.
|
||
Beispiel: Feld entfernen – Lösche die entsprechende Zelle aus "rows".
|
||
LayoutTypes: detail, list, edit, etc. – Passe Views an, um UI zu optimieren.
|
||
|
||
Rebuild durchführen:
|
||
Nach Änderungen muss ein Rebuild ausgeführt werden, um Caches zu leeren und Metadata neu zu mergen.
|
||
CLI-Befehl (im Docker-Container): docker exec espocrm php /var/www/html/command.php Rebuild
|
||
Alternative: Web-Interface > Administration > Clear Cache & Rebuild.
|
||
|
||
7. Panel-Labels und Übersetzungen
|
||
|
||
Um Relationship-Panels und Links korrekt zu beschriften, müssen Labels in den i18n-Sprachdateien definiert werden.
|
||
|
||
**Wichtig - Labels in allen Sprachen definieren**:
|
||
- Labels müssen in **allen installierten Sprachen** definiert werden (z. B. de_DE UND en_US)
|
||
- Fehlende Labels in einer Sprache können dazu führen, dass die Beschriftung nicht funktioniert
|
||
- Selbst wenn die Hauptsprache de_DE ist, sollten en_US Labels immer mit definiert werden
|
||
|
||
**Labels müssen in zwei Sektionen stehen**:
|
||
- `fields`: Für die Anzeige als Feld
|
||
- `links`: Für die Anzeige in Relationship-Panels
|
||
- Beide Sektionen müssen identische Werte haben
|
||
|
||
Pfade:
|
||
- `custom/Espo/Custom/Resources/i18n/de_DE/{EntityType}.json` (deutsch)
|
||
- `custom/Espo/Custom/Resources/i18n/en_US/{EntityType}.json` (englisch)
|
||
|
||
Struktur (Beispiel CBeteiligte.json):
|
||
```json
|
||
{
|
||
"fields": {
|
||
"address": "Adresse",
|
||
"vmhvermieterbeteiligte": "Vermieter",
|
||
"vmhmieterbeteiligte": "Mieter",
|
||
"vmhRumungsklagesKlaeger": "Kläger"
|
||
},
|
||
"links": {
|
||
"calls": "Anrufe",
|
||
"tasks": "Aufgaben",
|
||
"vmhvermieterbeteiligte": "Vermieter",
|
||
"vmhmieterbeteiligte": "Mieter",
|
||
"vmhRumungsklagesKlaeger": "Kläger"
|
||
},
|
||
"labels": {
|
||
"Create CBeteiligte": "Beteiligte erstellen"
|
||
}
|
||
}
|
||
```
|
||
|
||
Best Practice:
|
||
- Bei jeder neuen Relationship immer beide Sprachen (de_DE und en_US) aktualisieren
|
||
- Link-Namen in fields UND links eintragen
|
||
- Nach Änderungen Rebuild durchführen
|
||
- Das Admin UI macht dies automatisch, manuelle Änderungen müssen beide Dateien berücksichtigen
|
||
Effekt: Aktualisiert DB-Schema, Views und entfernt alte Caches. Ohne Rebuild sind Änderungen unsichtbar.
|
||
Hinweis: Führe den Befehl auf dem Host aus, da der Container den PHP-Zugang hat.
|
||
|
||
**Tooltips für Felder definieren**:
|
||
- Tooltips sind Hilfe-Texte, die beim Hovern über das Info-Icon neben einem Feld erscheinen
|
||
- Tooltips werden in einem separaten `tooltips`-Objekt in den i18n-Dateien definiert
|
||
- Das Feld muss in der entityDef mit `"tooltip": true` markiert sein, damit das Icon angezeigt wird
|
||
|
||
Aktivierung in entityDef (entityDefs/{EntityType}.json):
|
||
```json
|
||
{
|
||
"fields": {
|
||
"lage": {
|
||
"type": "varchar",
|
||
"required": false,
|
||
"maxLength": 255,
|
||
"tooltip": true,
|
||
"isCustom": true
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Definition in i18n-Dateien (i18n/de_DE/{EntityType}.json):
|
||
```json
|
||
{
|
||
"fields": {
|
||
"lage": "Lage"
|
||
},
|
||
"links": {},
|
||
"labels": {},
|
||
"tooltips": {
|
||
"lage": "Lage innerhalb des Objekts (z.B. EG links, 1. OG rechts)"
|
||
}
|
||
}
|
||
```
|
||
|
||
Best Practice:
|
||
- Tooltip-Texte sollten kurz und prägnant sein (1-2 Sätze)
|
||
- Tooltips in allen Sprachen definieren (de_DE, en_US, etc.)
|
||
- Nach Änderungen Rebuild durchführen
|
||
- Tooltips werden nur angezeigt, wenn `"tooltip": true` in der entityDef gesetzt ist
|
||
|
||
## 8. Custom Scripts und Tools
|
||
|
||
Um die Entwicklung und Wartung zu erleichtern, wurden benutzerdefinierte Scripts im `custom/scripts/`-Ordner abgelegt. Diese Scripts überleben EspoCRM-Updates, da sie außerhalb der Core-Dateien liegen.
|
||
|
||
### Verfügbare Scripts:
|
||
|
||
#### workflow_manager.php
|
||
- **Zweck**: Verwaltung von BPMN-Workflows in EspoCRM. Ermöglicht das Lesen, Bearbeiten, Löschen, Ausführen und Testen von Workflows direkt über die Datenbank.
|
||
- **Bedienung**:
|
||
- Ausführen im EspoCRM-Container: `docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php <aktion> [parameter]`
|
||
- Aktionen:
|
||
- `list`: Listet alle verfügbaren Workflows auf (ID und Name).
|
||
- `read <id>`: Zeigt detaillierte Informationen zu einem Workflow (inkl. JSON-Data).
|
||
- `delete <id>`: Löscht einen Workflow (mit Bestätigung).
|
||
- `edit <id> <json_data>`: Bearbeitet die Workflow-Data (übergib gültiges JSON).
|
||
- `execute <workflow_id> <record_id>`: Führt einen Workflow manuell für einen Record aus (simuliert Trigger).
|
||
- `test <id>`: Testet Workflow-Bedingungen (simuliert Auswertung).
|
||
- **Beispiele**:
|
||
- `docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php list`
|
||
- `docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php read 68df9eb6b8d460186`
|
||
- `docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php execute 68df9eb6b8d460186 some_record_id`
|
||
- **Hinweise**:
|
||
- Sichere Backups vor Lösch- oder Edit-Operationen.
|
||
- Für komplexe Änderungen die EspoCRM-UI verwenden.
|
||
- Execute simuliert nur einfache Aktionen; für vollständige Ausführung EspoCRM-API nutzen.
|
||
|
||
## 8. Troubleshooting
|
||
|
||
### 404-Fehler "Link does not exist"
|
||
- **Symptom**: HTTP 404-Fehler in Logs: "Link does not exist" beim Versuch, eine Relationship anzuzeigen oder zu verknüpfen.
|
||
- **Ursache**: Bei hasMany-Relationships fehlt die Definition auf einer Seite der Beziehung. EspoCRM benötigt bidirektionale Link-Definitionen.
|
||
- **Lösung**:
|
||
- Prüfe beide entityDefs-Dateien (z.B. `CBeteiligte.json` UND `Contact.json`).
|
||
- Stelle sicher, dass beide Seiten den Link mit derselben `relationName` definieren.
|
||
- Das `foreign`-Attribut muss jeweils auf den Link-Namen der Gegenseite zeigen.
|
||
- Beispiel:
|
||
```json
|
||
// In CBeteiligte.json:
|
||
"contactsBeteiligte": {
|
||
"type": "hasMany",
|
||
"relationName": "cBeteiligteContact",
|
||
"foreign": "cBeteiligteContact",
|
||
"entity": "Contact"
|
||
}
|
||
|
||
// In Contact.json:
|
||
"cBeteiligteContact": {
|
||
"type": "hasMany",
|
||
"relationName": "cBeteiligteContact",
|
||
"foreign": "contactsBeteiligte",
|
||
"entity": "CBeteiligte"
|
||
}
|
||
```
|
||
- Nach Korrektur: `docker exec espocrm php /var/www/html/command.php Rebuild` ausführen.
|
||
|
||
### 500-Fehler bei Layout-Änderungen
|
||
- **Symptom**: HTTP 500-Fehler beim Versuch, Layouts in der EspoCRM-UI zu bearbeiten (z.B. "Permission denied for custom/Espo/Custom/Resources/layouts/...").
|
||
- **Ursache**: Das `custom/`-Verzeichnis gehört `root:root`, aber der EspoCRM-Container läuft als `www-data`-User, der keine Schreibrechte hat.
|
||
- **Lösung**:
|
||
- Führe auf dem Host aus: `chown -R www-data:www-data /var/lib/docker/volumes/vmh-espocrm_espocrm/_data/custom`
|
||
- Dies gibt `www-data` Schreibrechte für Custom-Dateien.
|
||
- **Prävention**: Stelle sicher, dass neue Custom-Dateien mit korrekten Berechtigungen erstellt werden (z.B. via Docker-Container als `www-data`).
|
||
|
||
### Allgemeine Tipps
|
||
- **WICHTIG**: Nach jeder Änderung an Custom-Dateien das Check & Rebuild Script ausführen:
|
||
```bash
|
||
./custom/scripts/check_and_rebuild.sh
|
||
```
|
||
Das Script prüft automatisch auf häufige Fehler (JSON-Syntax, Dateirechte) und führt bei Fehlerfreiheit den Rebuild durch.
|
||
|
||
- Manueller Rebuild (nur falls Script nicht funktioniert):
|
||
```bash
|
||
docker exec espocrm php /var/www/html/command.php Rebuild
|
||
```
|
||
|
||
- Logs prüfen: `tail -n 100 /var/lib/docker/volumes/vmh-espocrm_espocrm/_data/data/logs/espo-YYYY-MM-DD.log`
|
||
- Bei Relationship-Problemen: Logs nach "404" und "Link does not exist" durchsuchen: `tail -n 500 /var/lib/docker/volumes/vmh-espocrm_espocrm/_data/data/logs/espo-$(date +%Y-%m-%d).log | grep -A 3 "404\|Link does not exist"`
|
||
- Bei DB-Problemen: Custom-Scripts wie `workflow_manager.php` verwenden.
|
||
|
||
### Check & Rebuild Script
|
||
|
||
Das Script `custom/scripts/check_and_rebuild.sh` automatisiert die Qualitätssicherung und führt folgende Prüfungen durch:
|
||
|
||
1. **JSON-Syntax-Validierung**: Prüft alle `.json` Dateien im `custom/` Verzeichnis auf gültiges JSON
|
||
2. **Dateirechte-Prüfung**: Stellt sicher, dass alle Dateien `www-data:www-data` als Owner haben
|
||
3. **System-Checks**: Validiert Existenz von Cache- und Logs-Verzeichnissen
|
||
4. **Automatischer Rebuild**: Bei Fehlerfreiheit wird der Rebuild durchgeführt
|
||
|
||
**Verwendung:**
|
||
```bash
|
||
# Im EspoCRM-Root-Verzeichnis ausführen
|
||
./custom/scripts/check_and_rebuild.sh
|
||
```
|
||
|
||
**Ausgabe:**
|
||
- ✓ Grün: Alles in Ordnung
|
||
- ⚠ Gelb: Warnungen (Rebuild wird trotzdem ausgeführt)
|
||
- ✗ Rot: Fehler (Rebuild wird NICHT ausgeführt)
|
||
|
||
**Bei Berechtigungsfehlern:**
|
||
```bash
|
||
sudo chown -R www-data:www-data custom/
|
||
sudo find custom/ -type f -name "*.json" -exec chmod 664 {} \;
|
||
sudo find custom/ -type d -exec chmod 775 {} \;
|
||
```
|
||
|
||
## 9. Reports und Report-Panels
|
||
|
||
EspoCRM bietet über das Advanced Pack zwei Arten von Report-Integrationen: **Report-Filter** und **Report-Panels**. Diese ermöglichen die dynamische Anzeige von gefilterten Listen in Entity-Views.
|
||
|
||
### Report-Filter
|
||
|
||
Report-Filter ermöglichen es, vordefinierte Filter auf List-Views anzuwenden, die in Datenbanktabellen gespeichert sind.
|
||
|
||
#### Struktur und Dateien:
|
||
|
||
1. **entityDefs/{EntityType}.json** - Filter-Definition
|
||
```json
|
||
{
|
||
"collection": {
|
||
"filters": {
|
||
"reportFilterXXXXXXXXXX": {
|
||
"isReportFilter": true,
|
||
"id": "reportFilterIdHere"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
2. **selectDefs/{EntityType}.json** - Filter-Klasse
|
||
```json
|
||
{
|
||
"primaryFilterClassNameMap": {
|
||
"reportFilterXXXXXXXXXX": "Espo\\Modules\\Advanced\\Classes\\Select\\Common\\PrimaryFilters\\ReportFilter"
|
||
}
|
||
}
|
||
```
|
||
|
||
3. **clientDefs/{EntityType}.json** - Frontend-Integration
|
||
```json
|
||
{
|
||
"filterList": [
|
||
"__APPEND__",
|
||
{
|
||
"isReportFilter": true,
|
||
"name": "reportFilterXXXXXXXXXX",
|
||
"accessDataList": [
|
||
{
|
||
"teamIdList": ["team-id-here"]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
4. **i18n/{Language}/{EntityType}.json** - Übersetzungen
|
||
```json
|
||
{
|
||
"presetFilters": {
|
||
"reportFilterXXXXXXXXXX": "Filter-Name"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Report-Panels
|
||
|
||
Report-Panels zeigen Listen von Entitäten in Side-Panels der Detail-View an. Sie können Team-basierte Zugriffskontrolle haben.
|
||
|
||
#### Struktur:
|
||
|
||
**clientDefs/{EntityType}.json** - Panel-Definition
|
||
```json
|
||
{
|
||
"sidePanels": {
|
||
"detail": [
|
||
"__APPEND__",
|
||
{
|
||
"isReportPanel": true,
|
||
"name": "reportPanelXXXXXXXXXX",
|
||
"label": "Panel-Titel",
|
||
"view": "advanced:views/report-panel/record/panels/report-panel-side",
|
||
"reportPanelId": "reportPanelIdHere",
|
||
"reportType": "List",
|
||
"reportEntityType": "EntityType",
|
||
"displayType": "List",
|
||
"displayTotal": false,
|
||
"displayOnlyTotal": false,
|
||
"useSiMultiplier": true,
|
||
"accessDataList": [
|
||
{
|
||
"scope": "EntityType"
|
||
},
|
||
{
|
||
"teamIdList": ["team-id-here"]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### Wichtige Eigenschaften:
|
||
|
||
- **`isReportFilter`/`isReportPanel`**: Markiert den Eintrag als Report-Element
|
||
- **`accessDataList`**: Array von Zugriffsbedingungen (Team-IDs, Scopes)
|
||
- **`reportType`**: `"List"` für Listen-Reports
|
||
- **`displayType`**: Anzeige-Typ (`"List"`, `"Chart"`, etc.)
|
||
- **`view`**: Spezielle Report-Panel-View aus dem Advanced Pack
|
||
- **`__APPEND__`**: Erweitert bestehende Arrays statt sie zu überschreiben
|
||
|
||
### Best Practices:
|
||
|
||
1. **Naming Convention**:
|
||
- Filter: `reportFilter{uniqueId}` (z.B. `reportFilter6972174b6540731c1`)
|
||
- Panels: `reportPanel{uniqueId}` (z.B. `reportPanel697216784307d43ad`)
|
||
|
||
2. **Team-basierte Zugriffskontrolle**:
|
||
- Definiere `teamIdList` in `accessDataList` für eingeschränkten Zugriff
|
||
- Mehrere Teams können kombiniert werden
|
||
|
||
3. **Mehrsprachigkeit**:
|
||
- Labels in allen Sprachen definieren (de_DE, en_US)
|
||
- Fehlerhafte Labels können zu UI-Problemen führen
|
||
|
||
4. **Datei-Abhängigkeiten**:
|
||
- Report-Filter benötigen 4 Dateien: entityDefs, selectDefs, clientDefs, i18n
|
||
- Report-Panels benötigen 1 Datei: clientDefs
|
||
- Fehlende Dateien führen zu nicht-funktionalen Filtern
|
||
|
||
5. **Placeholder-Dateien**:
|
||
- `logicDefs/{EntityType}.json` kann als leeres Objekt `{}` angelegt werden
|
||
- Ermöglicht zukünftige Erweiterungen ohne Struktur-Änderungen
|
||
|
||
### Beispiel-Implementation:
|
||
|
||
**Szenario**: UserTask-Filter für Team "vermieterhelden"
|
||
|
||
```bash
|
||
# entityDefs/BpmnUserTask.json
|
||
{
|
||
"collection": {
|
||
"filters": {
|
||
"reportFilter6972174b6540731c1": {
|
||
"isReportFilter": true,
|
||
"id": "6972174b6540731c1"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
# selectDefs/BpmnUserTask.json
|
||
{
|
||
"primaryFilterClassNameMap": {
|
||
"reportFilter6972174b6540731c1": "Espo\\Modules\\Advanced\\Classes\\Select\\Common\\PrimaryFilters\\ReportFilter"
|
||
}
|
||
}
|
||
|
||
# clientDefs/BpmnUserTask.json
|
||
{
|
||
"filterList": [
|
||
"__APPEND__",
|
||
{
|
||
"isReportFilter": true,
|
||
"name": "reportFilter6972174b6540731c1",
|
||
"accessDataList": [
|
||
{
|
||
"teamIdList": ["68da9bdd622c9958a"]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
|
||
# i18n/en_US/BpmnUserTask.json
|
||
{
|
||
"presetFilters": {
|
||
"reportFilter6972174b6540731c1": "UserTask"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Troubleshooting:
|
||
|
||
- **Filter erscheint nicht**: Prüfe ob alle 4 Dateien existieren und Rebuild durchgeführt wurde
|
||
- **Zugriffsfehler**: Überprüfe `teamIdList` und User-Team-Zuordnung
|
||
- **Leere Liste**: Report-Definition in DB prüfen (Tabelle: `report`)
|
||
- **Falsches Label**: i18n-Dateien in allen Sprachen prüfen
|
||
|
||
### Nach Änderungen:
|
||
|
||
```bash
|
||
# Rebuild durchführen
|
||
docker exec espocrm php /var/www/html/command.php Rebuild
|
||
|
||
# Oder Check-Script verwenden
|
||
./custom/scripts/check_and_rebuild.sh
|
||
```
|
||
|
||
## 10. Portal-Freigabe-System
|
||
|
||
Um Entitäten für Portalnutzer (Contact-Entität) freizugeben, wurde ein konsistentes Freigabe-System implementiert:
|
||
|
||
### Implementierte Portal-Relationships:
|
||
- **CVmhMietverhltnis** → `contactsMietverhltnis` (relationName: `cVmhMietverhltnisContact`)
|
||
- **CBeteiligte** → `contactsBeteiligte` (relationName: `cBeteiligteContact`)
|
||
- **CMietobjekt** → `contactsMietobjekt` (relationName: `cMietobjektContactPortal`)
|
||
- **CAdressen** → `contactsAdressen` (relationName: `cAdressenContact`)
|
||
- **CVmhRumungsklage** → `contactsRumungsklage` (relationName: `cVmhRumungsklageContact`)
|
||
|
||
### Pattern für neue Portal-Relationships:
|
||
|
||
1. **entityDefs der Hauptentität** (z.B. `CBeteiligte.json`):
|
||
```json
|
||
"contactsBeteiligte": {
|
||
"type": "hasMany",
|
||
"relationName": "cBeteiligteContact",
|
||
"foreign": "cBeteiligteContact",
|
||
"entity": "Contact",
|
||
"audited": false,
|
||
"isCustom": true
|
||
}
|
||
```
|
||
|
||
2. **entityDefs von Contact** (`Contact.json`):
|
||
```json
|
||
"cBeteiligteContact": {
|
||
"type": "hasMany",
|
||
"relationName": "cBeteiligteContact",
|
||
"foreign": "contactsBeteiligte",
|
||
"entity": "CBeteiligte",
|
||
"audited": false,
|
||
"isCustom": true
|
||
}
|
||
```
|
||
|
||
3. **clientDefs der Hauptentität** (`CBeteiligte.json`):
|
||
```json
|
||
"relationshipPanels": {
|
||
"contactsBeteiligte": {
|
||
"layout": null,
|
||
"selectPrimaryFilterName": "portalUsers"
|
||
}
|
||
}
|
||
```
|
||
|
||
4. **bottomPanelsDetail Layout** (Tab-Ansicht):
|
||
```json
|
||
{
|
||
"_tabBreak_0": {
|
||
"index": 0,
|
||
"tabBreak": true,
|
||
"tabLabel": "Freigabe für"
|
||
},
|
||
"contactsBeteiligte": {
|
||
"dynamicLogicVisible": null,
|
||
"style": "warning",
|
||
"dynamicLogicStyled": null,
|
||
"sticked": true,
|
||
"index": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
### Wichtige Hinweise:
|
||
- `selectPrimaryFilterName: "portalUsers"` filtert automatisch auf Portal-User
|
||
- Tab "Freigabe für" sollte immer der erste Tab im Bottom-Panel sein (index: 0)
|
||
- Style "warning" hebt das Panel visuell hervor
|
||
- Nach Änderungen immer Rebuild durchführen und beide Seiten der Relationship definieren |