feat(sync): Fix Var6 revert logic for direction='to_advoware' and enhance conflict handling
This commit is contained in:
@@ -350,6 +350,116 @@ async def _create_empty_slot(self, betnr: int, advo_komm: Dict) -> None:
|
||||
|
||||
---
|
||||
|
||||
## 🔴 **Zusätzlicher Bug #2: Var6 nicht revertiert bei direction='to_advoware'** - FIXED ✅
|
||||
|
||||
### Problem
|
||||
Bei `direction='to_advoware'` (EspoCRM wins) und Var6 (Advoware changed):
|
||||
- ❌ Advoware→EspoCRM wurde geskippt (korrekt)
|
||||
- ❌ ABER: Advoware-Wert wurde **NICHT** auf EspoCRM-Wert zurückgesetzt
|
||||
- ❌ Resultat: Advoware behält User-Änderung obwohl EspoCRM gewinnen soll!
|
||||
|
||||
**Konkretes Beispiel (Entity 104860 Trace)**:
|
||||
```
|
||||
[KOMM] ✏️ Var6: Changed in Advoware - synced='+49111111...', current='+491111112...'
|
||||
[KOMM] ===== CONFLICT STATUS: espo_wins=False =====
|
||||
[KOMM] ℹ️ Skipping Advoware→EspoCRM (direction=to_advoware)
|
||||
[KOMM] ✅ Bidirectional Sync complete: 0 total changes ← FALSCH!
|
||||
```
|
||||
|
||||
→ Die Nummer `+491111112` blieb in Advoware, aber EspoCRM hat `+49111111`!
|
||||
|
||||
### Fix
|
||||
|
||||
#### 1. Var6-Revert bei direction='to_advoware'
|
||||
```python
|
||||
# kommunikation_sync_utils.py:
|
||||
|
||||
else:
|
||||
self.logger.info(f"[KOMM] ℹ️ Skipping Advoware→EspoCRM (direction={direction})")
|
||||
|
||||
# FIX: Bei direction='to_advoware' müssen Var6-Änderungen zurückgesetzt werden!
|
||||
if direction == 'to_advoware' and len(diff['advo_changed']) > 0:
|
||||
self.logger.info(f"[KOMM] 🔄 Reverting {len(diff['advo_changed'])} Var6 entries to EspoCRM values...")
|
||||
for komm, old_value, new_value in diff['advo_changed']:
|
||||
# Revert: new_value (Advoware) → old_value (EspoCRM synced value)
|
||||
await self._revert_advoware_change(betnr, komm, old_value, new_value, advo_bet)
|
||||
result['espocrm_to_advoware']['updated'] += 1
|
||||
|
||||
# Bei direction='to_advoware' müssen auch Var4-Einträge zu Empty Slots gemacht werden!
|
||||
if direction == 'to_advoware' and len(diff['advo_new']) > 0:
|
||||
self.logger.info(f"[KOMM] 🔄 Converting {len(diff['advo_new'])} Var4 entries to Empty Slots...")
|
||||
for komm in diff['advo_new']:
|
||||
await self._create_empty_slot(betnr, komm)
|
||||
result['espocrm_to_advoware']['deleted'] += 1
|
||||
```
|
||||
|
||||
#### 2. Neue Methode: _revert_advoware_change()
|
||||
```python
|
||||
async def _revert_advoware_change(
|
||||
self,
|
||||
betnr: int,
|
||||
advo_komm: Dict,
|
||||
espo_synced_value: str,
|
||||
advo_current_value: str,
|
||||
advo_bet: Dict
|
||||
) -> None:
|
||||
"""
|
||||
Revertiert Var6-Änderung in Advoware zurück auf EspoCRM-Wert
|
||||
|
||||
Verwendet bei direction='to_advoware' (EspoCRM wins):
|
||||
- User hat in Advoware geändert
|
||||
- Aber EspoCRM soll gewinnen
|
||||
- → Setze Advoware zurück auf EspoCRM-Wert
|
||||
"""
|
||||
komm_id = advo_komm['id']
|
||||
marker = parse_marker(advo_komm.get('bemerkung', ''))
|
||||
|
||||
kommkz = marker['kommKz']
|
||||
user_text = marker.get('user_text', '')
|
||||
|
||||
# Revert: Setze tlf zurück auf EspoCRM-Wert
|
||||
new_marker = create_marker(espo_synced_value, kommkz, user_text)
|
||||
|
||||
await self.advoware.update_kommunikation(betnr, komm_id, {
|
||||
'tlf': espo_synced_value,
|
||||
'bemerkung': new_marker,
|
||||
'online': advo_komm.get('online', False)
|
||||
})
|
||||
|
||||
self.logger.info(f"[KOMM] ✅ Reverted Var6: '{advo_current_value[:30]}...' → '{espo_synced_value[:30]}...'")
|
||||
```
|
||||
|
||||
### Impact
|
||||
- ✅ Bei `direction='to_advoware'` werden Var6-Änderungen jetzt auf EspoCRM-Wert zurückgesetzt
|
||||
- ✅ Marker wird mit EspoCRM-Wert aktualisiert
|
||||
- ✅ User-Bemerkung bleibt erhalten
|
||||
- ✅ Beide Systeme sind nach Konflikt identisch
|
||||
|
||||
### Beispiel Trace (nach Fix)
|
||||
```
|
||||
[KOMM] ✏️ Var6: Changed in Advoware - synced='+49111111...', current='+491111112...'
|
||||
[KOMM] ⚠️ CONFLICT: EspoCRM wins - skipping Advoware→EspoCRM sync
|
||||
[KOMM] 🔄 Reverting 1 Var6 entries to EspoCRM values (EspoCRM wins)...
|
||||
[KOMM] ✅ Reverted Var6: '+491111112' → '+49111111'
|
||||
[KOMM] ✅ Bidirectional Sync complete: 1 total changes ← KORREKT!
|
||||
```
|
||||
|
||||
**WICHTIG**: Gleicher Fix auch bei `espo_wins=True` (direction='both'):
|
||||
```python
|
||||
elif direction in ['both', 'to_espocrm'] and espo_wins:
|
||||
# FIX: Var6-Änderungen revertieren
|
||||
if len(diff['advo_changed']) > 0:
|
||||
for komm, old_value, new_value in diff['advo_changed']:
|
||||
await self._revert_advoware_change(betnr, komm, old_value, new_value, advo_bet)
|
||||
|
||||
# FIX: Var4-Einträge zu Empty Slots
|
||||
if len(diff['advo_new']) > 0:
|
||||
for komm in diff['advo_new']:
|
||||
await self._create_empty_slot(betnr, komm)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
### Geänderte Dateien
|
||||
@@ -364,9 +474,11 @@ async def _create_empty_slot(self, betnr: int, advo_komm: Dict) -> None:
|
||||
|
||||
3. ✅ `services/kommunikation_sync_utils.py`
|
||||
- `sync_bidirectional()` - Hash nur für sync-relevante (Problem #3)
|
||||
- `sync_bidirectional()` - Var4→Empty Slots bei Konflikt (Zusätzlicher Bug)
|
||||
- `sync_bidirectional()` - Var4→Empty Slots bei Konflikt (Zusätzlicher Bug #1)
|
||||
- `sync_bidirectional()` - Var6-Revert bei direction='to_advoware' (Zusätzlicher Bug #2)
|
||||
- `_compute_diff()` - Hash nur für sync-relevante (Problem #3)
|
||||
- `_create_empty_slot()` - Unterstützt jetzt Var4 ohne Marker (Zusätzlicher Bug)
|
||||
- `_create_empty_slot()` - Unterstützt jetzt Var4 ohne Marker (Zusätzlicher Bug #1)
|
||||
- `_revert_advoware_change()` - NEU: Revertiert Var6 auf EspoCRM-Wert (Zusätzlicher Bug #2)
|
||||
|
||||
4. ✅ `steps/vmh/beteiligte_sync_event_step.py`
|
||||
- `handler()` - Retry-Backoff Check (Problem #12)
|
||||
|
||||
Reference in New Issue
Block a user