""" Deep-Dive: Suche nach versteckten ID-Feldern Die Relationships emailAddresses/phoneNumbers existieren (kein 404), aber wir bekommen 403 Forbidden. Möglichkeiten: 1. IDs sind in emailAddressData versteckt (vielleicht als 'id' Feld?) 2. Es gibt ein separates ID-Array 3. IDs sind in einem anderen Format gespeichert 4. Admin-API-Key hat nicht genug Rechte """ 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 inspect_email_data_structure(): """Schaue sehr genau in emailAddressData/phoneNumberData""" print_section("DEEP INSPECTION: emailAddressData Structure") context = SimpleContext() espo = EspoCRMAPI(context) entity = await espo.get_entity('CBeteiligte', TEST_BETEILIGTE_ID) email_data = entity.get('emailAddressData', []) print(f"\n📧 emailAddressData hat {len(email_data)} Einträge\n") for i, email in enumerate(email_data): print(f"[{i+1}] RAW Type: {type(email)}") print(f" Keys: {list(email.keys())}") print(f" JSON:\n") print(json.dumps(email, indent=4, ensure_ascii=False)) # Prüfe ob 'id' Feld vorhanden ist if 'id' in email: print(f"\n ✅ ID GEFUNDEN: {email['id']}") else: print(f"\n ❌ Kein 'id' Feld") # Prüfe alle Felder auf ID-ähnliche Werte print(f"\n Alle Werte:") for key, value in email.items(): print(f" {key:20s} = {value}") print() async def test_raw_api_call(): """Mache rohe API-Calls um zu sehen was wirklich zurückkommt""" print_section("RAW API CALL: Direkt ohne Wrapper") context = SimpleContext() espo = EspoCRMAPI(context) # Test 1: Normale Entity-Abfrage print(f"\n1️⃣ GET /CBeteiligte/{TEST_BETEILIGTE_ID}") result1 = await espo.api_call(f'CBeteiligte/{TEST_BETEILIGTE_ID}') # Zeige nur Email-relevante Felder email_fields = {k: v for k, v in result1.items() if 'email' in k.lower()} print(json.dumps(email_fields, indent=2, ensure_ascii=False)) # Test 2: Mit maxDepth Parameter (falls EspoCRM das unterstützt) print(f"\n2️⃣ GET mit maxDepth=2") try: result2 = await espo.api_call( f'CBeteiligte/{TEST_BETEILIGTE_ID}', params={'maxDepth': '2'} ) email_fields2 = {k: v for k, v in result2.items() if 'email' in k.lower()} print(json.dumps(email_fields2, indent=2, ensure_ascii=False)) except Exception as e: print(f" ❌ Error: {e}") # Test 3: Select nur emailAddressData print(f"\n3️⃣ GET mit select=emailAddressData") result3 = await espo.api_call( f'CBeteiligte/{TEST_BETEILIGTE_ID}', params={'select': 'emailAddressData'} ) print(json.dumps(result3, indent=2, ensure_ascii=False)) async def search_for_link_table(): """Suche nach EntityEmailAddress oder EntityPhoneNumber Link-Tables""" print_section("SUCHE: Link-Tables") context = SimpleContext() espo = EspoCRMAPI(context) # In EspoCRM gibt es manchmal Link-Tables wie "EntityEmailAddress" link_table_names = [ 'EntityEmailAddress', 'EntityPhoneNumber', 'ContactEmailAddress', 'ContactPhoneNumber', 'CBeteiligteEmailAddress', 'CBeteiligtePhoneNumber' ] for table_name in link_table_names: print(f"\n🔍 Teste: {table_name}") try: result = await espo.api_call(table_name, params={'maxSize': 3}) print(f" ✅ Existiert! Total: {result.get('total', 'unknown')}") if result.get('list'): print(f" Beispiel:") print(json.dumps(result['list'][0], indent=6, ensure_ascii=False)) except Exception as e: error_msg = str(e) if '404' in error_msg: print(f" ❌ 404 - Existiert nicht") elif '403' in error_msg: print(f" ⚠️ 403 - Existiert aber kein Zugriff") else: print(f" ❌ {error_msg}") async def test_update_with_ids(): """Test: Kann ich beim UPDATE IDs setzen?""" print_section("TEST: Update mit IDs") context = SimpleContext() espo = EspoCRMAPI(context) print(f"\n💡 Idee: Vielleicht kann man beim UPDATE IDs mitgeben") print(f" und EspoCRM erstellt dann die Verknüpfung?\n") # Hole aktuelle Daten entity = await espo.get_entity('CBeteiligte', TEST_BETEILIGTE_ID) current_emails = entity.get('emailAddressData', []) print(f"Aktuelle Emails:") for email in current_emails: print(f" • {email.get('emailAddress')}") # Versuche ein Update mit expliziter ID print(f"\n🧪 Teste: Füge 'id' Feld zu emailAddressData hinzu") test_emails = [] for email in current_emails: email_copy = email.copy() # Generiere eine Test-ID (oder verwende eine echte wenn wir eine finden) email_copy['id'] = f"test-id-{hash(email['emailAddress']) % 100000}" test_emails.append(email_copy) print(f" • {email['emailAddress']:40s} → id={email_copy['id']}") print(f"\n⚠️ ACHTUNG: Würde jetzt UPDATE machen mit:") print(json.dumps({'emailAddressData': test_emails}, indent=2, ensure_ascii=False)) print(f"\n→ NICHT ausgeführt (zu riskant ohne Backup)") async def check_database_or_config(): """Prüfe ob es Config/Settings gibt die IDs aktivieren""" print_section("ESPOCRM CONFIG: ID-Unterstützung") context = SimpleContext() espo = EspoCRMAPI(context) print(f"\n📋 Hole App-Informationen:") try: # EspoCRM hat oft einen /App endpoint app_info = await espo.api_call('App/user') # Zeige nur relevante Felder if app_info: relevant = ['acl', 'preferences', 'settings'] for key in relevant: if key in app_info: print(f"\n{key}:") # Suche nach Email/Phone-relevanten Einstellungen data = app_info[key] if isinstance(data, dict): email_phone_settings = {k: v for k, v in data.items() if 'email' in k.lower() or 'phone' in k.lower()} if email_phone_settings: print(json.dumps(email_phone_settings, indent=2, ensure_ascii=False)) else: print(" (keine Email/Phone-spezifischen Einstellungen)") except Exception as e: print(f" ❌ Error: {e}") # Prüfe Settings print(f"\n📋 System Settings:") try: settings = await espo.api_call('Settings') if settings: email_phone_settings = {k: v for k, v in settings.items() if 'email' in k.lower() or 'phone' in k.lower()} if email_phone_settings: print(json.dumps(email_phone_settings, indent=2, ensure_ascii=False)) except Exception as e: print(f" ❌ Error: {e}") async def main(): print("\n" + "="*70) print("DEEP DIVE: SUCHE NACH PHONENUMBER/EMAILADDRESS IDs") print("="*70) try: # Sehr detaillierte Inspektion await inspect_email_data_structure() # Rohe API-Calls await test_raw_api_call() # Link-Tables await search_for_link_table() # Update-Test (ohne tatsächlich zu updaten) await test_update_with_ids() # Config await check_database_or_config() print_section("FAZIT") print("\n🎯 Mögliche Szenarien:") print("\n1️⃣ IDs existieren NICHT in emailAddressData") print(" → Wert-basiertes Matching notwendig") print(" → Hybrid-Strategie (primary-Flag)") print("\n2️⃣ IDs existieren aber sind versteckt/nicht zugänglich") print(" → API-Rechte müssen erweitert werden") print(" → Admin muss emailAddresses/phoneNumbers Relationship freigeben") print("\n3️⃣ IDs können beim UPDATE gesetzt werden") print(" → Wir könnten eigene IDs generieren") print(" → Advoware-ID direkt als EspoCRM-ID nutzen") except Exception as e: print(f"\n❌ Fehler: {e}") import traceback traceback.print_exc() if __name__ == "__main__": asyncio.run(main())