Files
motia/bitbylaw/scripts/espocrm_tests/test_espocrm_id_injection.py
bitbylaw 7856dd1d68 Add tests for Kommunikation Sync implementation and verification scripts
- Implemented comprehensive tests for the Kommunikation Sync functionality, covering base64 encoding, marker parsing, creation, type detection, and integration scenarios.
- Added a verification script to check for unique IDs in Advoware communications, ensuring stability and integrity of the IDs.
- Created utility scripts for code validation, notification testing, and PUT response detail analysis to enhance development and testing processes.
- Updated README with details on new tools and their usage.
2026-02-08 23:05:56 +00:00

226 lines
7.4 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
TEST: Können wir eigene IDs in emailAddressData setzen?
Wenn EspoCRM IDs beim UPDATE akzeptiert und speichert,
dann können wir:
- Advoware-ID als 'id' in emailAddressData speichern
- Stabiles Matching haben
- Bidirektionalen Sync machen
Vorsichtiger Test mit Backup!
"""
import asyncio
import json
from services.espocrm import EspoCRMAPI
TEST_BETEILIGTE_ID = '68e4af00172be7924'
class SimpleContext:
class Logger:
def info(self, msg): print(f"[INFO] {msg}")
def error(self, msg): print(f"[ERROR] {msg}")
def warning(self, msg): print(f"[WARN] {msg}")
def debug(self, msg): pass
def __init__(self):
self.logger = self.Logger()
def print_section(title):
print("\n" + "="*70)
print(title)
print("="*70)
async def test_id_persistence():
"""
Teste ob EspoCRM IDs in emailAddressData speichert
Ablauf:
1. Hole aktuelle Daten (Backup)
2. Füge 'id' Feld zu EINEM Email hinzu
3. UPDATE
4. GET wieder
5. Prüfe ob 'id' noch da ist
6. Restore original falls nötig
"""
print_section("TEST: ID Persistence in emailAddressData")
context = SimpleContext()
espo = EspoCRMAPI(context)
# 1. Backup
print("\n1⃣ Backup: Hole aktuelle Daten")
entity_backup = await espo.get_entity('CBeteiligte', TEST_BETEILIGTE_ID)
emails_backup = entity_backup.get('emailAddressData', [])
print(f" Backup: {len(emails_backup)} Emails gesichert")
for email in emails_backup:
print(f"{email['emailAddress']}")
# 2. Modifiziere NUR das erste Email (primary)
print("\n2⃣ Modifikation: Füge 'id' zu primary Email hinzu")
emails_modified = []
for i, email in enumerate(emails_backup):
email_copy = email.copy()
if email_copy.get('primary'): # Nur primary modifizieren
# Nutze einen recognizable Test-Wert
test_id = f"advoware-{i+1}-test-123"
email_copy['id'] = test_id
print(f" ✏️ {email['emailAddress']:40s} → id={test_id}")
else:
print(f" ⏭️ {email['emailAddress']:40s} (unverändert)")
emails_modified.append(email_copy)
# 3. UPDATE
print("\n3⃣ UPDATE: Sende modifizierte Daten")
try:
await espo.update_entity('CBeteiligte', TEST_BETEILIGTE_ID, {
'emailAddressData': emails_modified
})
print(" ✅ UPDATE erfolgreich")
except Exception as e:
print(f" ❌ UPDATE fehlgeschlagen: {e}")
return
# 4. GET wieder
print("\n4⃣ GET: Hole Daten wieder ab")
await asyncio.sleep(0.5) # Kurze Pause
entity_after = await espo.get_entity('CBeteiligte', TEST_BETEILIGTE_ID)
emails_after = entity_after.get('emailAddressData', [])
print(f" Nach UPDATE: {len(emails_after)} Emails")
# 5. Vergleiche
print("\n5⃣ VERGLEICH: Ist 'id' noch da?")
id_found = False
for email in emails_after:
email_addr = email['emailAddress']
has_id = 'id' in email
if has_id:
print(f"{email_addr:40s} → id={email['id']}")
id_found = True
else:
print(f"{email_addr:40s} → KEIN id Feld")
# 6. Ergebnis
print(f"\n6⃣ ERGEBNIS:")
if id_found:
print(" 🎉 SUCCESS! EspoCRM speichert und liefert 'id' Feld zurück!")
print(" → Wir können Advoware-IDs in emailAddressData speichern")
print(" → Stabiles bidirektionales Matching möglich")
else:
print(" ❌ FAILED: EspoCRM ignoriert/entfernt 'id' Feld")
print(" → Wert-basiertes Matching notwendig")
print(" → Hybrid-Strategie (primary-Flag) ist beste Option")
# 7. Restore (optional - nur wenn User will)
print(f"\n7⃣ CLEANUP:")
print(" Original-Daten (ohne id):")
for email in emails_backup:
print(f"{email['emailAddress']}")
if id_found:
restore = input("\n 🔄 Restore zu Original (ohne id)? [y/N]: ").strip().lower()
if restore == 'y':
await espo.update_entity('CBeteiligte', TEST_BETEILIGTE_ID, {
'emailAddressData': emails_backup
})
print(" ✅ Restored")
else:
print(" ⏭️ Nicht restored (id bleibt)")
return id_found
async def test_custom_field_approach():
"""
Alternative: Nutze ein custom field in CBeteiligte für ID-Mapping
Idee: Speichere JSON-Mapping in einem Textfeld
"""
print_section("ALTERNATIVE: Custom Field für ID-Mapping")
print("\n💡 Idee: Nutze custom field 'kommunikationMapping'")
print(" Struktur:")
print(" {")
print(' "emails": [')
print(' {"emailAddress": "max@example.com", "advowareId": 123, "advowareRowId": "ABC"}')
print(' ],')
print(' "phones": [')
print(' {"phoneNumber": "+49...", "advowareId": 456, "advowareRowId": "DEF"}')
print(' ]')
print(" }")
print("\n✅ Vorteile:")
print(" • Stabiles Matching via advowareId")
print(" • Change Detection via advowareRowId")
print(" • Bidirektionaler Sync möglich")
print("\n❌ Nachteile:")
print(" • Erfordert custom field in EspoCRM")
print(" • Daten-Duplikation (in Data + Mapping)")
print(" • Fragil wenn emailAddress/phoneNumber ändert")
context = SimpleContext()
espo = EspoCRMAPI(context)
# Prüfe ob custom field existiert
print("\n🔍 Prüfe ob 'kommunikationMapping' Feld existiert:")
try:
entity = await espo.get_entity('CBeteiligte', TEST_BETEILIGTE_ID)
if 'kommunikationMapping' in entity:
print(f" ✅ Feld existiert: {entity['kommunikationMapping']}")
else:
print(f" ❌ Feld existiert nicht")
print(f" → Müsste in EspoCRM angelegt werden")
except Exception as e:
print(f" ❌ Error: {e}")
async def main():
print("\n" + "="*70)
print("TEST: KÖNNEN WIR EIGENE IDs IN emailAddressData SETZEN?")
print("="*70)
print("\nZiel: Herausfinden ob EspoCRM 'id' Felder akzeptiert und speichert\n")
try:
# Haupttest
id_works = await test_id_persistence()
# Alternative
await test_custom_field_approach()
print_section("FINAL RECOMMENDATION")
if id_works:
print("\n🎯 EMPFEHLUNG: Nutze 'id' Feld in emailAddressData")
print("\n📋 Implementation:")
print(" 1. Bei Advoware → EspoCRM: Füge 'id' mit Advoware-ID hinzu")
print(" 2. Matching via 'id' Feld")
print(" 3. Change Detection via Advoware rowId")
print(" 4. Bidirektionaler Sync möglich")
else:
print("\n🎯 EMPFEHLUNG A: Hybrid-Strategie (primary-Flag)")
print(" • Einfach zu implementieren")
print(" • Nutzt Standard-EspoCRM")
print(" • Eingeschränkt bidirektional")
print("\n🎯 EMPFEHLUNG B: Custom Field 'kommunikationMapping'")
print(" • Vollständig bidirektional")
print(" • Erfordert EspoCRM-Anpassung")
print(" • Komplexere Implementation")
except Exception as e:
print(f"\n❌ Fehler: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())