Files
motia/bitbylaw/docs/ADRESSEN_SYNC_SUMMARY.md
bitbylaw c770f2c8ee feat: Implement address synchronization between EspoCRM and Advoware
- Add AdressenMapper for transforming addresses between EspoCRM and Advoware formats.
- Create AdressenSync class to handle address creation, update, and deletion synchronization.
- Introduce NotificationManager for managing manual intervention notifications in case of sync issues.
- Implement detailed logging for address sync operations and error handling.
- Ensure READ-ONLY field changes are detected and notified for manual resolution.
2026-02-08 14:29:29 +00:00

255 lines
7.6 KiB
Markdown

# 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