diff --git a/README.md b/README.md index d9d47565..b335655d 100644 --- a/README.md +++ b/README.md @@ -1117,4 +1117,166 @@ Um Entitäten für Portalnutzer (Contact-Entität) freizugeben, wurde ein konsis - `selectPrimaryFilterName: "portalUsers"` filtert automatisch auf Portal-User - Tab "Freigabe für" sollte immer der erste Tab im Bottom-Panel sein (index: 0) - Style "warning" hebt das Panel visuell hervor -- Nach Änderungen immer Rebuild durchführen und beide Seiten der Relationship definieren \ No newline at end of file +- Nach Änderungen immer Rebuild durchführen und beide Seiten der Relationship definieren + +--- + +## Custom JavaScript & CSS Integration + +### JavaScript-Module einbinden + +EspoCRM verwendet AMD/RequireJS für JavaScript-Module. Custom JavaScript-Dateien werden in `client/custom/src/` abgelegt. + +**Beispiel: RVG-Gebührenrechner für CVmhErstgespraech** + +**1. Modul erstellen** (`client/custom/src/modules/rvg-calculator.js`): +```javascript +define('custom:modules/rvg-calculator', [], function () { + return { + kalkuliereKosten: function(streitwert, anzahlKlaeger, anzahlBeklagte, ustProzent) { + // Berechnungslogik + return { /* Ergebnisobjekt */ }; + } + }; +}); +``` + +**2. Custom Field View erstellen** (`client/custom/src/views/{entity}/fields/{fieldname}.js`): +```javascript +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.listenTo(this.model, 'change:streitwert change:anzahlVermieter', this.calculate); + this.listenTo(this.model, 'sync', this.calculate); // Initial load + }, + calculate: function () { + var result = RvgCalculator.kalkuliereKosten(/*...*/); + this.model.set('kostenRaeumungsantrag', result.kostenRaeumungsantrag); + } + }); +}); +``` + +**3. In entityDefs registrieren**: +```json +{ + "fields": { + "vergleich1InstanzGk": { + "type": "currency", + "readOnly": true, + "view": "custom:views/c-vmh-erstgespraech/fields/rvg-calculated" + } + } +} +``` + +**Wichtige Patterns:** +- `listenTo(model, 'sync', callback)` - Für initiale Berechnung beim Laden +- `listenTo(model, 'change:field1 change:field2', callback)` - Für Reaktivität +- `calculating` Flag verhindert Rekursion bei `model.set()` +- Browser-Cache: Hard Refresh (Ctrl+Shift+R) nach JS-Änderungen erforderlich + +### CSS-Manipulation & Feld-Hervorhebung + +EspoCRM erlaubt Custom CSS über Metadata-Registrierung. + +**1. CSS-Datei erstellen** (`client/custom/css/erstgespraech-highlight.css`): +```css +/* Feld-Selektor über data-name Attribut */ +.detail .cell[data-name="vorzusch1Instanz"] { + background-color: #d4edda; + padding: 10px; + border-bottom: 4px solid #28a745; + border-radius: 4px; +} + +.detail .cell[data-name="vorzusch1Instanz"] .numeric-text { + font-weight: bold; + color: #155724; + font-size: 1.1em; +} +``` + +**2. CSS in Metadata registrieren** (`custom/Espo/Custom/Resources/metadata/app/client.json`): +```json +{ + "cssList": [ + "__APPEND__", + "client/custom/css/erstgespraech-highlight.css" + ] +} +``` + +**3. Rebuild durchführen** - CSS wird in gecachtes Bundle integriert + +**CSS-Targeting-Strategien:** +- **Feld-spezifisch:** `.cell[data-name="fieldName"]` +- **Entity-spezifisch:** `body[data-controller="CVmhErstgespraech"]` +- **View-spezifisch:** `.detail` (Detail-View), `.edit` (Edit-View), `.list` (List-View) +- **Label vs. Value:** + - `.label-text` - Feldlabel + - `.numeric-text` / `.text-default` - Feldwert + - `.field[data-name="..."]` - Field-Container + +**HTML-Struktur (Referenz):** +```html +
+ +
+ 3.067,63 € +
+
+``` + +**Best Practices:** +- CSS-Dateien in `client/custom/css/` oder `client/custom/modules/{module}/css/` ablegen +- `__APPEND__` verwendet um Core-CSS zu erweitern, nicht zu überschreiben +- Spezifische Selektoren verwenden um Kollisionen zu vermeiden +- Nach CSS-Änderungen: Rebuild + Hard Refresh (Browser Cache löschen) + +### RVG-Gebührenrechner (CVmhErstgespraech) + +**Implementierung:** Automatische Berechnung von Anwalts- und Gerichtskosten nach RVG 2025 / GKG + +**Komponenten:** +1. **Calculator-Modul** (`client/custom/src/modules/rvg-calculator.js`): + - `getWertgebuehr()`: RVG 2025 Tabelle (65 Stufen, €500-€2M) + - `getGerichtsgebuehr()`: GKG progressive Berechnung + - `getZuschlag()`: §7 RVG Personenzuschlag (+0.3 pro Person, max +2.0) + - `kalkuliereKosten()`: Hauptfunktion für alle Szenarien + +2. **Custom Field Views**: + - `rvg-calculated.js`: Trigger für alle Berechnungen + - `beruecksichtigte-personen.js`: Live-Text-Anzeige "X Vermieter, Y Mieter, Z Dritte" + - `warmmiete.js`: Kaltmiete + BK-Vorauszahlung + BK-Pauschale + - `streitwert.js`: (Kaltmiete + BK-Pauschale) × 12 + +3. **Berechnete Felder** (readOnly currency fields): + - Außergerichtliche Gebühren: 1.3 + Zuschlag + Pauschale 20% (max 20€) + - Kosten Räumungsantrag: 0.3 + 0.3/Person + Pauschale + - 1. Instanz: 3.0 GK + RA-Kosten (1.3 Verf + 1.2 Term + Pauschale) + - Säumnisszenario: 3.0 GK + reduzierte RA (0.5 Term statt 1.2) + - Vergleichsszenario: 1.0 GK + RA (1.3 Verf + 1.2 Term + 1.0 Vergl) + +4. **USt-Satz Handling**: + - Enum Field: "0" / "19" (String, nicht Integer!) + - Konvertierung: `parseInt(ustSatz)` → dann `/100` im Calculator + - **Wichtig:** Expliziter Null-Check nötig, `0` ist falsy in `|| 19` + +5. **Reaktivität**: + - Listener auf: streitwert, anzahlVermieter, anzahlMieter, anzahlSonstigeVolljhrigeBewohner, ustSatz + - Initial berechnen mit `'sync'` Event + - `calculating` Flag verhindert Rekursion + +**Layout-Panels:** +- **Gebührenberechnung** (primary, info-note): Standard 1. Instanz Kosten +- **Säumnisszenario I. Inst.** (primary, success-note): Beklagte erscheint nicht +- **Vergleichsszenario I. Inst.** (primary, success-note): Einigung vor Urteil + +**Hervorhebung:** "Vorauszuschießende Kosten I. Inst." wird via CSS hervorgehoben (grüner Hintergrund, fetter Wert) \ No newline at end of file diff --git a/client/custom/css/erstgespraech-highlight.css b/client/custom/css/erstgespraech-highlight.css index 8b8d2fc7..2417991c 100644 --- a/client/custom/css/erstgespraech-highlight.css +++ b/client/custom/css/erstgespraech-highlight.css @@ -2,7 +2,7 @@ .detail .cell[data-name="vorzusch1Instanz"] { background-color: #d4edda; /* Hellgrün */ padding: 10px; - border-left: 4px solid #28a745; /* Grüner Rand links */ + border-bottom: 4px solid #28a745; /* Grüner Rand unten */ border-radius: 4px; } @@ -13,7 +13,6 @@ } .detail .cell[data-name="vorzusch1Instanz"] .label-text { - font-weight: 600; color: #155724; } @@ -21,6 +20,6 @@ .edit .cell[data-name="vorzusch1Instanz"] { background-color: #d4edda; padding: 10px; - border-left: 4px solid #28a745; + border-bottom: 4px solid #28a745; border-radius: 4px; } diff --git a/data/config.php b/data/config.php index 3dd42c8e..c9122fba 100644 --- a/data/config.php +++ b/data/config.php @@ -349,8 +349,8 @@ return [ 0 => 'youtube.com', 1 => 'google.com' ], - 'cacheTimestamp' => 1769198038, - 'microtime' => 1769198038.586617, + 'cacheTimestamp' => 1769198236, + 'microtime' => 1769198236.97567, 'siteUrl' => 'https://crm.bitbylaw.com', 'fullTextSearchMinLength' => 4, 'appTimestamp' => 1768843902,