# Adressen-Sync: Zusammenfassung & Implementierungsplan **Datum**: 8. Februar 2026 **Status**: ✅ Analyse abgeschlossen, bereit für Implementierung --- ## 📋 Executive Summary ### ✅ Was funktioniert: - **CREATE** (POST): Alle Felder können gesetzt werden - **UPDATE** (PUT): 4 Haupt-Adressfelder (`strasse`, `plz`, `ort`, `anschrift`) - **MATCHING**: Via `bemerkung`-Feld mit EspoCRM-ID (stabil, READ-ONLY) - **SYNC from Advoware**: Vollständig möglich ### ❌ Was nicht funktioniert: - **DELETE**: 403 Forbidden (nicht verfügbar) - **Soft-Delete**: `gueltigBis` ist READ-ONLY (kann nicht nachträglich gesetzt werden) - **8 Felder READ-ONLY bei PUT**: `land`, `postfach`, `postfachPLZ`, `standardAnschrift`, `bemerkung`, `gueltigVon`, `gueltigBis`, `reihenfolgeIndex` ### 💡 Lösung: Hybrid-Ansatz **Automatischer Sync + Notification-System für manuelle Eingriffe** --- ## 🏗️ Implementierte Komponenten ### 1. Notification-System ✅ **Datei**: [`services/notification_utils.py`](../services/notification_utils.py) **Features:** - Zentrale `NotificationManager` Klasse - Task-Erstellung in EspoCRM mit Schritt-für-Schritt Anleitung - In-App Notifications an assigned Users - 6 vordefinierte Action-Types: - `address_delete_required` - DELETE manuell nötig - `address_reactivate_required` - Neue Adresse erstellen - `address_field_update_required` - READ-ONLY Felder ändern - `readonly_field_conflict` - Sync-Konflikt - `missing_in_advoware` - Element fehlt - `general_manual_action` - Allgemein **Verwendung:** ```python from services.notification_utils import NotificationManager notif_mgr = NotificationManager(espocrm_api, context) # DELETE erforderlich await notif_mgr.notify_manual_action_required( entity_type='CAdressen', entity_id='65abc123', action_type='address_delete_required', details={ 'betnr': '104860', 'strasse': 'Teststraße 123', 'plz': '30159', 'ort': 'Hannover' } ) # → Erstellt Task + Notification mit detaillierter Anleitung ``` ### 2. Umfassende Test-Suite ✅ **Test-Scripts** (alle in [`scripts/`](../scripts/)): 1. **`test_adressen_api.py`** - Haupttest (7 Tests) - POST/PUT mit allen Feldern - Feld-für-Feld Verifikation - Response-Analyse 2. **`test_adressen_delete_matching.py`** - DELETE + Matching - DELETE-Funktionalität (→ 403) - `bemerkung`-basiertes Matching - Stabilität von `bemerkung` bei PUT 3. **`test_adressen_deactivate_ordering.py`** - Deaktivierung - `gueltigBis` nachträglich setzen (→ READ-ONLY) - `reihenfolgeIndex` Verhalten - Automatisches Ans-Ende-Reihen 4. **`test_adressen_gueltigbis_modify.py`** - Soft-Delete - `gueltigBis` ändern (→ nicht möglich) - Verschiedene Methoden getestet 5. **`test_put_response_detail.py`** - PUT-Analyse - Welche Felder werden wirklich geändert - Response vs. GET Vergleich ### 3. Dokumentation ✅ **Datei**: [`docs/ADRESSEN_SYNC_ANALYSE.md`](ADRESSEN_SYNC_ANALYSE.md) **Inhalte:** - Swagger API-Dokumentation - EspoCRM Entity-Struktur - Detaillierte Test-Ergebnisse - Sync-Strategien (3 Optionen evaluiert) - Finale Empfehlung: Hybrid-Ansatz - Feld-Mappings - Risiko-Analyse - Implementierungsplan --- ## 🔑 Kritische Erkenntnisse ### ID-Mapping ``` ❌ id = 0 → Immer 0, unbrauchbar ✅ bemerkung → Stabil (READ-ONLY), perfekt für Matching ✅ reihenfolgeIndex → Stabil, automatisch vergeben, für PUT-Endpoint ❌ rowId → Ändert sich bei PUT, nicht für Matching! ``` ### PUT-Feldübersicht | Feld | POST | PUT | Matching | |------|------|-----|----------| | `strasse` | ✅ | ✅ | - | | `plz` | ✅ | ✅ | - | | `ort` | ✅ | ✅ | - | | `land` | ✅ | ❌ READ-ONLY | - | | `postfach` | ✅ | ❌ READ-ONLY | - | | `postfachPLZ` | ✅ | ❌ READ-ONLY | - | | `anschrift` | ✅ | ✅ | - | | `standardAnschrift` | ✅ | ❌ READ-ONLY | - | | `bemerkung` | ✅ | ❌ READ-ONLY | ✅ Perfekt! | | `gueltigVon` | ✅ | ❌ READ-ONLY | - | | `gueltigBis` | ✅ | ❌ READ-ONLY | - | | `reihenfolgeIndex` | - | ❌ System | ✅ Für PUT | --- ## 🚀 Nächste Schritte ### Phase 1: Validierung ⏳ - [ ] EspoCRM CAdressen Entity prüfen - [ ] Felder vorhanden: `advowareIndexId`, `advowareRowId`, `syncStatus`, `isActive`, `manualActionNote` - [ ] Relation zu CBeteiligte korrekt - [ ] Notification-System testen - [ ] Task-Erstellung funktioniert - [ ] Assigned Users werden benachrichtigt ### Phase 2: Mapper ⏳ - [ ] `services/adressen_mapper.py` erstellen ```python class AdressenMapper: def map_espocrm_to_advoware(espo_addr) -> dict def map_advoware_to_espocrm(advo_addr) -> dict def find_by_bemerkung(addresses, espo_id) -> dict def detect_readonly_changes(espo, advo) -> dict ``` ### Phase 3: Sync-Service ⏳ - [ ] `services/adressen_sync.py` erstellen ```python class AdressenSyncService: async def create_address(espo_addr) async def update_address(espo_addr) async def delete_address(espo_addr) # → Notification async def sync_from_advoware(betnr, espo_beteiligte_id) ``` ### Phase 4: Integration ⏳ - [ ] In bestehenden Beteiligte-Sync integrieren oder - [ ] Eigener Adressen-Sync Step ### Phase 5: Testing ⏳ - [ ] Unit Tests für Mapper - [ ] Integration Tests mit Test-Daten - [ ] End-to-End Test: CREATE → UPDATE → DELETE - [ ] Notification-Flow testen ### Phase 6: Deployment ⏳ - [ ] Staging-Test mit echten Daten - [ ] User-Schulung: Manuelle Eingriffe - [ ] Monitoring einrichten - [ ] Production Rollout --- ## 📝 Wichtige Hinweise für Entwickler ### Matching-Strategie **IMMER via `bemerkung`-Feld:** ```python # Beim CREATE: bemerkung = f"EspoCRM-ID: {espocrm_address_id}" # Beim Sync: espocrm_id = parse_espocrm_id_from_bemerkung(advo_addr['bemerkung']) # Robust gegen User-Änderungen: import re match = re.search(r'EspoCRM-ID:\s*([a-f0-9-]+)', bemerkung) espocrm_id = match.group(1) if match else None ``` ### Notification Trigger **Immer Notifications erstellen bei:** - DELETE-Request (API nicht verfügbar) - PUT mit READ-ONLY Feldern (land, postfach, etc.) - Reaktivierung (neue Adresse erstellen) - Adresse direkt in Advoware erstellt (fehlende bemerkung) ### Sync-Richtung - **EspoCRM → Advoware**: Für CREATE/UPDATE - **Advoware → EspoCRM**: Master für "Existenz" - **Konflikt-Resolution**: Siehe Dokumentation ### Aktuelle Adresse-Matching **Wichtig**: Die "aktuelle" Adresse muss in beiden Systemen gleich sein! **Strategie:** ```python # In Advoware: standardAnschrift = true (READ-ONLY!) # In EspoCRM: isPrimary = true (eigenes Feld) # Sync-Logik: if espo_addr['isPrimary']: # Prüfe ob Advoware-Adresse standardAnschrift = true hat if not advo_addr['standardAnschrift']: # → Notification: Hauptadresse manuell in Advoware setzen await notify_main_address_mismatch(...) ``` --- ## 📊 Metriken & Monitoring **Zu überwachende KPIs:** - Anzahl erstellter Notifications pro Tag - Durchschnittliche Zeit bis Task-Completion - Anzahl gescheiterter Syncs - READ-ONLY Feld-Konflikte (Häufigkeit) - DELETE-Requests (manuell nötig) **Alerts einrichten für:** - Mehr als 5 unerledigte DELETE-Tasks pro User - Sync-Fehlerrate > 10% - Tasks älter als 7 Tage --- ## 🔗 Referenzen - **Hauptdokumentation**: [`docs/ADRESSEN_SYNC_ANALYSE.md`](ADRESSEN_SYNC_ANALYSE.md) - **Notification-Utility**: [`services/notification_utils.py`](../services/notification_utils.py) - **Test-Scripts**: [`scripts/test_adressen_*.py`](../scripts/) - **Swagger-Doku**: Advoware API v1 - Adressen Endpoints --- **Erstellt**: 8. Februar 2026 **Autor**: GitHub Copilot **Review**: Pending