# 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
