Compare commits
15 Commits
8d912c6613
...
56271ca05a
| Author | SHA1 | Date | |
|---|---|---|---|
| 56271ca05a | |||
| 42d396f460 | |||
| cf60d2a91d | |||
| e1a7158931 | |||
| 15ecc7068f | |||
| ac58b51452 | |||
| 185524e432 | |||
| 99045d55d2 | |||
| c9e5846110 | |||
| 37e158c806 | |||
| 8c83e54650 | |||
| e878125489 | |||
| 06326d4d0b | |||
| 96becef2ba | |||
| 5750c4486e |
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -4,6 +4,10 @@
|
|||||||
"approve": true,
|
"approve": true,
|
||||||
"matchCommandLine": true
|
"matchCommandLine": true
|
||||||
},
|
},
|
||||||
"./custom/scripts/check_and_rebuild.sh": true
|
"./custom/scripts/check_and_rebuild.sh": true,
|
||||||
|
"/^bash /var/lib/docker/volumes/vmh-espocrm_espocrm/_data/custom/scripts/check_and_rebuild\\.sh$/": {
|
||||||
|
"approve": true,
|
||||||
|
"matchCommandLine": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
657
README.md
657
README.md
@@ -1,8 +1,26 @@
|
|||||||
KI-basierte Bearbeitung von EspoCRM: Struktur und Funktionsweise
|
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.
|
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.
|
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
|
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.
|
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.
|
||||||
@@ -141,6 +159,269 @@ JSON
|
|||||||
layoutAvailabilityList: Array für Feld-Sichtbarkeit in Layouts (z. B. ["list", "detail"]).
|
layoutAvailabilityList: Array für Feld-Sichtbarkeit in Layouts (z. B. ["list", "detail"]).
|
||||||
layoutIgnoreList: Zu ignorierende Layouts.
|
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
|
3. Auslösen von Änderungen und Rebuild-Prozess
|
||||||
|
|
||||||
Was Änderungen auslösen:
|
Was Änderungen auslösen:
|
||||||
@@ -148,6 +429,185 @@ JSON
|
|||||||
Datenbank-Effekte: Neue Felder/Links in entityDefs erzeugen Tabellen/Spalten (bei Rebuild).
|
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).
|
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).
|
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:
|
Rebuild auslösen:
|
||||||
Manuell: Administration > Clear Cache & Rebuild (löscht Caches und merged Metadata neu).
|
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")).
|
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")).
|
||||||
@@ -393,7 +853,202 @@ sudo find custom/ -type f -name "*.json" -exec chmod 664 {} \;
|
|||||||
sudo find custom/ -type d -exec chmod 775 {} \;
|
sudo find custom/ -type d -exec chmod 775 {} \;
|
||||||
```
|
```
|
||||||
|
|
||||||
## 9. Portal-Freigabe-System
|
## 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:
|
Um Entitäten für Portalnutzer (Contact-Entität) freizugeben, wurde ein konsistentes Freigabe-System implementiert:
|
||||||
|
|
||||||
|
|||||||
291
client/custom/src/modules/rvg-calculator.js
Normal file
291
client/custom/src/modules/rvg-calculator.js
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
// RVG-Kalkulation ab 1.6.2025 (strenge Stufen-Regel)
|
||||||
|
// Keine Interpolation innerhalb der Stufen – nur Sprung bei Überschreiten der Obergrenze
|
||||||
|
|
||||||
|
define('custom:modules/rvg-calculator', [], function () {
|
||||||
|
|
||||||
|
const rvgTabellen = {
|
||||||
|
'2025': [ // [bis einschließlich, 1,0-Gebühr]
|
||||||
|
[500, 51.50], [1000, 93.00], [1500, 134.50], [2000, 176.00],
|
||||||
|
[3000, 235.50], [4000, 295.00], [5000, 354.50], [6000, 414.00],
|
||||||
|
[7000, 473.50], [8000, 533.00], [9000, 592.50], [10000, 652.00],
|
||||||
|
[13000, 707.00], [16000, 762.00], [19000, 817.00], [22000, 872.00],
|
||||||
|
[25000, 927.00], [30000, 1013.00], [35000, 1099.00], [40000, 1185.00],
|
||||||
|
[45000, 1271.00], [50000, 1357.00], [65000, 1456.50], [80000, 1556.00],
|
||||||
|
[95000, 1655.50], [110000, 1755.00], [125000, 1854.50], [140000, 1954.00],
|
||||||
|
[155000, 2053.50], [170000, 2153.00], [185000, 2252.50], [200000, 2352.00],
|
||||||
|
[230000, 2492.00], [260000, 2632.00], [290000, 2772.00], [320000, 2912.00],
|
||||||
|
[350000, 3052.00], [380000, 3192.00], [410000, 3332.00], [440000, 3472.00],
|
||||||
|
[470000, 3612.00], [500000, 3752.00], [550000, 3927.00], [600000, 4102.00],
|
||||||
|
[650000, 4277.00], [700000, 4452.00], [750000, 4627.00], [800000, 4802.00],
|
||||||
|
[850000, 4977.00], [900000, 5152.00], [950000, 5327.00], [1000000, 5502.00],
|
||||||
|
[1050000, 5677.00], [1100000, 5852.00], [1150000, 6027.00], [1200000, 6202.00],
|
||||||
|
[1250000, 6377.00], [1300000, 6552.00], [1350000, 6727.00], [1400000, 6902.00],
|
||||||
|
[1450000, 7077.00], [1500000, 7252.00], [1550000, 7427.00], [1600000, 7602.00],
|
||||||
|
[1650000, 7777.00], [1700000, 7952.00], [1750000, 8127.00], [1800000, 8302.00],
|
||||||
|
[1850000, 8477.00], [1900000, 8652.00], [1950000, 8827.00], [2000000, 9002.00]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
function getWertgebuehr(streitwert, tabelleName) {
|
||||||
|
tabelleName = tabelleName || '2025';
|
||||||
|
const tabelle = rvgTabellen[tabelleName];
|
||||||
|
if (!tabelle) return 0;
|
||||||
|
|
||||||
|
streitwert = Number(streitwert);
|
||||||
|
if (isNaN(streitwert) || streitwert <= 0) return 0;
|
||||||
|
if (streitwert > 2000000) return 0; // Fehler: zu hoch
|
||||||
|
|
||||||
|
for (let i = 0; i < tabelle.length; i++) {
|
||||||
|
const [bis, gebuehr] = tabelle[i];
|
||||||
|
if (streitwert <= bis) {
|
||||||
|
return gebuehr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabelle[tabelle.length - 1][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getZuschlag(anzahl) {
|
||||||
|
const extra = Math.max(0, Math.floor(anzahl) - 1);
|
||||||
|
return Math.min(2.0, extra * 0.3); // +0,3 pro weiterer Person, max +2,0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GKG Gerichtsgebühr berechnen (Gerichtskostengesetz)
|
||||||
|
function getGerichtsgebuehr(streitwert) {
|
||||||
|
if (streitwert <= 0) return 0;
|
||||||
|
|
||||||
|
let gebuehr = 40; // Basisgebühr bis 500€
|
||||||
|
|
||||||
|
if (streitwert <= 500) {
|
||||||
|
return gebuehr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bis 2.000€: je angefangene 500€ weitere 21€
|
||||||
|
if (streitwert <= 2000) {
|
||||||
|
const schritte = Math.ceil((streitwert - 500) / 500);
|
||||||
|
gebuehr += schritte * 21;
|
||||||
|
return Math.round(gebuehr * 100) / 100; // Rundung auf Cent
|
||||||
|
}
|
||||||
|
gebuehr += Math.ceil((2000 - 500) / 500) * 21; // = 3 * 21 = 63
|
||||||
|
|
||||||
|
// Bis 10.000€: je angefangene 1.000€ weitere 22,50€
|
||||||
|
if (streitwert <= 10000) {
|
||||||
|
const schritte = Math.ceil((streitwert - 2000) / 1000);
|
||||||
|
gebuehr += schritte * 22.50;
|
||||||
|
return Math.round(gebuehr * 100) / 100;
|
||||||
|
}
|
||||||
|
gebuehr += Math.ceil((10000 - 2000) / 1000) * 22.50; // = 8 * 22.50 = 180
|
||||||
|
|
||||||
|
// Bis 25.000€: je angefangene 3.000€ weitere 30,50€
|
||||||
|
if (streitwert <= 25000) {
|
||||||
|
const schritte = Math.ceil((streitwert - 10000) / 3000);
|
||||||
|
gebuehr += schritte * 30.50;
|
||||||
|
return Math.round(gebuehr * 100) / 100;
|
||||||
|
}
|
||||||
|
gebuehr += Math.ceil((25000 - 10000) / 3000) * 30.50; // = 5 * 30.50 = 152.50
|
||||||
|
|
||||||
|
// Bis 50.000€: je angefangene 5.000€ weitere 40,50€
|
||||||
|
if (streitwert <= 50000) {
|
||||||
|
const schritte = Math.ceil((streitwert - 25000) / 5000);
|
||||||
|
gebuehr += schritte * 40.50;
|
||||||
|
return Math.round(gebuehr * 100) / 100;
|
||||||
|
}
|
||||||
|
gebuehr += Math.ceil((50000 - 25000) / 5000) * 40.50; // = 5 * 40.50 = 202.50
|
||||||
|
|
||||||
|
// Bis 200.000€: je angefangene 15.000€ weitere 140€
|
||||||
|
if (streitwert <= 200000) {
|
||||||
|
const schritte = Math.ceil((streitwert - 50000) / 15000);
|
||||||
|
gebuehr += schritte * 140;
|
||||||
|
return Math.round(gebuehr * 100) / 100;
|
||||||
|
}
|
||||||
|
gebuehr += Math.ceil((200000 - 50000) / 15000) * 140; // = 10 * 140 = 1400
|
||||||
|
|
||||||
|
// Bis 500.000€: je angefangene 30.000€ weitere 210€
|
||||||
|
if (streitwert <= 500000) {
|
||||||
|
const schritte = Math.ceil((streitwert - 200000) / 30000);
|
||||||
|
gebuehr += schritte * 210;
|
||||||
|
return Math.round(gebuehr * 100) / 100;
|
||||||
|
}
|
||||||
|
gebuehr += Math.ceil((500000 - 200000) / 30000) * 210; // = 10 * 210 = 2100
|
||||||
|
|
||||||
|
// Über 500.000€: je angefangene 50.000€ weitere 210€
|
||||||
|
const schritte = Math.ceil((streitwert - 500000) / 50000);
|
||||||
|
gebuehr += schritte * 210;
|
||||||
|
|
||||||
|
return Math.round(gebuehr * 100) / 100; // Rundung auf Cent
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
kalkuliereKosten: function(streitwert, anzahlKlaeger, anzahlBeklagte, ustProzent, tabelle) {
|
||||||
|
anzahlKlaeger = anzahlKlaeger || 1;
|
||||||
|
anzahlBeklagte = anzahlBeklagte || 1;
|
||||||
|
if (typeof ustProzent === 'undefined' || ustProzent === null) {
|
||||||
|
ustProzent = 19;
|
||||||
|
}
|
||||||
|
tabelle = tabelle || '2025';
|
||||||
|
|
||||||
|
const ustSatz = ustProzent / 100;
|
||||||
|
const w = getWertgebuehr(streitwert, tabelle);
|
||||||
|
|
||||||
|
if (w === 0) {
|
||||||
|
return {
|
||||||
|
streitwert: streitwert,
|
||||||
|
wertgebuehr: 0,
|
||||||
|
aussergerichtlichNetto: 0,
|
||||||
|
aussergerichtlichBrutto: 0,
|
||||||
|
gerichtskosten1Instanz: 0,
|
||||||
|
anwaltskostenKlaeger1InstanzNetto: 0,
|
||||||
|
anwaltskostenKlaeger1InstanzBrutto: 0,
|
||||||
|
vergleichsgebuehrKlaeger1InstanzNetto: 0,
|
||||||
|
vergleichsgebuehrKlaeger1InstanzBrutto: 0,
|
||||||
|
anwaltskostenBeklagte1InstanzNetto: 0,
|
||||||
|
anwaltskostenBeklagte1InstanzBrutto: 0,
|
||||||
|
vergleichsgebuehrBeklagte1InstanzNetto: 0,
|
||||||
|
vergleichsgebuehrBeklagte1InstanzBrutto: 0,
|
||||||
|
gerichtskosten2Instanz: 0,
|
||||||
|
anwaltskostenKlaeger2InstanzNetto: 0,
|
||||||
|
anwaltskostenKlaeger2InstanzBrutto: 0,
|
||||||
|
vergleichsgebuehrKlaeger2InstanzNetto: 0,
|
||||||
|
vergleichsgebuehrKlaeger2InstanzBrutto: 0,
|
||||||
|
anwaltskostenBeklagte2InstanzNetto: 0,
|
||||||
|
anwaltskostenBeklagte2InstanzBrutto: 0,
|
||||||
|
vergleichsgebuehrBeklagte2InstanzNetto: 0,
|
||||||
|
vergleichsgebuehrBeklagte2InstanzBrutto: 0,
|
||||||
|
zwangsvollstreckungRaeumungNetto: 0,
|
||||||
|
zwangsvollstreckungRaeumungBrutto: 0,
|
||||||
|
kostenRaeumungsantrag: 0,
|
||||||
|
vorzusch1InstanzNetto: 0,
|
||||||
|
vorzusch1InstanzBrutto: 0,
|
||||||
|
vergleich1InstanzGk: 0,
|
||||||
|
vergleich1InstanzAnwK: 0,
|
||||||
|
vergleich1InstanzSumme: 0,
|
||||||
|
saeumnis1InstanzGk: 0,
|
||||||
|
saeumnis1InstanzAnwK: 0,
|
||||||
|
saeumnis1InstanzSumme: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const zuschlagK = getZuschlag(anzahlKlaeger);
|
||||||
|
const zuschlagB = getZuschlag(anzahlBeklagte);
|
||||||
|
|
||||||
|
|
||||||
|
// Außergerichtlich (nur Klägerseite)
|
||||||
|
const ausserSatz = 1.3 + zuschlagK;
|
||||||
|
const ausserGeb = w * ausserSatz;
|
||||||
|
const ausserPausch = Math.min(20, 0.2 * ausserGeb);
|
||||||
|
const ausserNetto = ausserGeb + ausserPausch;
|
||||||
|
const ausserBrutto = ausserNetto * (1 + ustSatz);
|
||||||
|
|
||||||
|
// Gerichtskosten 1. Instanz (GKG-Tabelle, 3,0 Gebühren)
|
||||||
|
const gkEinfach = getGerichtsgebuehr(streitwert);
|
||||||
|
const gk1 = gkEinfach * 3.0;
|
||||||
|
|
||||||
|
// Anwaltskosten Kläger 1. Instanz
|
||||||
|
const inst1VerfK = w * (1.3 + zuschlagK);
|
||||||
|
const inst1TermK = w * 1.2;
|
||||||
|
const inst1PauschK = Math.min(20, 0.2 * (inst1VerfK + inst1TermK));
|
||||||
|
const inst1NettoK = inst1VerfK + inst1TermK + inst1PauschK;
|
||||||
|
const inst1BruttoK = inst1NettoK * (1 + ustSatz);
|
||||||
|
|
||||||
|
const vergl1KNetto = w * 1.0;
|
||||||
|
const vergl1KBrutto = vergl1KNetto * (1 + ustSatz);
|
||||||
|
|
||||||
|
// Anwaltskosten Beklagte 1. Instanz
|
||||||
|
const inst1VerfB = w * (1.3 + zuschlagB);
|
||||||
|
const inst1TermB = w * 1.2;
|
||||||
|
const inst1PauschB = Math.min(20, 0.2 * (inst1VerfB + inst1TermB));
|
||||||
|
const inst1NettoB = inst1VerfB + inst1TermB + inst1PauschB;
|
||||||
|
const inst1BruttoB = inst1NettoB * (1 + ustSatz);
|
||||||
|
|
||||||
|
const vergl1BNetto = w * 1.0;
|
||||||
|
const vergl1BBrutto = vergl1BNetto * (1 + ustSatz);
|
||||||
|
|
||||||
|
// Gerichtskosten 2. Instanz (GKG-Tabelle, 4,0 Gebühren)
|
||||||
|
const gk2 = gkEinfach * 4.0;
|
||||||
|
|
||||||
|
// Anwaltskosten Kläger 2. Instanz
|
||||||
|
const inst2VerfK = w * (1.6 + zuschlagK);
|
||||||
|
const inst2TermK = w * 1.2;
|
||||||
|
const inst2PauschK = Math.min(20, 0.2 * (inst2VerfK + inst2TermK));
|
||||||
|
const inst2NettoK = inst2VerfK + inst2TermK + inst2PauschK;
|
||||||
|
const inst2BruttoK = inst2NettoK * (1 + ustSatz);
|
||||||
|
|
||||||
|
const vergl2KNetto = w * 1.0;
|
||||||
|
const vergl2KBrutto = vergl2KNetto * (1 + ustSatz);
|
||||||
|
|
||||||
|
// Anwaltskosten Beklagte 2. Instanz
|
||||||
|
const inst2VerfB = w * (1.6 + zuschlagB);
|
||||||
|
const inst2TermB = w * 1.2;
|
||||||
|
const inst2PauschB = Math.min(20, 0.2 * (inst2VerfB + inst2TermB));
|
||||||
|
const inst2NettoB = inst2VerfB + inst2TermB + inst2PauschB;
|
||||||
|
const inst2BruttoB = inst2NettoB * (1 + ustSatz);
|
||||||
|
|
||||||
|
const vergl2BNetto = w * 1.0;
|
||||||
|
const vergl2BBrutto = vergl2BNetto * (1 + ustSatz);
|
||||||
|
|
||||||
|
// Zwangsvollstreckung Räumung = Räumungsantrag (identisch)
|
||||||
|
// Verfahrensgebühr 0,3 + 0,3 pro weitere Person + Pauschale 20% (max 20€)
|
||||||
|
const zvBasis = w * 0.3;
|
||||||
|
const zvExtraPersonen = ((anzahlKlaeger - 1) + (anzahlBeklagte - 1)) * 0.3 * w;
|
||||||
|
const zvVerfK = zvBasis + zvExtraPersonen;
|
||||||
|
const zvPauschK = Math.min(20, 0.2 * zvVerfK);
|
||||||
|
const zvNetto = zvVerfK + zvPauschK;
|
||||||
|
const zvBrutto = zvNetto * (1 + ustSatz);
|
||||||
|
|
||||||
|
// Kosten Räumungsantrag (identisch mit Zwangsvollstreckung)
|
||||||
|
const raeumGesamt = zvBrutto;
|
||||||
|
|
||||||
|
// Vorauszuschießende Kosten 1. Instanz (inkl. Gerichtskosten!)
|
||||||
|
const vorzusch1Netto = inst1VerfK + inst1TermK + inst1PauschK + gk1;
|
||||||
|
const vorzusch1Brutto = (inst1VerfK + inst1TermK + inst1PauschK) * (1 + ustSatz) + gk1;
|
||||||
|
|
||||||
|
// Vergleichsszenario 1. Instanz (Vergleichsgebühr + nur 1,0 Gerichtsgebühr statt 3,0)
|
||||||
|
const vergl1Gk = gkEinfach * 1.0; // nur 1,0 statt 3,0
|
||||||
|
const vergl1AnwKNetto = inst1VerfK + inst1TermK + vergl1KNetto + inst1PauschK; // Verf + Term + Vergl
|
||||||
|
const vergl1AnwKBrutto = vergl1AnwKNetto * (1 + ustSatz);
|
||||||
|
const vergl1GesamtBrutto = vergl1AnwKBrutto + vergl1Gk;
|
||||||
|
|
||||||
|
// Säumnisszenario 1. Instanz (0,5 Terminsgebühr statt 1,2)
|
||||||
|
const saeum1TermK = w * 0.5; // reduzierte Terminsgebühr
|
||||||
|
const saeum1AnwKNetto = inst1VerfK + saeum1TermK + inst1PauschK;
|
||||||
|
const saeum1AnwKBrutto = saeum1AnwKNetto * (1 + ustSatz);
|
||||||
|
const saeum1GesamtBrutto = saeum1AnwKBrutto + gk1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
streitwert: streitwert,
|
||||||
|
wertgebuehr: w,
|
||||||
|
aussergerichtlichNetto: ausserNetto,
|
||||||
|
aussergerichtlichBrutto: ausserBrutto,
|
||||||
|
gerichtskosten1Instanz: gk1,
|
||||||
|
anwaltskostenKlaeger1InstanzNetto: inst1NettoK,
|
||||||
|
anwaltskostenKlaeger1InstanzBrutto: inst1BruttoK,
|
||||||
|
vergleichsgebuehrKlaeger1InstanzNetto: vergl1KNetto,
|
||||||
|
vergleichsgebuehrKlaeger1InstanzBrutto: vergl1KBrutto,
|
||||||
|
anwaltskostenBeklagte1InstanzNetto: inst1NettoB,
|
||||||
|
anwaltskostenBeklagte1InstanzBrutto: inst1BruttoB,
|
||||||
|
vergleichsgebuehrBeklagte1InstanzNetto: vergl1BNetto,
|
||||||
|
vergleichsgebuehrBeklagte1InstanzBrutto: vergl1BBrutto,
|
||||||
|
gerichtskosten2Instanz: gk2,
|
||||||
|
anwaltskostenKlaeger2InstanzNetto: inst2NettoK,
|
||||||
|
anwaltskostenKlaeger2InstanzBrutto: inst2BruttoK,
|
||||||
|
vergleichsgebuehrKlaeger2InstanzNetto: vergl2KNetto,
|
||||||
|
vergleichsgebuehrKlaeger2InstanzBrutto: vergl2KBrutto,
|
||||||
|
anwaltskostenBeklagte2InstanzNetto: inst2NettoB,
|
||||||
|
anwaltskostenBeklagte2InstanzBrutto: inst2BruttoB,
|
||||||
|
vergleichsgebuehrBeklagte2InstanzNetto: vergl2BNetto,
|
||||||
|
vergleichsgebuehrBeklagte2InstanzBrutto: vergl2BBrutto,
|
||||||
|
zwangsvollstreckungRaeumungNetto: zvNetto,
|
||||||
|
zwangsvollstreckungRaeumungBrutto: zvBrutto,
|
||||||
|
kostenRaeumungsantrag: raeumGesamt,
|
||||||
|
vorzusch1InstanzNetto: vorzusch1Netto,
|
||||||
|
vorzusch1InstanzBrutto: vorzusch1Brutto,
|
||||||
|
vergleich1InstanzGk: vergl1Gk,
|
||||||
|
vergleich1InstanzAnwK: vergl1AnwKBrutto,
|
||||||
|
vergleich1InstanzSumme: vergl1GesamtBrutto,
|
||||||
|
saeumnis1InstanzGk: gk1,
|
||||||
|
saeumnis1InstanzAnwK: saeum1AnwKBrutto,
|
||||||
|
saeumnis1InstanzSumme: saeum1GesamtBrutto
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
define('custom:views/c-vmh-erstgespraech/fields/rvg-calculated', [
|
||||||
|
'views/fields/currency',
|
||||||
|
'custom:modules/rvg-calculator'
|
||||||
|
], function (Dep, RvgCalculator) {
|
||||||
|
|
||||||
|
return Dep.extend({
|
||||||
|
|
||||||
|
setup: function () {
|
||||||
|
Dep.prototype.setup.call(this);
|
||||||
|
|
||||||
|
this.calculating = false;
|
||||||
|
|
||||||
|
// Listen to changes on relevant fields (combined listener)
|
||||||
|
this.listenTo(this.model, 'change:streitwert change:anzahlVermieter change:anzahlMieter change:anzahlSonstigeVolljhrigeBewohner change:ustSatz', this.calculate.bind(this));
|
||||||
|
|
||||||
|
// Initial calculation
|
||||||
|
this.calculate();
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate: function () {
|
||||||
|
if (this.calculating) return;
|
||||||
|
this.calculating = true;
|
||||||
|
|
||||||
|
var streitwert = parseFloat(this.model.get('streitwert')) || 0;
|
||||||
|
var anzahlKlaeger = parseInt(this.model.get('anzahlVermieter')) || 1;
|
||||||
|
var anzahlMieter = parseInt(this.model.get('anzahlMieter')) || 0;
|
||||||
|
var anzahlSonstige = parseInt(this.model.get('anzahlSonstigeVolljhrigeBewohner')) || 0;
|
||||||
|
var anzahlBeklagte = anzahlMieter + anzahlSonstige;
|
||||||
|
if (anzahlBeklagte < 1) anzahlBeklagte = 1;
|
||||||
|
|
||||||
|
// USt-Satz: "0" oder "19" (String) direkt als Integer
|
||||||
|
var ustSatzString = this.model.get('ustSatz') || '19';
|
||||||
|
var ustSatz = parseInt(ustSatzString);
|
||||||
|
|
||||||
|
var result = RvgCalculator.kalkuliereKosten(streitwert, anzahlKlaeger, anzahlBeklagte, ustSatz);
|
||||||
|
|
||||||
|
// Update all cost fields
|
||||||
|
this.model.set({
|
||||||
|
'aussergerichtlicheGebuehren': result.aussergerichtlichBrutto,
|
||||||
|
'kostenRaeumungsantrag': result.kostenRaeumungsantrag,
|
||||||
|
'gerichtskosten1Instanz': result.gerichtskosten1Instanz,
|
||||||
|
'anwaltskostenKlaeger1Instanz': result.anwaltskostenKlaeger1InstanzBrutto,
|
||||||
|
'vorzusch1Instanz': result.vorzusch1InstanzBrutto,
|
||||||
|
'vergleich1InstanzGk': result.vergleich1InstanzGk,
|
||||||
|
'vergleich1InstanzAnwK': result.vergleich1InstanzAnwK,
|
||||||
|
'vergleich1InstanzSumme': result.vergleich1InstanzSumme,
|
||||||
|
'saeumnis1InstanzGk': result.saeumnis1InstanzGk,
|
||||||
|
'saeumnis1InstanzAnwK': result.saeumnis1InstanzAnwK,
|
||||||
|
'saeumnis1InstanzSumme': result.saeumnis1InstanzSumme
|
||||||
|
});
|
||||||
|
|
||||||
|
this.calculating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
define('custom:views/c-vmh-erstgespraech/fields/streitwert', ['views/fields/currency'], function (Dep) {
|
||||||
|
|
||||||
|
return Dep.extend({
|
||||||
|
|
||||||
|
setup: function () {
|
||||||
|
Dep.prototype.setup.call(this);
|
||||||
|
|
||||||
|
this.calculating = false;
|
||||||
|
|
||||||
|
// Listen to changes on dependent fields
|
||||||
|
this.listenTo(this.model, 'change:kaltmiete', this.calculate.bind(this));
|
||||||
|
this.listenTo(this.model, 'change:bKPauschale', this.calculate.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
afterRender: function () {
|
||||||
|
Dep.prototype.afterRender.call(this);
|
||||||
|
// Don't calculate on initial render - only on changes
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate: function () {
|
||||||
|
if (this.calculating) return;
|
||||||
|
this.calculating = true;
|
||||||
|
|
||||||
|
var kaltmiete = parseFloat(this.model.get('kaltmiete')) || 0;
|
||||||
|
var bKPauschale = parseFloat(this.model.get('bKPauschale')) || 0;
|
||||||
|
|
||||||
|
var streitwert = (kaltmiete + bKPauschale) * 12;
|
||||||
|
|
||||||
|
// Set value - this will trigger the parent view to update
|
||||||
|
this.model.set('streitwert', streitwert);
|
||||||
|
|
||||||
|
this.calculating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
define('custom:views/c-vmh-erstgespraech/fields/warmmiete', ['views/fields/currency'], function (Dep) {
|
||||||
|
|
||||||
|
return Dep.extend({
|
||||||
|
|
||||||
|
setup: function () {
|
||||||
|
Dep.prototype.setup.call(this);
|
||||||
|
|
||||||
|
this.calculating = false;
|
||||||
|
|
||||||
|
// Listen to changes on dependent fields
|
||||||
|
this.listenTo(this.model, 'change:kaltmiete', this.calculate.bind(this));
|
||||||
|
this.listenTo(this.model, 'change:bKVorauszahlung', this.calculate.bind(this));
|
||||||
|
this.listenTo(this.model, 'change:bKPauschale', this.calculate.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
afterRender: function () {
|
||||||
|
Dep.prototype.afterRender.call(this);
|
||||||
|
// Don't calculate on initial render - only on changes
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate: function () {
|
||||||
|
if (this.calculating) return;
|
||||||
|
this.calculating = true;
|
||||||
|
|
||||||
|
var kaltmiete = parseFloat(this.model.get('kaltmiete')) || 0;
|
||||||
|
var bKVorauszahlung = parseFloat(this.model.get('bKVorauszahlung')) || 0;
|
||||||
|
var bKPauschale = parseFloat(this.model.get('bKPauschale')) || 0;
|
||||||
|
|
||||||
|
var warmmiete = kaltmiete + bKVorauszahlung + bKPauschale;
|
||||||
|
|
||||||
|
// Set value - this will trigger the parent view to update
|
||||||
|
this.model.set('warmmiete', warmmiete);
|
||||||
|
|
||||||
|
this.calculating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
49
client/custom/src/views/c-vmh-erstgespraech/record/edit.js
Normal file
49
client/custom/src/views/c-vmh-erstgespraech/record/edit.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
define('custom:views/c-vmh-erstgespraech/record/edit', ['views/record/edit'], function (Dep) {
|
||||||
|
|
||||||
|
return Dep.extend({
|
||||||
|
|
||||||
|
setup: function () {
|
||||||
|
Dep.prototype.setup.call(this);
|
||||||
|
|
||||||
|
// Listen for changes on Kaltmiete, BK-Vorauszahlung, and BK-Pauschale
|
||||||
|
this.listenTo(this.model, 'change:kaltmiete change:bKVorauszahlung change:bKPauschale', function () {
|
||||||
|
this.calculateFields();
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// Initial calculation after fields are ready
|
||||||
|
this.once('after:render', function () {
|
||||||
|
this.calculateFields();
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
calculateFields: function () {
|
||||||
|
var kaltmiete = parseFloat(this.model.get('kaltmiete')) || 0;
|
||||||
|
var bKVorauszahlung = parseFloat(this.model.get('bKVorauszahlung')) || 0;
|
||||||
|
var bKPauschale = parseFloat(this.model.get('bKPauschale')) || 0;
|
||||||
|
|
||||||
|
// Berechne Warmmiete
|
||||||
|
var warmmiete = kaltmiete + bKVorauszahlung + bKPauschale;
|
||||||
|
this.model.set('warmmiete', warmmiete, {silent: false});
|
||||||
|
|
||||||
|
// Berechne Streitwert
|
||||||
|
var streitwert = (kaltmiete + bKPauschale) * 12;
|
||||||
|
this.model.set('streitwert', streitwert, {silent: false});
|
||||||
|
|
||||||
|
// Force update der View
|
||||||
|
if (this.hasView('warmmiete')) {
|
||||||
|
var warmmieteView = this.getView('warmmiete');
|
||||||
|
if (warmmieteView && warmmieteView.reRender) {
|
||||||
|
warmmieteView.reRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hasView('streitwert')) {
|
||||||
|
var streitwertView = this.getView('streitwert');
|
||||||
|
if (streitwertView && streitwertView.reRender) {
|
||||||
|
streitwertView.reRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
121
custom/CUSTOM_DIRECTORY.md
Normal file
121
custom/CUSTOM_DIRECTORY.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# EspoCRM Custom Directory - Übersicht
|
||||||
|
|
||||||
|
## Verzeichnisstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
custom/
|
||||||
|
├── Espo/
|
||||||
|
│ ├── Custom/ # Custom Entitäten, Services, Controller etc.
|
||||||
|
│ └── Modules/ # Custom Module
|
||||||
|
├── scripts/ # Custom PHP Scripts für Wartung/Verwaltung
|
||||||
|
│ ├── check_and_rebuild.sh
|
||||||
|
│ └── workflow_manager.php
|
||||||
|
└── workflows/ # Workflow-Definitionen als JSON
|
||||||
|
├── README.md
|
||||||
|
├── vmh-erstberatung-abschliessen.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zweck der Verzeichnisse
|
||||||
|
|
||||||
|
### custom/Espo/Custom/
|
||||||
|
Hauptverzeichnis für EspoCRM-Customizations:
|
||||||
|
- `Resources/metadata/` - Entity-, Field-, Client-Definitionen
|
||||||
|
- `Resources/layouts/` - UI-Layout-Definitionen
|
||||||
|
- `Resources/i18n/` - Übersetzungen
|
||||||
|
- `Classes/` - Custom PHP-Klassen
|
||||||
|
- `Controllers/` - Custom Controller
|
||||||
|
- `Services/` - Custom Services
|
||||||
|
- `Repositories/` - Custom Repositories
|
||||||
|
|
||||||
|
### custom/Espo/Modules/
|
||||||
|
Zusätzliche Module (z.B. von Extensions):
|
||||||
|
- Jedes Modul hat eigene `Resources/metadata/` Struktur
|
||||||
|
- Module sind gekapselt und wiederverwendbar
|
||||||
|
|
||||||
|
### custom/scripts/
|
||||||
|
**PHP Scripts für Wartung und Verwaltung:**
|
||||||
|
|
||||||
|
#### workflow_manager.php
|
||||||
|
Zentrale Schnittstelle für Workflow-Verwaltung:
|
||||||
|
- **list** - Alle Workflows (BPM + Simple) auflisten
|
||||||
|
- **read** - Workflow-Details anzeigen
|
||||||
|
- **import** - Workflow aus JSON importieren
|
||||||
|
- **export** - Workflow nach JSON exportieren
|
||||||
|
- **delete** - Workflow löschen
|
||||||
|
|
||||||
|
**Verwendung:**
|
||||||
|
```bash
|
||||||
|
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php <action> [args]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### check_and_rebuild.sh
|
||||||
|
Validierung und Rebuild:
|
||||||
|
- JSON-Syntax-Prüfung
|
||||||
|
- EspoCRM Rebuild
|
||||||
|
- Cache-Bereinigung
|
||||||
|
|
||||||
|
### custom/workflows/
|
||||||
|
**Workflow-Definitionen als JSON:**
|
||||||
|
- Versionskontrolle für Workflows
|
||||||
|
- Import/Export über workflow_manager.php
|
||||||
|
- Sowohl Simple Workflows als auch BPM Flowcharts
|
||||||
|
- Format-Dokumentation in `README.md`
|
||||||
|
|
||||||
|
**Workflow-Typen:**
|
||||||
|
1. **Simple Workflows** - Regel-basierte Automationen
|
||||||
|
- Trigger: afterRecordSaved, afterRecordCreated, scheduled, manual
|
||||||
|
- Bedingungen: Feld-Vergleiche (equals, changed, contains, etc.)
|
||||||
|
- Aktionen: sendEmail, createEntity, updateEntity, etc.
|
||||||
|
|
||||||
|
2. **BPM Flowcharts** - Komplexe BPMN 2.0-Workflows
|
||||||
|
- Visuelle Designer im Admin-Interface
|
||||||
|
- Start-Events, Gateways, Tasks, End-Events
|
||||||
|
- Für mehrstufige Geschäftsprozesse
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Workflow-Entwicklung
|
||||||
|
1. Workflow als JSON in `custom/workflows/` erstellen
|
||||||
|
2. Mit `workflow_manager.php import` einspielen
|
||||||
|
3. Im Admin-Interface testen
|
||||||
|
4. Bei Änderungen: Export → Anpassung → Import
|
||||||
|
|
||||||
|
### Versionskontrolle
|
||||||
|
- Alle JSON-Dateien in Git committen
|
||||||
|
- Beschreibende Dateinamen (z.B. `vmh-<entity>-<funktion>.json`)
|
||||||
|
- Regelmäßig Backups per `export` erstellen
|
||||||
|
|
||||||
|
### Änderungen anwenden
|
||||||
|
Nach Metadata-Änderungen immer:
|
||||||
|
```bash
|
||||||
|
docker exec espocrm php /var/www/html/command.php rebuild
|
||||||
|
# oder
|
||||||
|
./custom/scripts/check_and_rebuild.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nützliche Befehle
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Alle Workflows auflisten
|
||||||
|
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php list
|
||||||
|
|
||||||
|
# Workflow importieren
|
||||||
|
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php import \
|
||||||
|
/var/www/html/custom/workflows/my-workflow.json
|
||||||
|
|
||||||
|
# Workflow exportieren (Backup)
|
||||||
|
docker exec espocrm php /var/www/html/custom/scripts/workflow_manager.php export \
|
||||||
|
<workflow-id> /var/www/html/custom/workflows/backup-workflow.json
|
||||||
|
|
||||||
|
# System rebuilden
|
||||||
|
docker exec espocrm php /var/www/html/command.php rebuild
|
||||||
|
|
||||||
|
# Cache löschen
|
||||||
|
docker exec espocrm rm -rf /var/www/html/data/cache/*
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dokumentation
|
||||||
|
|
||||||
|
- **Hauptdokumentation:** `/README.md` - Vollständige KI-Dokumentation für EspoCRM
|
||||||
|
- **Workflow-Formate:** `/custom/workflows/README.md` - JSON-Format-Spezifikationen
|
||||||
|
- **EspoCRM Docs:** https://docs.espocrm.com
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Espo\Custom\Classes\FormulaFunctions\IbanGroup;
|
||||||
|
|
||||||
|
use Espo\Core\Formula\Functions\BaseFunction;
|
||||||
|
use Espo\Core\Formula\ArgumentList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IBAN-Validierung mit Modulo-97-Algorithmus (ISO 13616)
|
||||||
|
* Mathematische Prüfung ohne externe Datenbank
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leerzeichen entfernen und in Großbuchstaben umwandeln
|
||||||
|
$iban = strtoupper(str_replace(' ', '', trim($iban)));
|
||||||
|
|
||||||
|
// Basis-Format prüfen: Mindestens 15, maximal 34 Zeichen
|
||||||
|
$length = strlen($iban);
|
||||||
|
if ($length < 15 || $length > 34) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format prüfen: 2 Buchstaben (Ländercode) + 2 Ziffern (Prüfziffer) + Rest alphanumerisch
|
||||||
|
if (!preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]+$/', $iban)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ländercode extrahieren und Länge prüfen (optionale erweiterte Prüfung)
|
||||||
|
$countryCode = substr($iban, 0, 2);
|
||||||
|
$expectedLength = $this->getIbanLength($countryCode);
|
||||||
|
if ($expectedLength && $length !== $expectedLength) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modulo-97-Algorithmus (ISO 13616)
|
||||||
|
// 1. IBAN umstellen: ersten 4 Zeichen ans Ende
|
||||||
|
$rearranged = substr($iban, 4) . substr($iban, 0, 4);
|
||||||
|
|
||||||
|
// 2. Buchstaben in Zahlen umwandeln (A=10, B=11, ..., Z=35)
|
||||||
|
$numericString = '';
|
||||||
|
for ($i = 0; $i < strlen($rearranged); $i++) {
|
||||||
|
$char = $rearranged[$i];
|
||||||
|
if (ctype_alpha($char)) {
|
||||||
|
// A=65 -> 10, B=66 -> 11, ..., Z=90 -> 35
|
||||||
|
$numericString .= (string)(ord($char) - 55);
|
||||||
|
} else {
|
||||||
|
$numericString .= $char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Modulo 97 berechnen (schrittweise wegen großer Zahlen)
|
||||||
|
$remainder = 0;
|
||||||
|
for ($i = 0; $i < strlen($numericString); $i++) {
|
||||||
|
$remainder = ($remainder * 10 + (int)$numericString[$i]) % 97;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Rest muss genau 1 sein für gültige IBAN
|
||||||
|
return $remainder === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die erwartete Länge einer IBAN für einen Ländercode zurück
|
||||||
|
* Quelle: ISO 13616 / SWIFT IBAN Registry
|
||||||
|
*/
|
||||||
|
private function getIbanLength(string $countryCode): ?int
|
||||||
|
{
|
||||||
|
$lengths = [
|
||||||
|
'AD' => 24, 'AE' => 23, 'AL' => 28, 'AT' => 20, 'AZ' => 28,
|
||||||
|
'BA' => 20, 'BE' => 16, 'BG' => 22, 'BH' => 22, 'BR' => 29,
|
||||||
|
'BY' => 28, 'CH' => 21, 'CR' => 22, 'CY' => 28, 'CZ' => 24,
|
||||||
|
'DE' => 22, 'DK' => 18, 'DO' => 28, 'EE' => 20, 'EG' => 29,
|
||||||
|
'ES' => 24, 'FI' => 18, 'FO' => 18, 'FR' => 27, 'GB' => 22,
|
||||||
|
'GE' => 22, 'GI' => 23, 'GL' => 18, 'GR' => 27, 'GT' => 28,
|
||||||
|
'HR' => 21, 'HU' => 28, 'IE' => 22, 'IL' => 23, 'IS' => 26,
|
||||||
|
'IT' => 27, 'JO' => 30, 'KW' => 30, 'KZ' => 20, 'LB' => 28,
|
||||||
|
'LC' => 32, 'LI' => 21, 'LT' => 20, 'LU' => 20, 'LV' => 21,
|
||||||
|
'MC' => 27, 'MD' => 24, 'ME' => 22, 'MK' => 19, 'MR' => 27,
|
||||||
|
'MT' => 31, 'MU' => 30, 'NL' => 18, 'NO' => 15, 'PK' => 24,
|
||||||
|
'PL' => 28, 'PS' => 29, 'PT' => 25, 'QA' => 29, 'RO' => 24,
|
||||||
|
'RS' => 22, 'SA' => 24, 'SE' => 24, 'SI' => 19, 'SK' => 24,
|
||||||
|
'SM' => 27, 'TN' => 24, 'TR' => 26, 'UA' => 29, 'VA' => 22,
|
||||||
|
'VG' => 24, 'XK' => 20,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $lengths[$countryCode] ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
custom/Espo/Custom/Controllers/CBankverbindungen.php
Normal file
7
custom/Espo/Custom/Controllers/CBankverbindungen.php
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Espo\Custom\Controllers;
|
||||||
|
|
||||||
|
class CBankverbindungen extends \Espo\Core\Templates\Controllers\Base
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Espo\Custom\Controllers;
|
|
||||||
|
|
||||||
class CVMHBeteiligte extends \Espo\Core\Templates\Controllers\Person
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "إنشاء {الكيانTypeTranslated}"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "العنوان"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "الاجتماعات",
|
|
||||||
"calls": "المكالمات",
|
|
||||||
"tasks": "مهام"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "إنشاء {الكيانTypeTranslated}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Създаване на Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Адрес"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Срещи",
|
|
||||||
"calls": "Разговори",
|
|
||||||
"tasks": "Задачи"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Създаване на VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Vytvořit Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Vytvořit VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Opret Bankverbindung "
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adresse"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Møder",
|
|
||||||
"calls": "Opkald",
|
|
||||||
"tasks": "Opgaver"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Opret VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Bankverbindung erstellen",
|
||||||
|
"CBankverbindungen": "Bankverbindungen"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"name": "Name",
|
||||||
|
"iban": "IBAN",
|
||||||
|
"bic": "BIC/SWIFT",
|
||||||
|
"kontoinhaber": "Kontoinhaber",
|
||||||
|
"bankname": "Bankname",
|
||||||
|
"istAktiv": "Ist aktiv",
|
||||||
|
"istStandard": "Standard-Konto",
|
||||||
|
"advowareKontoId": "Advoware Konto-ID",
|
||||||
|
"advowareLastSync": "Advoware letzte Synchronisation",
|
||||||
|
"syncStatus": "Sync-Status",
|
||||||
|
"beteiligte": "Beteiligter",
|
||||||
|
"createdAt": "Erstellt am",
|
||||||
|
"modifiedAt": "Geändert am",
|
||||||
|
"createdBy": "Erstellt von",
|
||||||
|
"modifiedBy": "Geändert von",
|
||||||
|
"assignedUser": "Zugewiesen an",
|
||||||
|
"teams": "Teams"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"beteiligte": "Beteiligter",
|
||||||
|
"createdBy": "Erstellt von",
|
||||||
|
"modifiedBy": "Geändert von",
|
||||||
|
"assignedUser": "Zugewiesen an",
|
||||||
|
"teams": "Teams"
|
||||||
|
},
|
||||||
|
"tooltips": {
|
||||||
|
"name": "Bezeichnung der Bankverbindung (z.B. 'Hauptkonto', 'Geschäftskonto', 'Mietkautionskonto')",
|
||||||
|
"iban": "Internationale Bankkontonummer im Format DE89370400440532013000. Nur Großbuchstaben und Ziffern, 2-stelliger Ländercode gefolgt von Prüfziffer und Kontonummer (max. 34 Zeichen)",
|
||||||
|
"bic": "Bank Identifier Code (SWIFT-Code) im Format COBADEFFXXX. 8 oder 11 Zeichen: 4 Zeichen Bankcode, 2 Zeichen Ländercode, 2 Zeichen Ortscode, optional 3 Zeichen Filialcode",
|
||||||
|
"kontoinhaber": "Vollständiger Name des Kontoinhabers, wie auf dem Bankkonto hinterlegt",
|
||||||
|
"bankname": "Name der kontoführenden Bank (z.B. 'Sparkasse Köln Bonn', 'Deutsche Bank')",
|
||||||
|
"istAktiv": "Deaktivierte Bankverbindungen werden nicht mehr für neue Transaktionen verwendet, bleiben aber im System erhalten",
|
||||||
|
"istStandard": "Das Standard-Konto wird automatisch vorgeschlagen, wenn für diesen Beteiligten eine Zahlung erfasst wird. Nur ein Konto kann als Standard markiert sein",
|
||||||
|
"beteiligte": "Der Beteiligte, dem diese Bankverbindung zugeordnet ist",
|
||||||
|
"advowareKontoId": "Eindeutige Konto-ID aus Advoware für die Synchronisation. Wird automatisch bei der Synchronisation gesetzt",
|
||||||
|
"advowareLastSync": "Zeitpunkt der letzten erfolgreichen Synchronisation mit Advoware. Wird automatisch aktualisiert",
|
||||||
|
"syncStatus": "Status der Advoware-Synchronisation: 'Synchronisiert' = Daten sind aktuell, 'Abweichungen' = Daten weichen ab, 'Fehlgeschlagen' = Sync-Fehler aufgetreten"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"syncStatus": {
|
||||||
|
"clean": "Synchronisiert",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"calls1": "Anrufe",
|
"calls1": "Anrufe",
|
||||||
"contactsBeteiligte": "Freigegebene Nutzer",
|
"contactsBeteiligte": "Freigegebene Nutzer",
|
||||||
"dokumentesBeteiligte": "Dokumente",
|
"dokumentesBeteiligte": "Dokumente",
|
||||||
|
"bankverbindungens": "Bankverbindungen",
|
||||||
"betnr": "Advoware Identifikator",
|
"betnr": "Advoware Identifikator",
|
||||||
"advowareLastSync": "Advoware letzte Synchronisation",
|
"advowareLastSync": "Advoware letzte Synchronisation",
|
||||||
"syncStatus": "Sync-Status"
|
"syncStatus": "Sync-Status"
|
||||||
@@ -28,7 +29,8 @@
|
|||||||
"adressens": "Adressen",
|
"adressens": "Adressen",
|
||||||
"calls1": "Anrufe",
|
"calls1": "Anrufe",
|
||||||
"contactsBeteiligte": "Freigegebene Nutzer",
|
"contactsBeteiligte": "Freigegebene Nutzer",
|
||||||
"dokumentesBeteiligte": "Dokumente"
|
"dokumentesBeteiligte": "Dokumente",
|
||||||
|
"bankverbindungens": "Bankverbindungen"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"Create CBeteiligte": "Beteiligte erstellen"
|
"Create CBeteiligte": "Beteiligte erstellen"
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
{
|
{
|
||||||
|
"fields": {
|
||||||
|
"user": "Benutzer",
|
||||||
|
"calls1": "Anrufe"
|
||||||
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"calls": "Anrufe",
|
"calls": "Anrufe",
|
||||||
"tasks": "Aufgaben"
|
"tasks": "Aufgaben",
|
||||||
|
"user": "Benutzer",
|
||||||
|
"calls1": "Anrufe"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"Create CCallQueues": "Call-Queue erstellen"
|
"Create CCallQueues": "Call-Queue erstellen"
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
"anschrift": "Anschrift",
|
"anschrift": "Anschrift",
|
||||||
"objekttyp": "Objekttyp",
|
"objekttyp": "Objekttyp",
|
||||||
"lage": "Lage",
|
"lage": "Lage",
|
||||||
"vmhMietverhltnises2Mietobjekt": "Mietverhältnisse",
|
"vmhMietverhltnises2Mietobjekt": "Mietverhältnisse (veraltet)",
|
||||||
|
"vmhMietverhltnises": "Mietverhältnisse",
|
||||||
"contactsMietobjekt": "Freigegebene Nutzer",
|
"contactsMietobjekt": "Freigegebene Nutzer",
|
||||||
"dokumentesMietobjekt": "Dokumente"
|
"dokumentesMietobjekt": "Dokumente"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"vmhMietverhltnises2Mietobjekt": "Mietverhältnisse",
|
"vmhMietverhltnises2Mietobjekt": "Mietverhältnisse (veraltet)",
|
||||||
|
"vmhMietverhltnises": "Mietverhältnisse",
|
||||||
"contactsMietobjekt": "Freigegebene Nutzer",
|
"contactsMietobjekt": "Freigegebene Nutzer",
|
||||||
"dokumentesMietobjekt": "Dokumente"
|
"dokumentesMietobjekt": "Dokumente"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adresse"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"calls": "Anrufe",
|
|
||||||
"tasks": "Aufgaben"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "VMHBeteiligte erstellen"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -59,8 +59,19 @@
|
|||||||
"beendigungstatbestand": "Beendigungstatbestand",
|
"beendigungstatbestand": "Beendigungstatbestand",
|
||||||
"contact": "Kontakt",
|
"contact": "Kontakt",
|
||||||
"nchsterAnruf": "Nächster Anruf",
|
"nchsterAnruf": "Nächster Anruf",
|
||||||
"runWorkflow": "Workflow ausführen",
|
"dokumentesvmherstgespraech": "Dokumente",
|
||||||
"dokumentesvmherstgespraech": "Dokumente"
|
"ustSatz": "USt-Satz",
|
||||||
|
"aussergerichtlicheGebuehren": "Außergerichtliche Gebühren",
|
||||||
|
"kostenRaeumungsantrag": "Kosten Räumungsantrag",
|
||||||
|
"gerichtskosten1Instanz": "GK-Kosten I. Inst.",
|
||||||
|
"anwaltskostenKlaeger1Instanz": "RA-Kosten Kläger I. Inst.",
|
||||||
|
"vorzusch1Instanz": "Vorauszuschießende Kosten I. Inst.",
|
||||||
|
"vergleich1InstanzGk": "Vergleich I. Inst.: GK-Kosten",
|
||||||
|
"vergleich1InstanzAnwK": "Vergleich I. Inst.: RA-Kosten",
|
||||||
|
"vergleich1InstanzSumme": "Vergleich I. Inst.: Summe",
|
||||||
|
"saeumnis1InstanzGk": "Säumnis I. Inst.: GK-Kosten",
|
||||||
|
"saeumnis1InstanzAnwK": "Säumnis I. Inst.: RA-Kosten",
|
||||||
|
"saeumnis1InstanzSumme": "Säumnis I. Inst.: Summe"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"calls": "Anrufe",
|
"calls": "Anrufe",
|
||||||
@@ -123,6 +134,10 @@
|
|||||||
"OPKonto": "Mietkonto / Offene-Posten Liste",
|
"OPKonto": "Mietkonto / Offene-Posten Liste",
|
||||||
"WiderspruchMieter": "Widerspruch des Mieter",
|
"WiderspruchMieter": "Widerspruch des Mieter",
|
||||||
"SonstigeUnterlagen": "Sonstige Unterlagen"
|
"SonstigeUnterlagen": "Sonstige Unterlagen"
|
||||||
|
},
|
||||||
|
"ustSatz": {
|
||||||
|
"0": "0%",
|
||||||
|
"19": "19%"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"contactsMietverhltnis": "Freigegebene Nutzer",
|
"contactsMietverhltnis": "Freigegebene Nutzer",
|
||||||
"sonstigebesitzervmhmietverhltnis": "Sonstige Bewohner",
|
"sonstigebesitzervmhmietverhltnis": "Sonstige Bewohner",
|
||||||
"dokumentesvmhMietverhltnisse": "Dokumente",
|
"dokumentesvmhMietverhltnisse": "Dokumente",
|
||||||
"vmhMietobjekt2Mietverhltnis": "Mietobjekte",
|
"vmhMietobjekt2Mietverhltnis": "Mietobjekte (veraltet)",
|
||||||
"vmhMietobjekt": "Mietobjekt"
|
"vmhMietobjekt": "Mietobjekt"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"contactsMietverhltnis": "Freigegebene Nutzer",
|
"contactsMietverhltnis": "Freigegebene Nutzer",
|
||||||
"sonstigebesitzervmhmietverhltnis": "Sonstige Bewohner",
|
"sonstigebesitzervmhmietverhltnis": "Sonstige Bewohner",
|
||||||
"dokumentesvmhMietverhltnisse": "Dokumente",
|
"dokumentesvmhMietverhltnisse": "Dokumente",
|
||||||
"vmhMietobjekt2Mietverhltnis": "Mietobjekte",
|
"vmhMietobjekt2Mietverhltnis": "Mietobjekte (veraltet)",
|
||||||
"vmhMietobjekt": "Mietobjekt"
|
"vmhMietobjekt": "Mietobjekt"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
"kuendigungsservice": "Kündigungsservice",
|
"kuendigungsservice": "Kündigungsservice",
|
||||||
"aussergerichtlicheGebuehren13": "Außergerichtliche Gebühren 1,3",
|
"aussergerichtlicheGebuehren13": "Außergerichtliche Gebühren 1,3",
|
||||||
"gerichtskosten1Instanz": "Gerichtskosten 1. Instanz",
|
"gerichtskosten1Instanz": "Gerichtskosten 1. Instanz",
|
||||||
"anwaltskosten1Instanz": "Anwaltskosten 1. Instanz"
|
"anwaltskosten1Instanz": "Anwaltskosten 1. Instanz",
|
||||||
|
"freigeschalteteNutzer": "Freigeschaltete Nutzer (veraltet)",
|
||||||
|
"collaborators": "Mitarbeiter",
|
||||||
|
"vmhVermietersRKL": "Vermieter"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"calls": "Anrufe",
|
"calls": "Anrufe",
|
||||||
@@ -24,7 +27,10 @@
|
|||||||
"beklagte": "Beklagte",
|
"beklagte": "Beklagte",
|
||||||
"vmhMietverhltnises": "Mietverhältnisse",
|
"vmhMietverhltnises": "Mietverhältnisse",
|
||||||
"contactsRumungsklage": "Freigegebene Nutzer",
|
"contactsRumungsklage": "Freigegebene Nutzer",
|
||||||
"dokumentesvmhraumungsklage": "Dokumente"
|
"dokumentesvmhraumungsklage": "Dokumente",
|
||||||
|
"freigeschalteteNutzer": "Freigeschaltete Nutzer (veraltet)",
|
||||||
|
"collaborators": "Mitarbeiter",
|
||||||
|
"vmhVermietersRKL": "Vermieter"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"Create CVmhRumungsklage": "Räumungsklage erstellen"
|
"Create CVmhRumungsklage": "Räumungsklage erstellen"
|
||||||
|
|||||||
@@ -1,12 +1,23 @@
|
|||||||
{
|
{
|
||||||
"fields": {
|
"fields": {
|
||||||
"address": "Adresse"
|
"address": "Adresse",
|
||||||
|
"rechtsform": "Rechtsform",
|
||||||
|
"advowareBetnr": "Advoware Beteiligten-Nr.",
|
||||||
|
"vmhRumungsklagesVermieter": "Räumungsklagen",
|
||||||
|
"contactsVermieter": "Freigegebene Nutzer",
|
||||||
|
"vmhKontaktpersonenVermieter": "Kontaktpersonen"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"calls": "Anrufe",
|
"calls": "Anrufe",
|
||||||
"tasks": "Aufgaben"
|
"tasks": "Aufgaben",
|
||||||
|
"vmhRumungsklagesVermieter": "Räumungsklagen",
|
||||||
|
"contactsVermieter": "Freigegebene Nutzer",
|
||||||
|
"vmhKontaktpersonenVermieter": "Kontaktpersonen"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"Create CVmhVermieter": "Vermieter erstellen"
|
"Create CVmhVermieter": "Vermieter erstellen"
|
||||||
|
},
|
||||||
|
"tooltips": {
|
||||||
|
"advowareBetnr": "Eindeutige Beteiligten-Nummer aus Advoware"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
41
custom/Espo/Custom/Resources/i18n/de_DE/Call.json
Normal file
41
custom/Espo/Custom/Resources/i18n/de_DE/Call.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"cWichtigkeit": {
|
||||||
|
"Standard": "Standard",
|
||||||
|
"Erhöht": "Erhöht",
|
||||||
|
"Hoch": "Hoch",
|
||||||
|
"Dringend": "Dringend"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"Planned": "Geplant",
|
||||||
|
"Held": "Erfolgreich",
|
||||||
|
"Not Held": "Abgesagt",
|
||||||
|
"TempNotReached": "Vorübergehend nicht erreicht",
|
||||||
|
"FinalNotReached": "Dauerhaft nicht erreicht"
|
||||||
|
},
|
||||||
|
"direction": {
|
||||||
|
"Outbound": "Ausgehend",
|
||||||
|
"Inbound": "Eingehend",
|
||||||
|
"Internal": "Intern"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"cWichtigkeit": "Wichtigkeit",
|
||||||
|
"cBeteiligtes": "Beteiligte",
|
||||||
|
"cCallQueues": "Call-Queue",
|
||||||
|
"user": "Benutzer",
|
||||||
|
"calls1": "Anrufe"
|
||||||
|
},
|
||||||
|
"tooltips": {
|
||||||
|
"cWichtigkeit": "Wichtigkeit des Anrufes aus Sicht der Kanzlei"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"Create Call": "Anruf erstellen"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"cBeteiligtes": "Beteiligte",
|
||||||
|
"cCallQueues": "Call-Queue",
|
||||||
|
"user": "Benutzer",
|
||||||
|
"calls1": "Anrufe"
|
||||||
|
}
|
||||||
|
}
|
||||||
58
custom/Espo/Custom/Resources/i18n/de_DE/Contact.json
Normal file
58
custom/Espo/Custom/Resources/i18n/de_DE/Contact.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"cRechtsform": "Rechtsform",
|
||||||
|
"cVmhRumungsklages": "Räumungsklagen",
|
||||||
|
"cDISGTyp": "Persönlichkeitstyp (nach DISG)",
|
||||||
|
"cVmhErstgespraechs": "Erstgespräch",
|
||||||
|
"cVmhVermietersFreigabe": "Vermieter (Freigabe)",
|
||||||
|
"cVmhVermietersKontaktpersonen": "Vermieter (Kontaktpersonen)",
|
||||||
|
"cVmhMietverhltnisesContact": "Mietverhältnisse",
|
||||||
|
"cDokumentesvmhcontact": "Dokumente",
|
||||||
|
"cVmhmietobjekt2contact": "Mietobjekte",
|
||||||
|
"cBeteiligteContact": "Beteiligte",
|
||||||
|
"cMietobjekteContactPortal": "Mietobjekte (Portal)",
|
||||||
|
"cAdressenContact": "Adressen",
|
||||||
|
"cVmhRumungsklageContact": "Räumungsklagen (Portal)",
|
||||||
|
"cBankverbindungenContact": "Bankverbindungen"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"cVmhRumungsklages": "Räumungsklagen",
|
||||||
|
"cVmhErstgespraechs": "Erstgespräch",
|
||||||
|
"cVmhVermietersFreigabe": "Vermieter (Freigabe)",
|
||||||
|
"cVmhVermietersKontaktpersonen": "Vermieter (Kontaktpersonen)",
|
||||||
|
"cVmhMietverhltnisesContact": "Mietverhältnisse",
|
||||||
|
"cDokumentesvmhcontact": "Dokumente",
|
||||||
|
"cVmhmietobjekt2contact": "Mietobjekte",
|
||||||
|
"cBeteiligteContact": "Beteiligte",
|
||||||
|
"cMietobjekteContactPortal": "Mietobjekte (Portal)",
|
||||||
|
"cAdressenContact": "Adressen",
|
||||||
|
"cVmhRumungsklageContact": "Räumungsklagen (Portal)",
|
||||||
|
"cBankverbindungenContact": "Bankverbindungen"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cRechtsform": {
|
||||||
|
"": "",
|
||||||
|
"Herr": "Herr",
|
||||||
|
"Frau": "Frau",
|
||||||
|
"GmbH": "GmbH"
|
||||||
|
},
|
||||||
|
"cDISGTyp": {
|
||||||
|
"Dominant": "Dominant",
|
||||||
|
"Initiativ": "Initiativ",
|
||||||
|
"Stetig": "Stetig",
|
||||||
|
"Gewissenhaft": "Gewissenhaft",
|
||||||
|
"Unbekannt": "Unbekannt"
|
||||||
|
},
|
||||||
|
"salutationName": {
|
||||||
|
"": "",
|
||||||
|
"Mr.": "Herr",
|
||||||
|
"Ms.": "Frau"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tooltips": {
|
||||||
|
"cDISGTyp": "Persönlichkeitstyp nach DISG:\n\nDominant = Schnelles Tempo, fordernder Ton, Fokus auf Ergebnisse.\nInitiativ = Hohe Sprechgeschwindigkeit, emotionale Sprache, sucht Bestätigung.\nStetig = Langsames Tempo, zögernde Pausen, risikoscheu.\nGewissenhaft = Präzise Formulierungen, sucht Daten, skeptisch."
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"Create Contact": "Portalnutzer erstellen"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
custom/Espo/Custom/Resources/i18n/de_DE/PhoneNumber.json
Normal file
8
custom/Espo/Custom/Resources/i18n/de_DE/PhoneNumber.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"advoware_tlf_id": "Advoware Telefon-ID"
|
||||||
|
},
|
||||||
|
"tooltips": {
|
||||||
|
"advoware_tlf_id": "Eindeutige Telefonnummer-ID aus dem Advoware-System"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
custom/Espo/Custom/Resources/i18n/de_DE/User.json
Normal file
8
custom/Espo/Custom/Resources/i18n/de_DE/User.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"cCallQueues": "Persönliche Warteschleife"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"cCallQueues": "Persönliche Warteschleife"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"presetFilters": {
|
||||||
|
"reportFilter6972174b6540731c1": "UserTask"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"name": "Name",
|
||||||
|
"iban": "IBAN",
|
||||||
|
"bic": "BIC/SWIFT",
|
||||||
|
"kontoinhaber": "Account Holder",
|
||||||
|
"bankname": "Bank Name",
|
||||||
|
"istAktiv": "Is Active",
|
||||||
|
"istStandard": "Default Account",
|
||||||
|
"advowareKontoId": "Advoware Account ID",
|
||||||
|
"advowareLastSync": "Advoware Last Sync",
|
||||||
|
"syncStatus": "Sync Status",
|
||||||
|
"beteiligte": "Participant"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"beteiligte": "Participant"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Create Bank Account"
|
||||||
|
},
|
||||||
|
"tooltips": {
|
||||||
|
"name": "Name or description of the bank account (e.g. 'Main Account', 'Business Account', 'Deposit Account')",
|
||||||
|
"iban": "International Bank Account Number in format DE89370400440532013000. Only uppercase letters and digits, 2-letter country code followed by check digit and account number (max. 34 characters)",
|
||||||
|
"bic": "Bank Identifier Code (SWIFT code) in format COBADEFFXXX. 8 or 11 characters: 4 characters bank code, 2 characters country code, 2 characters location code, optionally 3 characters branch code",
|
||||||
|
"kontoinhaber": "Full name of the account holder as registered with the bank",
|
||||||
|
"bankname": "Name of the bank (e.g. 'Sparkasse Cologne Bonn', 'Deutsche Bank')",
|
||||||
|
"istAktiv": "Inactive bank accounts are no longer used for new transactions but remain in the system",
|
||||||
|
"istStandard": "The default account is automatically suggested when a payment is recorded for this participant. Only one account can be marked as default",
|
||||||
|
"beteiligte": "The participant to whom this bank account belongs",
|
||||||
|
"advowareKontoId": "Unique account ID from Advoware for synchronization. Automatically set during synchronization",
|
||||||
|
"advowareLastSync": "Time of last successful synchronization with Advoware. Automatically updated",
|
||||||
|
"syncStatus": "Advoware synchronization status: 'Synchronized' = data is current, 'Discrepancies' = data differs, 'Failed' = sync error occurred"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"syncStatus": {
|
||||||
|
"clean": "Synchronized",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
"anschriftPostalCode": "Postal Code",
|
"anschriftPostalCode": "Postal Code",
|
||||||
"anschriftMap": "Map",
|
"anschriftMap": "Map",
|
||||||
"objekttyp": "Property Type",
|
"objekttyp": "Property Type",
|
||||||
|
"lage": "Location",
|
||||||
"vmhMietverhltnises2Mietobjekt": "Tenancies",
|
"vmhMietverhltnises2Mietobjekt": "Tenancies",
|
||||||
"contact2mietobjekt": "Contacts",
|
"contact2mietobjekt": "Contacts",
|
||||||
"contactsMietobjekt": "Portal Users",
|
"contactsMietobjekt": "Portal Users",
|
||||||
@@ -35,5 +36,8 @@
|
|||||||
"Gewerbehalle": "Gewerbehalle",
|
"Gewerbehalle": "Gewerbehalle",
|
||||||
"Sonstiges": "Sonstiges"
|
"Sonstiges": "Sonstiges"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"tooltips": {
|
||||||
|
"lage": "Location within the property (e.g. ground floor left, 1st floor right)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Address"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Meetings",
|
|
||||||
"calls": "Calls",
|
|
||||||
"tasks": "Tasks"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Create VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -60,8 +60,9 @@
|
|||||||
"contact": "Contact",
|
"contact": "Contact",
|
||||||
"nchsterAnruf": "Next Call",
|
"nchsterAnruf": "Next Call",
|
||||||
"dokumentesvmherstgespraech": "Documents",
|
"dokumentesvmherstgespraech": "Documents",
|
||||||
"runWorkflow": "Run Workflow",
|
"testArray": "Test Array",
|
||||||
"testArray": "Test Array"
|
"vorzusch1Instanz": "Vorauszuschießende Kosten I. Inst.",
|
||||||
|
"kostenRaeumungstitel": "Kosten Räumungsantrag"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"meetings": "Meetings",
|
"meetings": "Meetings",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"Call": "Anruf",
|
"Call": "Anruf",
|
||||||
"Contact": "Portalnutzer",
|
"Contact": "Portalnutzer",
|
||||||
"CCallQueues": "Call-Queue",
|
"CCallQueues": "Call-Queue",
|
||||||
"CVMHBeteiligte": "VMHBeteiligte"
|
"CBankverbindungen": "Bankverbindung"
|
||||||
},
|
},
|
||||||
"scopeNamesPlural": {
|
"scopeNamesPlural": {
|
||||||
"CVmhMietverhltnis": "Mietverhältnisse",
|
"CVmhMietverhltnis": "Mietverhältnisse",
|
||||||
@@ -25,6 +25,6 @@
|
|||||||
"Call": "Anrufe",
|
"Call": "Anrufe",
|
||||||
"Contact": "Portalnutzer",
|
"Contact": "Portalnutzer",
|
||||||
"CCallQueues": "Call-Queues",
|
"CCallQueues": "Call-Queues",
|
||||||
"CVMHBeteiligte": "VMHBeteiligtes"
|
"CBankverbindungen": "Bankverbindungen"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
8
custom/Espo/Custom/Resources/i18n/en_US/PhoneNumber.json
Normal file
8
custom/Espo/Custom/Resources/i18n/en_US/PhoneNumber.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"fields": {
|
||||||
|
"advoware_tlf_id": "Advoware Phone ID"
|
||||||
|
},
|
||||||
|
"tooltips": {
|
||||||
|
"advoware_tlf_id": "Unique phone number ID from the Advoware system"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Crear Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Dirección"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Reuniones",
|
|
||||||
"calls": "Llamadas",
|
|
||||||
"tasks": "Tareas"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Crear VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Crear Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Dirección"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Presentaciones",
|
|
||||||
"calls": "Llamadas",
|
|
||||||
"tasks": "Tareas"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Crear VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "ایجاد Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "آدرس"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "جلسات",
|
|
||||||
"calls": "تماس ها",
|
|
||||||
"tasks": "وظایف"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "ایجاد VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Créer un Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Créer un VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Napravi Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adresa"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Sastanci",
|
|
||||||
"calls": "Pozivi",
|
|
||||||
"tasks": "Zadaci"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Kreiraj VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "{EntityTypeTranslated} létrehozása"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Cím"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "találkozók",
|
|
||||||
"calls": "felhívja",
|
|
||||||
"tasks": "Feladatok"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "{EntityTypeTranslated} létrehozása"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Buat Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Buat VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Crea Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Indirizzo"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Riunioni",
|
|
||||||
"calls": "Chiamate",
|
|
||||||
"tasks": "Compiti"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Crea VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Bankverbindung を作成する"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "住所"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "会議",
|
|
||||||
"calls": "通話",
|
|
||||||
"tasks": "タスク"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "VMHBeteiligte を作成する"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Sukurti Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adresas"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Susitikimai",
|
|
||||||
"calls": "Skambučiai",
|
|
||||||
"tasks": "Užduotys"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Sukurti VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Izveidot Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adrese"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Tikšanās",
|
|
||||||
"calls": "Zvani",
|
|
||||||
"tasks": "Uzdevumi"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Izveidot VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Opprett Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adresse"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Møter",
|
|
||||||
"calls": "Samtaler",
|
|
||||||
"tasks": "Oppgaver"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Opprett VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Creëer Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adres"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Vergaderingen",
|
|
||||||
"calls": "Gesprekken",
|
|
||||||
"tasks": "Taken"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Creëer VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Utwórz Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adres"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Spotkania",
|
|
||||||
"calls": "Rozmowy",
|
|
||||||
"tasks": "Zadania"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Utwórz VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Criar Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Endereço"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Reuniões",
|
|
||||||
"calls": "Ligações",
|
|
||||||
"tasks": "Tarefas"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Criar VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Criar Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Endereço"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Reuniões",
|
|
||||||
"calls": "Chamadas",
|
|
||||||
"tasks": "Tarefas"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Criar VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Creare Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Creare VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Создать Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Адрес"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Встречи",
|
|
||||||
"calls": "Звонки",
|
|
||||||
"tasks": "Задачи"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Создать VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Vytvoriť Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adresa"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Stretnutia",
|
|
||||||
"calls": "Hovory",
|
|
||||||
"tasks": "Úlohy"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Vytvoriť VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Ustvari Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Naslov"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Srečanja",
|
|
||||||
"calls": "Klici",
|
|
||||||
"tasks": "Naloge"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Ustvari VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Napravi Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adresa"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Ročišta",
|
|
||||||
"calls": "Pozivi",
|
|
||||||
"tasks": "Zadaci"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Napravi VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Skapa Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adress"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Möten",
|
|
||||||
"calls": "Samtal",
|
|
||||||
"tasks": "Uppgifter"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Skapa VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "สร้าง Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "ที่อยู่"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "การประชุม",
|
|
||||||
"calls": "โทร",
|
|
||||||
"tasks": "งาน"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "สร้าง VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Bankverbindung oluştur"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Adres "
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Toplantılar",
|
|
||||||
"calls": "(Seslenme)",
|
|
||||||
"tasks": "Görevler"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "VMHBeteiligte oluştur"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Створити Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Адреса"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Зустрічі",
|
|
||||||
"calls": "Дзвінки",
|
|
||||||
"tasks": "Завдання"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "Створити VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "Tạo Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "Địa chỉ"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "Cuộc hẹn",
|
|
||||||
"calls": "Cuộc gọi",
|
|
||||||
"tasks": "Nhiệm vụ"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "创建 Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "地址"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "会晤",
|
|
||||||
"calls": "通话",
|
|
||||||
"tasks": "任务"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "创建 VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"labels": {
|
||||||
|
"Create CBankverbindungen": "建立Bankverbindung"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"fields": {
|
|
||||||
"address": "地址"
|
|
||||||
},
|
|
||||||
"links": {
|
|
||||||
"meetings": "會議",
|
|
||||||
"calls": "通話",
|
|
||||||
"tasks": "任務"
|
|
||||||
},
|
|
||||||
"labels": {
|
|
||||||
"Create CVMHBeteiligte": "建立VMHBeteiligte"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"label": "Übersicht",
|
||||||
|
"rows": [
|
||||||
|
[
|
||||||
|
{"name": "name"},
|
||||||
|
{"name": "beteiligte"}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"name": "istAktiv"},
|
||||||
|
{"name": "istStandard"}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Bankdaten",
|
||||||
|
"rows": [
|
||||||
|
[
|
||||||
|
{"name": "iban"},
|
||||||
|
{"name": "bic"}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"name": "kontoinhaber"},
|
||||||
|
{"name": "bankname"}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Advoware Sync",
|
||||||
|
"tabBreak": true,
|
||||||
|
"tabLabel": "Erweitert",
|
||||||
|
"rows": [
|
||||||
|
[
|
||||||
|
{"name": "advowareKontoId"},
|
||||||
|
{"name": "syncStatus"},
|
||||||
|
{"name": "advowareLastSync"}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -5,28 +5,28 @@
|
|||||||
{
|
{
|
||||||
"name": "name"
|
"name": "name"
|
||||||
},
|
},
|
||||||
false
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
{
|
||||||
"name": "emailAddress"
|
"name": "istAktiv"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "phoneNumber"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "address"
|
"name": "iban"
|
||||||
},
|
},
|
||||||
false
|
{
|
||||||
|
"name": "bic"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "description",
|
"name": "bankname"
|
||||||
"fullWidth": true
|
},
|
||||||
|
{
|
||||||
|
"name": "istStandard"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
],
|
||||||
|
"style": "default",
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"link": true,
|
||||||
|
"width": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "beteiligte",
|
||||||
|
"width": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "iban",
|
||||||
|
"width": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bankname",
|
||||||
|
"width": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "istAktiv",
|
||||||
|
"width": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "istStandard",
|
||||||
|
"width": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "syncStatus",
|
||||||
|
"width": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user