# Entity-Mapping: EspoCRM CBeteiligte ↔ Advoware Beteiligte Basierend auf dem Vergleich von: - **EspoCRM**: CBeteiligte Entity ID `68e4af00172be7924` - **Advoware**: Beteiligter ID `104860` ## Gemeinsame Felder (direkte Übereinstimmung) | EspoCRM Feld | Advoware Feld | Typ | Notes | |--------------|---------------|-----|-------| | `name` | `name` | string | Vollständiger Name | | `rechtsform` | `rechtsform` | string | Rechtsform (z.B. "GmbH", "Frau") | | `id` | `id` | mixed | **Achtung:** EspoCRM=string, Advoware=int | ## Namenfelder | EspoCRM Feld | Advoware Feld | Mapping | |--------------|---------------|---------| | `firstName` | `vorname` | ✓ Direkt | | `lastName` | `name` | ✓ Bei Personen | | `middleName` | - | ❌ Kein direktes Mapping | | `firmenname` | `name` | ✓ Bei Firmen | | - | `geburtsname` | ← Nur in Advoware | | - | `kurzname` | ← Nur in Advoware | ## Kontaktdaten | EspoCRM Feld | Advoware Feld | Mapping | |--------------|---------------|---------| | `emailAddress` | `emailGesch` | ✓ Geschäftlich | | `emailAddressData` (array) | `email` | ⚠️ Komplex: Array vs. String | | `phoneNumber` | `telGesch` | ✓ Geschäftstelefon | | `phoneNumberData` (array) | `telPrivat` | ⚠️ Komplex | | - | `mobil` | ← Nur in Advoware | | - | `faxGesch` / `faxPrivat` | ← Nur in Advoware | | - | `autotelefon` | ← Nur in Advoware | | - | `internet` | ← Nur in Advoware | **Hinweis**: Advoware hat zusätzlich `kommunikation` Array mit strukturierten Kontaktdaten. ## Adressdaten | EspoCRM Feld | Advoware Feld | Mapping | |--------------|---------------|---------| | `adressensIds` / `adressensNames` | `adressen` (array) | ⚠️ Beziehung | | - | `strasse` | ← Hauptadresse in Advoware Root | | - | `plz` | ← Hauptadresse in Advoware Root | | - | `ort` | ← Hauptadresse in Advoware Root | | - | `anschrift` | ← Formatierte Adresse | **Hinweis**: - EspoCRM: Adressen als Related Entities (IDs/Names) - Advoware: Hauptadresse im Root-Objekt + `adressen` Array für zusätzliche ## Anrede & Titel | EspoCRM Feld | Advoware Feld | Mapping | |--------------|---------------|---------| | `salutationName` | `anrede` | ✓ (z.B. "Frau", "Herr") | | - | `bAnrede` | ← Briefanrede ("Sehr geehrte...") | | - | `titel` | ← Titel (Dr., Prof., etc.) | | - | `zusatz` | ← Namenszusatz | ## Geburtsdaten | EspoCRM Feld | Advoware Feld | Mapping | |--------------|---------------|---------| | `dateOfBirth` | `geburtsdatum` | ✓ Direkt | | - | `sterbedatum` | ← Nur in Advoware | | - | `familienstand` | ← Nur in Advoware | ## Handelsregister (für Firmen) | EspoCRM Feld | Advoware Feld | Mapping | |--------------|---------------|---------| | `handelsregisterNummer` | `handelsRegisterNummer` | ✓ Direkt | | `handelsregisterArt` (z.B. "HRB") | - | ❌ Nur in EspoCRM | | - | `registergericht` | ← Nur in Advoware | ## Bankverbindungen | EspoCRM Feld | Advoware Feld | Mapping | |--------------|---------------|---------| | `bankverbindungensIds` / Names | `bankkverbindungen` (array) | ⚠️ Related Entity vs. Array | ## Beteiligungen/Akten | EspoCRM Feld | Advoware Feld | Mapping | |--------------|---------------|---------| | - | `beteiligungen` (array) | ← Nur in Advoware | **Hinweis**: Advoware speichert die Akten-Beteiligungen direkt beim Beteiligten. ## EspoCRM-spezifische Felder | Feld | Zweck | |------|-------| | `betnr` | Beteiligten-Nummer (= Advoware `betNr`) | | `advowareLastSync` | Zeitstempel der letzten Synchronisation | | `syncStatus` | Status: "clean", "dirty", "syncing" | | `disgTyp` | DISC-Persönlichkeitstyp | | `description` | Notizen/Beschreibung | | `createdAt` / `createdById` / `createdByName` | Audit-Felder | | `modifiedAt` / `modifiedById` / `modifiedByName` | Audit-Felder | | `assignedUserId` / `assignedUserName` | Zuweisungen | | `teamsIds` / `teamsNames` | Team-Zugehörigkeit | | `deleted` | Soft-Delete Flag | | `isFollowed` / `followersIds` | Social Features | ## Advoware-spezifische Felder | Feld | Zweck | |------|-------| | `betNr` | Interne Beteiligten-Nummer | | `rowId` | Datenbank Row-ID | | `art` | Beteiligten-Art | | `angelegtAm` / `angelegtVon` | Erstellt | | `geaendertAm` / `geaendertVon` | Geändert | | `kontaktpersonen` (array) | Kontaktpersonen bei Firmen | | `ePost` / `bea` | Spezielle Kommunikationskanäle | ## Mapping-Strategie ### 1. Person (Natürliche Person) ```python espocrm_to_advoware = { 'firstName': 'vorname', 'lastName': 'name', 'dateOfBirth': 'geburtsdatum', 'rechtsform': 'rechtsform', # z.B. "Herr", "Frau" 'salutationName': 'anrede', 'emailAddress': 'emailGesch', 'phoneNumber': 'telGesch', } ``` ### 2. Firma (Juristische Person) ```python espocrm_to_advoware = { 'firmenname': 'name', 'rechtsform': 'rechtsform', # z.B. "GmbH", "AG" 'handelsregisterNummer': 'handelsRegisterNummer', 'emailAddress': 'emailGesch', 'phoneNumber': 'telGesch', } ``` ### 3. Adressen **EspoCRM → Advoware**: - Lade Related Entity `Adressen` via `adressensIds` - Mappe Hauptadresse zu Root-Feldern `strasse`, `plz`, `ort` - Zusätzliche Adressen in `adressen` Array **Advoware → EspoCRM**: - Hauptadresse aus Root-Feldern - `adressen` Array → Related Entities in EspoCRM ### 4. Kontaktdaten (Komplex) **EspoCRM `emailAddressData`**: ```json [ { "emailAddress": "primary@example.com", "primary": true, "optOut": false, "invalid": false } ] ``` **Advoware `kommunikation`**: ```json [ { "id": 88002, "kommArt": 0, // 0=Telefon, 1=Email, etc. "tlf": "0511/12345-60", "online": false } ] ``` **Mapping**: Erfordert Transformation basierend auf `kommArt`. ## Sync-Richtungen ### EspoCRM → Advoware (Webhook-getrieben) 1. Webhook empfängt `CBeteiligte` create/update/delete 2. Mappe Felder gemäß Tabelle oben 3. `POST /api/v1/advonet/Beteiligte` (create) oder `PUT /api/v1/advonet/Beteiligte/{betNr}` (update) 4. Update `advowareLastSync` und `syncStatus` in EspoCRM ### Advoware → EspoCRM (Polling oder Webhook) 1. Überwache Änderungen in Advoware 2. Mappe Felder zurück 3. `PUT /api/v1/CBeteiligte/{id}` in EspoCRM 4. Setze `syncStatus = "clean"` ## Konflikte & Regeln | Szenario | Regel | |----------|-------| | Beide Systeme geändert | Advoware als Master (führendes System) | | Feld nur in EspoCRM | Ignorieren beim Export, behalten | | Feld nur in Advoware | Null/Leer in EspoCRM setzen | | `betnr` vs. `betNr` | Sync-Link: Muss identisch sein | ## ID-Mapping **Problem**: EspoCRM und Advoware haben unterschiedliche ID-Systeme. **Lösung**: - EspoCRM `betnr` Feld = Advoware `betNr` - Dies ist der Sync-Link zwischen beiden Systemen - Bei Create in EspoCRM: `betnr` erst nach Advoware-Insert setzen - Bei Create in Advoware: EspoCRM ID in Custom Field speichern? ## Nächste Schritte 1. **Mapper-Modul erstellen**: `bitbylaw/services/espocrm_mapper.py` - `map_cbeteiligte_to_advoware(espo_data) -> advo_data` - `map_advoware_to_cbeteiligte(advo_data) -> espo_data` 2. **Sync-Event-Step implementieren**: `bitbylaw/steps/vmh/beteiligte_sync_event_step.py` - Subscribe to `vmh.beteiligte.create/update/delete` - Fetch full entity from EspoCRM - Transform via Mapper - Write to Advoware - Update sync metadata 3. **Testing**: - Unit Tests für Mapper - Integration Tests mit Sandbox-Daten - Konflikt-Szenarien testen 4. **Error Handling**: - Retry-Logic bei API-Fehlern - Validation vor dem Sync - Rollback bei Fehlern? - Logging aller Sync-Operationen 5. **Performance**: - Batch-Processing für mehrere Beteiligte - Rate Limiting beachten - Caching von Lookup-Daten ## Beispiel-Transformation ### EspoCRM CBeteiligte: ```json { "id": "68e4af00172be7924", "firstName": "Angela", "lastName": "Mustermanns", "rechtsform": "Frau", "emailAddress": "angela@example.com", "phoneNumber": "0511/12345", "betnr": 104860, "handelsregisterNummer": null } ``` ### Advoware Beteiligter: ```json { "betNr": 104860, "vorname": "Angela", "name": "Mustermanns", "rechtsform": "Frau", "anrede": "Frau", "emailGesch": "angela@example.com", "telGesch": "0511/12345" } ``` --- **Generiert am**: 2026-02-07 **Basierend auf**: Real-Daten-Vergleich mit `scripts/compare_beteiligte.py`