Compare commits

..

15 Commits

Author SHA1 Message Date
56271ca05a Add 'kostenRaeumungsantrag' field and update related calculations and localization in CVmhErstgespraech entity 2026-01-23 20:14:43 +01:00
42d396f460 Add RVG calculation module and integrate cost calculations into CVmhErstgespraech entity 2026-01-23 19:45:00 +01:00
cf60d2a91d Add warmmiete and streitwert calculations; enhance check_and_rebuild script for cache clearing 2026-01-23 17:53:41 +01:00
e1a7158931 Add IBAN and BIC validation with custom hooks; update localization messages and cache timestamps 2026-01-23 16:20:26 +01:00
15ecc7068f Refactor CBankverbindungen entity: remove IBAN validation formula and update metadata; adjust cache timestamps 2026-01-23 16:00:16 +01:00
ac58b51452 Add CBankverbindungen entity with multilingual support, tooltips, and layout definitions 2026-01-23 15:51:42 +01:00
185524e432 Add CBankverbindungen entity with multilingual support and metadata definitions 2026-01-23 15:15:29 +01:00
99045d55d2 Add report integration for BpmnUserTask with filters and panels; update cache timestamps 2026-01-22 13:40:14 +01:00
c9e5846110 Remove backup workflow definition for vmh-erstberatung-abschließen to streamline workflow management 2026-01-21 00:11:29 +01:00
37e158c806 Enhance workflow manager and definitions with category support for better organization 2026-01-21 00:01:51 +01:00
8c83e54650 Enhance documentation and workflow management in EspoCRM
- Update README.md to include a table of contents and detailed sections on workflow management and custom scripts.
- Remove deprecated 'runWorkflow' field from CVmhErstgespraech localization files.
- Add 'runWorkflow' field to detail layout for CVmhErstgespraech.
- Update workflow_manager.php to improve workflow listing and management functionality.
- Adjust cache timestamps in config.php.
- Create CUSTOM_DIRECTORY.md to outline the custom directory structure and best practices.
- Add README.md for workflow definitions with usage examples and JSON format specifications.
- Introduce new workflow definitions for 'vmh-erstberatung-abschließen' and its backup.
2026-01-20 23:58:29 +01:00
e878125489 Update labels for Mietverhältnisse in CMietobjekt.json to clarify terminology 2026-01-20 22:56:02 +01:00
06326d4d0b Add new entity definitions and fields for CVMHBeteiligte, update existing metadata for CBeteiligte, CDokumente, CMietobjekt, CVmhErstgespraech, CVmhMietverhltnis, CVmhRumungsklage, CVmhVermieter, and Contact; adjust cache timestamps in config.php 2026-01-20 22:55:28 +01:00
96becef2ba Refactor localization and metadata for CVMHBeteiligte
- Added "Location" field and tooltip to CMietobjekt localization.
- Removed CVMHBeteiligte localization files in multiple languages (es_ES, es_MX, fa_IR, fr_FR, hr_HR, hu_HU, id_ID, it_IT, ja_JP, lt_LT, lv_LV, nb_NO, nl_NL, pl_PL, pt_BR, pt_PT, ro_RO, ru_RU, sk_SK, sl_SI, sr_RS, sv_SE, th_TH, tr_TR, uk_UA, vi_VN, zh_CN, zh_TW).
- Deleted CVMHBeteiligte layout definitions and metadata.
- Updated Call, Contact, PhoneNumber, and User localization files in German and English.
- Removed references to CVMHBeteiligte in various entity definitions and metadata.
- Updated configuration file with new cache timestamp.
2026-01-20 22:43:39 +01:00
5750c4486e Update permissions correction logic in check_and_rebuild.sh; adjust cache timestamps in config.php; add listSmall.json layout for CVmhRumungsklage 2026-01-20 22:32:32 +01:00
134 changed files with 2982 additions and 690 deletions

View File

@@ -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
View File

@@ -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:

View 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
};
}
};
});

View File

@@ -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;
}
});
});

View File

@@ -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;
}
});
});

View File

@@ -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;
}
});
});

View 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
View 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

View File

@@ -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;
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Espo\Custom\Controllers;
class CBankverbindungen extends \Espo\Core\Templates\Controllers\Base
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace Espo\Custom\Controllers;
class CVMHBeteiligte extends \Espo\Core\Templates\Controllers\Person
{
}

View File

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

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "إنشاء {الكيانTypeTranslated}"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "العنوان"
},
"links": {
"meetings": "الاجتماعات",
"calls": "المكالمات",
"tasks": "مهام"
},
"labels": {
"Create CVMHBeteiligte": "إنشاء {الكيانTypeTranslated}"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Създаване на Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Адрес"
},
"links": {
"meetings": "Срещи",
"calls": "Разговори",
"tasks": "Задачи"
},
"labels": {
"Create CVMHBeteiligte": "Създаване на VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Vytvořit Bankverbindung"
}
}

View File

@@ -1,5 +0,0 @@
{
"labels": {
"Create CVMHBeteiligte": "Vytvořit VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Opret Bankverbindung "
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adresse"
},
"links": {
"meetings": "Møder",
"calls": "Opkald",
"tasks": "Opgaver"
},
"labels": {
"Create CVMHBeteiligte": "Opret VMHBeteiligte"
}
}

View File

@@ -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"
}
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"
}, },

View File

@@ -1,12 +0,0 @@
{
"fields": {
"address": "Adresse"
},
"links": {
"calls": "Anrufe",
"tasks": "Aufgaben"
},
"labels": {
"Create CVMHBeteiligte": "VMHBeteiligte erstellen"
}
}

View File

@@ -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%"
} }
} }
} }

View File

@@ -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": {

View File

@@ -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"

View File

@@ -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"
} }
} }

View 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"
}
}

View 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"
}
}

View File

@@ -0,0 +1,8 @@
{
"fields": {
"advoware_tlf_id": "Advoware Telefon-ID"
},
"tooltips": {
"advoware_tlf_id": "Eindeutige Telefonnummer-ID aus dem Advoware-System"
}
}

View File

@@ -0,0 +1,8 @@
{
"fields": {
"cCallQueues": "Persönliche Warteschleife"
},
"links": {
"cCallQueues": "Persönliche Warteschleife"
}
}

View File

@@ -0,0 +1,5 @@
{
"presetFilters": {
"reportFilter6972174b6540731c1": "UserTask"
}
}

View File

@@ -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"
}
}

View File

@@ -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)"
} }
} }

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Address"
},
"links": {
"meetings": "Meetings",
"calls": "Calls",
"tasks": "Tasks"
},
"labels": {
"Create CVMHBeteiligte": "Create VMHBeteiligte"
}
}

View File

@@ -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",

View File

@@ -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"
} }
} }

View File

@@ -0,0 +1,8 @@
{
"fields": {
"advoware_tlf_id": "Advoware Phone ID"
},
"tooltips": {
"advoware_tlf_id": "Unique phone number ID from the Advoware system"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Crear Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Dirección"
},
"links": {
"meetings": "Reuniones",
"calls": "Llamadas",
"tasks": "Tareas"
},
"labels": {
"Create CVMHBeteiligte": "Crear VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Crear Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Dirección"
},
"links": {
"meetings": "Presentaciones",
"calls": "Llamadas",
"tasks": "Tareas"
},
"labels": {
"Create CVMHBeteiligte": "Crear VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "ایجاد Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "آدرس"
},
"links": {
"meetings": "جلسات",
"calls": "تماس ها",
"tasks": "وظایف"
},
"labels": {
"Create CVMHBeteiligte": "ایجاد VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Créer un Bankverbindung"
}
}

View File

@@ -1,5 +0,0 @@
{
"labels": {
"Create CVMHBeteiligte": "Créer un VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Napravi Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adresa"
},
"links": {
"meetings": "Sastanci",
"calls": "Pozivi",
"tasks": "Zadaci"
},
"labels": {
"Create CVMHBeteiligte": "Kreiraj VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "{EntityTypeTranslated} létrehozása"
}
}

View File

@@ -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"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Buat Bankverbindung"
}
}

View File

@@ -1,5 +0,0 @@
{
"labels": {
"Create CVMHBeteiligte": "Buat VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Crea Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Indirizzo"
},
"links": {
"meetings": "Riunioni",
"calls": "Chiamate",
"tasks": "Compiti"
},
"labels": {
"Create CVMHBeteiligte": "Crea VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Bankverbindung を作成する"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "住所"
},
"links": {
"meetings": "会議",
"calls": "通話",
"tasks": "タスク"
},
"labels": {
"Create CVMHBeteiligte": "VMHBeteiligte を作成する"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Sukurti Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adresas"
},
"links": {
"meetings": "Susitikimai",
"calls": "Skambučiai",
"tasks": "Užduotys"
},
"labels": {
"Create CVMHBeteiligte": "Sukurti VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Izveidot Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adrese"
},
"links": {
"meetings": "Tikšanās",
"calls": "Zvani",
"tasks": "Uzdevumi"
},
"labels": {
"Create CVMHBeteiligte": "Izveidot VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Opprett Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adresse"
},
"links": {
"meetings": "Møter",
"calls": "Samtaler",
"tasks": "Oppgaver"
},
"labels": {
"Create CVMHBeteiligte": "Opprett VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Creëer Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adres"
},
"links": {
"meetings": "Vergaderingen",
"calls": "Gesprekken",
"tasks": "Taken"
},
"labels": {
"Create CVMHBeteiligte": "Creëer VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Utwórz Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adres"
},
"links": {
"meetings": "Spotkania",
"calls": "Rozmowy",
"tasks": "Zadania"
},
"labels": {
"Create CVMHBeteiligte": "Utwórz VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Criar Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Endereço"
},
"links": {
"meetings": "Reuniões",
"calls": "Ligações",
"tasks": "Tarefas"
},
"labels": {
"Create CVMHBeteiligte": "Criar VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Criar Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Endereço"
},
"links": {
"meetings": "Reuniões",
"calls": "Chamadas",
"tasks": "Tarefas"
},
"labels": {
"Create CVMHBeteiligte": "Criar VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Creare Bankverbindung"
}
}

View File

@@ -1,5 +0,0 @@
{
"labels": {
"Create CVMHBeteiligte": "Creare VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Создать Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Адрес"
},
"links": {
"meetings": "Встречи",
"calls": "Звонки",
"tasks": "Задачи"
},
"labels": {
"Create CVMHBeteiligte": "Создать VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Vytvoriť Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adresa"
},
"links": {
"meetings": "Stretnutia",
"calls": "Hovory",
"tasks": "Úlohy"
},
"labels": {
"Create CVMHBeteiligte": "Vytvoriť VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Ustvari Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Naslov"
},
"links": {
"meetings": "Srečanja",
"calls": "Klici",
"tasks": "Naloge"
},
"labels": {
"Create CVMHBeteiligte": "Ustvari VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Napravi Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adresa"
},
"links": {
"meetings": "Ročišta",
"calls": "Pozivi",
"tasks": "Zadaci"
},
"labels": {
"Create CVMHBeteiligte": "Napravi VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Skapa Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adress"
},
"links": {
"meetings": "Möten",
"calls": "Samtal",
"tasks": "Uppgifter"
},
"labels": {
"Create CVMHBeteiligte": "Skapa VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "สร้าง Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "ที่อยู่"
},
"links": {
"meetings": "การประชุม",
"calls": "โทร",
"tasks": "งาน"
},
"labels": {
"Create CVMHBeteiligte": "สร้าง VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Bankverbindung oluştur"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Adres "
},
"links": {
"meetings": "Toplantılar",
"calls": "(Seslenme)",
"tasks": "Görevler"
},
"labels": {
"Create CVMHBeteiligte": "VMHBeteiligte oluştur"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Створити Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "Адреса"
},
"links": {
"meetings": "Зустрічі",
"calls": "Дзвінки",
"tasks": "Завдання"
},
"labels": {
"Create CVMHBeteiligte": "Створити VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "Tạo Bankverbindung"
}
}

View File

@@ -1,10 +0,0 @@
{
"fields": {
"address": "Địa chỉ"
},
"links": {
"meetings": "Cuộc hẹn",
"calls": "Cuộc gọi",
"tasks": "Nhiệm vụ"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "创建 Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "地址"
},
"links": {
"meetings": "会晤",
"calls": "通话",
"tasks": "任务"
},
"labels": {
"Create CVMHBeteiligte": "创建 VMHBeteiligte"
}
}

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create CBankverbindungen": "建立Bankverbindung"
}
}

View File

@@ -1,13 +0,0 @@
{
"fields": {
"address": "地址"
},
"links": {
"meetings": "會議",
"calls": "通話",
"tasks": "任務"
},
"labels": {
"Create CVMHBeteiligte": "建立VMHBeteiligte"
}
}

View File

@@ -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"}
]
]
}
]

View File

@@ -1,32 +1,32 @@
[ [
{ {
"rows": [ "rows": [
[ [
{ {
"name": "name" "name": "name"
}, },
false {
], "name": "istAktiv"
[ }
{ ],
"name": "emailAddress" [
}, {
{ "name": "iban"
"name": "phoneNumber" },
} {
], "name": "bic"
[ }
{ ],
"name": "address" [
}, {
false "name": "bankname"
], },
[ {
{ "name": "istStandard"
"name": "description", }
"fullWidth": true ]
} ],
] "style": "default",
] "label": ""
} }
] ]

View File

@@ -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