feat: Enhance sync conflict detection and resolution logic in BeteiligteSync class
This commit is contained in:
@@ -241,29 +241,38 @@ class BeteiligteSync:
|
||||
# PRIMÄR: rowId-basierte Änderungserkennung (zuverlässiger!)
|
||||
espo_rowid = espo_entity.get('advowareRowId')
|
||||
advo_rowid = advo_entity.get('rowId')
|
||||
|
||||
if espo_rowid and advo_rowid:
|
||||
if espo_rowid != advo_rowid:
|
||||
# rowId unterschiedlich → Advoware wurde geändert
|
||||
self._log(f"Advoware rowId geändert: {espo_rowid[:20]}... → {advo_rowid[:20]}...")
|
||||
return 'advoware_newer'
|
||||
else:
|
||||
# rowId gleich → keine Änderung in Advoware
|
||||
# Prüfe ob EspoCRM geändert wurde (via modifiedAt)
|
||||
espo_modified = espo_entity.get('modifiedAt')
|
||||
last_sync = espo_entity.get('advowareLastSync')
|
||||
espo_modified = espo_entity.get('modifiedAt')
|
||||
|
||||
if espo_modified and last_sync:
|
||||
if espo_rowid and advo_rowid and last_sync:
|
||||
# Prüfe ob Advoware geändert wurde (rowId)
|
||||
advo_changed = (espo_rowid != advo_rowid)
|
||||
|
||||
# Prüfe ob EspoCRM auch geändert wurde (seit letztem Sync)
|
||||
espo_changed = False
|
||||
if espo_modified:
|
||||
try:
|
||||
espo_ts = self.parse_timestamp(espo_modified)
|
||||
sync_ts = self.parse_timestamp(last_sync)
|
||||
|
||||
if espo_ts and sync_ts and espo_ts > sync_ts:
|
||||
self._log(f"EspoCRM neuer (rowId gleich, aber modifiedAt > lastSync)")
|
||||
return 'espocrm_newer'
|
||||
if espo_ts and sync_ts:
|
||||
espo_changed = (espo_ts > sync_ts)
|
||||
except Exception as e:
|
||||
self._log(f"Timestamp-Parse-Fehler: {e}", level='debug')
|
||||
|
||||
# Konfliktlogik: Beide geändert seit letztem Sync?
|
||||
if advo_changed and espo_changed:
|
||||
self._log(f"🚨 KONFLIKT: Beide Seiten geändert seit letztem Sync")
|
||||
return 'conflict'
|
||||
elif advo_changed:
|
||||
self._log(f"Advoware rowId geändert: {espo_rowid[:20]}... → {advo_rowid[:20]}...")
|
||||
return 'advoware_newer'
|
||||
elif espo_changed:
|
||||
self._log(f"EspoCRM neuer (modifiedAt > lastSync)")
|
||||
return 'espocrm_newer'
|
||||
else:
|
||||
# Weder Advoware noch EspoCRM geändert
|
||||
return 'no_change'
|
||||
|
||||
# Keine Änderungen
|
||||
self._log("Keine Änderungen (rowId identisch)")
|
||||
return 'no_change'
|
||||
@@ -502,10 +511,6 @@ class BeteiligteSync:
|
||||
update_data.update(extra_fields)
|
||||
|
||||
await self.espocrm.update_entity('CBeteiligte', entity_id, update_data)
|
||||
'advowareLastSync': now,
|
||||
'syncErrorMessage': f"Konflikt am {now}: {conflict_details}. EspoCRM hat gewonnen.",
|
||||
'syncRetryCount': 0
|
||||
})
|
||||
|
||||
self._log(f"Konflikt gelöst für {entity_id}: EspoCRM wins")
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ class BeteiligteMapper:
|
||||
"""
|
||||
logger.debug(f"Mapping EspoCRM → Advoware STAMMDATEN: {espo_entity.get('id')}")
|
||||
|
||||
# Bestimme ob Person oder Firma
|
||||
is_firma = bool(espo_entity.get('firmenname'))
|
||||
# Bestimme ob Person oder Firma (über firmenname-Feld)
|
||||
firmenname = espo_entity.get('firmenname')
|
||||
is_firma = bool(firmenname and firmenname.strip())
|
||||
rechtsform = espo_entity.get('rechtsform', '')
|
||||
|
||||
# Basis-Struktur (nur Stammdaten, keine Kontaktdaten!)
|
||||
@@ -41,11 +42,11 @@ class BeteiligteMapper:
|
||||
|
||||
# NAME: Person vs. Firma
|
||||
if is_firma:
|
||||
# Firma: name = firmenname
|
||||
advo_data['name'] = espo_entity.get('firmenname', '')
|
||||
# Firma: Lese von firmenname-Feld
|
||||
advo_data['name'] = firmenname
|
||||
advo_data['vorname'] = None
|
||||
else:
|
||||
# Person: name = lastName, vorname = firstName
|
||||
# Natürliche Person: Lese von lastName/firstName
|
||||
advo_data['name'] = espo_entity.get('lastName', '')
|
||||
advo_data['vorname'] = espo_entity.get('firstName', '')
|
||||
|
||||
@@ -100,17 +101,19 @@ class BeteiligteMapper:
|
||||
'advowareRowId': advo_entity.get('rowId'), # Änderungserkennung
|
||||
}
|
||||
|
||||
# NAME: Person vs. Firma
|
||||
# NAME: Person vs. Firma (EspoCRM blendet lastName/firstName aus bei Firmen)
|
||||
if is_person:
|
||||
# Person
|
||||
# Natürliche Person → lastName/firstName verwenden
|
||||
espo_data['firstName'] = vorname
|
||||
espo_data['lastName'] = advo_entity.get('name', '')
|
||||
espo_data['name'] = f"{vorname} {advo_entity.get('name', '')}".strip()
|
||||
espo_data['firmenname'] = None
|
||||
espo_data['firmenname'] = None # Firma-Feld leer lassen
|
||||
else:
|
||||
# Firma
|
||||
espo_data['firmenname'] = advo_entity.get('name', '')
|
||||
espo_data['name'] = advo_entity.get('name', '')
|
||||
# Firma → firmenname verwenden (EspoCRM zeigt dann nur dieses Feld)
|
||||
firma_name = advo_entity.get('name', '')
|
||||
espo_data['firmenname'] = firma_name
|
||||
espo_data['name'] = firma_name
|
||||
# lastName/firstName nicht setzen (EspoCRM blendet sie aus bei Firmen)
|
||||
espo_data['firstName'] = None
|
||||
espo_data['lastName'] = None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user