diff --git a/bitbylaw/services/beteiligte_sync_utils.py b/bitbylaw/services/beteiligte_sync_utils.py index 2b8e80f6..6e5f699c 100644 --- a/bitbylaw/services/beteiligte_sync_utils.py +++ b/bitbylaw/services/beteiligte_sync_utils.py @@ -241,28 +241,37 @@ class BeteiligteSync: # PRIMÄR: rowId-basierte Änderungserkennung (zuverlässiger!) espo_rowid = espo_entity.get('advowareRowId') advo_rowid = advo_entity.get('rowId') + last_sync = espo_entity.get('advowareLastSync') + espo_modified = espo_entity.get('modifiedAt') - if espo_rowid and advo_rowid: - if espo_rowid != advo_rowid: - # rowId unterschiedlich → Advoware wurde geändert + 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: + 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: - # 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') - - if espo_modified and last_sync: - 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' - except Exception as e: - self._log(f"Timestamp-Parse-Fehler: {e}", level='debug') + # Weder Advoware noch EspoCRM geändert + return 'no_change' # Keine Änderungen self._log("Keine Änderungen (rowId identisch)") @@ -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") diff --git a/bitbylaw/services/espocrm_mapper.py b/bitbylaw/services/espocrm_mapper.py index 9e290bcb..f6b06f3e 100644 --- a/bitbylaw/services/espocrm_mapper.py +++ b/bitbylaw/services/espocrm_mapper.py @@ -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