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.
This commit is contained in:
2026-02-08 23:05:56 +00:00
parent a157d3fa1d
commit 7856dd1d68
37 changed files with 438 additions and 271 deletions

View File

@@ -0,0 +1,202 @@
"""
Detail-Analyse: emailAddressData und phoneNumberData Struktur
Erkenntnisse:
- CKommunikation Entity existiert NICHT in EspoCRM
- CBeteiligte hat phoneNumberData und emailAddressData Arrays
- PhoneNumber und EmailAddress Entities existieren (aber 403 Forbidden - nur intern)
Jetzt: Analysiere die Data-Arrays im Detail
"""
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): print(f"[DEBUG] {msg}")
def __init__(self):
self.logger = self.Logger()
def print_section(title):
print("\n" + "="*70)
print(title)
print("="*70)
async def analyze_communication_data():
"""Detaillierte Analyse der Communication-Data Felder"""
print_section("DETAIL-ANALYSE: emailAddressData und phoneNumberData")
context = SimpleContext()
espo = EspoCRMAPI(context)
# Hole Beteiligten
entity = await espo.get_entity('CBeteiligte', TEST_BETEILIGTE_ID)
print(f"\n✅ Beteiligter: {entity.get('name')}")
print(f" ID: {entity.get('id')}")
# emailAddressData
print("\n" + "="*50)
print("emailAddressData")
print("="*50)
email_data = entity.get('emailAddressData', [])
if email_data:
print(f"\n📧 {len(email_data)} Email-Adresse(n):\n")
for i, email in enumerate(email_data):
print(f"[{i+1}] {json.dumps(email, indent=2, ensure_ascii=False)}")
# Analysiere Struktur
if i == 0:
print(f"\n📊 Feld-Struktur:")
for key, value in email.items():
print(f"{key:20s}: {type(value).__name__:10s} = {value}")
else:
print("\n❌ Keine Email-Adressen vorhanden")
# phoneNumberData
print("\n" + "="*50)
print("phoneNumberData")
print("="*50)
phone_data = entity.get('phoneNumberData', [])
if phone_data:
print(f"\n📞 {len(phone_data)} Telefonnummer(n):\n")
for i, phone in enumerate(phone_data):
print(f"[{i+1}] {json.dumps(phone, indent=2, ensure_ascii=False)}")
# Analysiere Struktur
if i == 0:
print(f"\n📊 Feld-Struktur:")
for key, value in phone.items():
print(f"{key:20s}: {type(value).__name__:10s} = {value}")
else:
print("\n❌ Keine Telefonnummern vorhanden")
# Prüfe andere Beteiligten mit mehr Kommunikationsdaten
print_section("SUCHE: Beteiligter mit mehr Kommunikationsdaten")
print("\n🔍 Liste erste 20 Beteiligte und prüfe Kommunikationsdaten...\n")
beteiligte_list = await espo.list_entities('CBeteiligte', max_size=20)
best_example = None
max_comm_count = 0
for bet in beteiligte_list:
# list_entities kann Strings oder Dicts zurückgeben
if isinstance(bet, str):
continue
email_count = len(bet.get('emailAddressData', []))
phone_count = len(bet.get('phoneNumberData', []))
total = email_count + phone_count
if total > 0:
print(f"{bet.get('name', 'N/A')[:40]:40s} | "
f"Email: {email_count} | Phone: {phone_count}")
if total > max_comm_count:
max_comm_count = total
best_example = bet
if best_example and max_comm_count > 0:
print(f"\n✅ Bester Beispiel-Beteiligter: {best_example.get('name')}")
print(f" Gesamt: {max_comm_count} Kommunikationseinträge")
print("\n📧 emailAddressData:")
for i, email in enumerate(best_example.get('emailAddressData', [])):
print(f"\n [{i+1}] {json.dumps(email, indent=6, ensure_ascii=False)}")
print("\n📞 phoneNumberData:")
for i, phone in enumerate(best_example.get('phoneNumberData', [])):
print(f"\n [{i+1}] {json.dumps(phone, indent=6, ensure_ascii=False)}")
return entity, email_data, phone_data, best_example
async def main():
print("\n" + "="*70)
print("ESPOCRM KOMMUNIKATION - DETAIL-ANALYSE")
print("="*70)
print("\nZiel: Verstehe die Struktur von emailAddressData und phoneNumberData")
print("Frage: Haben diese Arrays IDs für Matching mit Advoware?\n")
try:
entity, emails, phones, best = await analyze_communication_data()
print_section("ZUSAMMENFASSUNG")
print("\n📊 Erkenntnisse:")
print("\n1⃣ EspoCRM Standard-Struktur:")
print(" • emailAddressData: Array von Email-Objekten")
print(" • phoneNumberData: Array von Telefon-Objekten")
print(" • Keine separate CKommunikation Entity")
if emails:
print("\n2⃣ emailAddressData Felder:")
sample = emails[0]
for key in sample.keys():
print(f"{key}")
if 'id' in sample:
print("\n ✅ Hat 'id' Feld → Kann für Matching verwendet werden!")
else:
print("\n ❌ Kein 'id' Feld → Matching via Wert (emailAddress)")
if phones:
print("\n3⃣ phoneNumberData Felder:")
sample = phones[0]
for key in sample.keys():
print(f"{key}")
if 'id' in sample:
print("\n ✅ Hat 'id' Feld → Kann für Matching verwendet werden!")
else:
print("\n ❌ Kein 'id' Feld → Matching via Wert (phoneNumber)")
print("\n💡 Sync-Strategie:")
print("\n Option A: Kommunikation als Teil von Beteiligte-Sync")
print(" ────────────────────────────────────────────────────")
print(" • emailAddressData → Advoware Kommunikation (kommKz=4)")
print(" • phoneNumberData → Advoware Kommunikation (kommKz=1)")
print(" • Sync innerhalb von beteiligte_sync.py")
print(" • Kein separates Entity in EspoCRM nötig")
print("\n Option B: Custom CKommunikation Entity erstellen")
print(" ────────────────────────────────────────────────────")
print(" • Neues Custom Entity in EspoCRM anlegen")
print(" • Many-to-One Beziehung zu CBeteiligte")
print(" • Separater kommunikation_sync.py")
print(" • Ermöglicht mehr Flexibilität (Fax, BeA, etc.)")
print("\n ⚠️ WICHTIG:")
print(" • Standard EspoCRM hat NUR Email und Phone")
print(" • Advoware hat 12 verschiedene Kommunikationstypen")
print(" • Für vollständigen Sync → Custom Entity empfohlen")
except Exception as e:
print(f"\n❌ Fehler: {e}")
import traceback
traceback.print_exc()
if __name__ == '__main__':
asyncio.run(main())