feat(sync): Implement comprehensive sync fixes and optimizations as of February 8, 2026
- Fixed initial sync logic to respect actual timestamps, preventing unwanted overwrites. - Introduced exponential backoff for retry logic, with auto-reset for permanently failed entities. - Added validation checks to ensure data consistency during sync processes. - Corrected hash calculation to only include sync-relevant communications. - Resolved issues with empty slots ignoring user inputs and improved conflict handling. - Enhanced handling of Var4 and Var6 entries during sync conflicts. - Documented changes and added new fields required in EspoCRM for improved sync management. Also added a detailed analysis of syncStatus values in EspoCRM CBeteiligte, outlining responsibilities and ensuring robust sync mechanisms.
This commit is contained in:
254
bitbylaw/docs/archive/ADRESSEN_SYNC_SUMMARY.md
Normal file
254
bitbylaw/docs/archive/ADRESSEN_SYNC_SUMMARY.md
Normal file
@@ -0,0 +1,254 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user