feat(sync): Implement auto-reset for permanently_failed entities and add retry backoff logic

- Added logic to reset permanently_failed entities that have reached their auto-reset threshold in `beteiligte_sync_cron_step.py`.
- Enhanced event handling in `beteiligte_sync_event_step.py` to skip retries if the next retry time has not been reached.
- Introduced validation checks after sync operations to ensure data consistency and integrity.
- Created detailed documentation outlining the fixes and their impacts on the sync process.
- Added scripts for analyzing sync issues and comparing entities to facilitate debugging and validation.
This commit is contained in:
2026-02-08 21:12:00 +00:00
parent 6e0e9a9730
commit 79e097be6f
8 changed files with 1135 additions and 30 deletions

View File

@@ -282,15 +282,18 @@ def find_empty_slot(kommkz: int, advo_kommunikationen: List[Dict]) -> Optional[D
"""
Findet leeren Slot mit passendem kommKz
Leere Slots haben: tlf='' und bemerkung='[ESPOCRM-SLOT:kommKz]'
Leere Slots haben: tlf='' (WIRKLICH leer!) UND bemerkung='[ESPOCRM-SLOT:kommKz]'
WICHTIG: User könnte Wert in einen Slot eingetragen haben → dann ist es KEIN Empty Slot mehr!
"""
for k in advo_kommunikationen:
tlf = (k.get('tlf') or '').strip()
bemerkung = k.get('bemerkung') or ''
if not tlf: # Leer
# Muss BEIDES erfüllen: tlf leer UND Slot-Marker
if not tlf:
marker = parse_marker(bemerkung)
if marker and marker['is_slot'] and marker['kommKz'] == kommkz:
if marker and marker.get('is_slot') and marker.get('kommKz') == kommkz:
return k
return None
@@ -301,21 +304,15 @@ def should_sync_to_espocrm(advo_komm: Dict) -> bool:
Prüft ob Advoware-Kommunikation zu EspoCRM synchronisiert werden soll
Nur wenn:
- Wert vorhanden
- Kein leerer Slot
- Wert vorhanden (tlf ist nicht leer)
WICHTIG: Ein Slot-Marker allein bedeutet NICHT "nicht sync-relevant"!
User könnte einen Wert in einen Slot eingetragen haben.
"""
tlf = (advo_komm.get('tlf') or '').strip()
if not tlf:
return False
bemerkung = advo_komm.get('bemerkung') or ''
marker = parse_marker(bemerkung)
# Keine leeren Slots
if marker and marker['is_slot']:
return False
return True
# Nur relevante Kriterium: Hat tlf einen Wert?
return bool(tlf)
def get_user_bemerkung(advo_komm: Dict) -> str: