Files
motia/bitbylaw/scripts/compare_beteiligte.py
bitbylaw e6ab22d5f4 feat: Add EspoCRM and Advoware integration for Beteiligte comparison
- Implemented `compare_beteiligte.py` script for comparing Beteiligte structures between EspoCRM and Advoware.
- Created `beteiligte_comparison_result.json` to store comparison results.
- Developed `EspoCRMAPI` service for handling API interactions with EspoCRM.
- Added comprehensive documentation for the EspoCRM API service.
- Included error handling and logging for API operations.
- Enhanced entity management with CRUD operations and search capabilities.
2026-02-07 14:42:58 +00:00

324 lines
11 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Helper-Script zum Vergleichen der Beteiligten-Strukturen zwischen Advoware und EspoCRM.
Usage:
python scripts/compare_beteiligte.py <entity_id_espocrm> [advoware_id]
Examples:
# Vergleiche EspoCRM Beteiligten (automatische Suche in Advoware)
python scripts/compare_beteiligte.py 64a3f2b8c9e1234567890abc
# Vergleiche mit spezifischer Advoware ID
python scripts/compare_beteiligte.py 64a3f2b8c9e1234567890abc 12345
"""
import sys
import asyncio
import json
import os
from pathlib import Path
# Add bitbylaw directory to path for imports
bitbylaw_dir = Path(__file__).parent.parent
sys.path.insert(0, str(bitbylaw_dir))
from services.espocrm import EspoCRMAPI
from services.advoware import AdvowareAPI
from config import Config
class SimpleContext:
"""Simple context for logging"""
class Logger:
def info(self, msg):
print(f"[INFO] {msg}")
def error(self, msg):
print(f"[ERROR] {msg}")
def debug(self, msg):
print(f"[DEBUG] {msg}")
def warning(self, msg):
print(f"[WARNING] {msg}")
def __init__(self):
self.logger = self.Logger()
async def fetch_from_espocrm(entity_id: str):
"""Fetch Beteiligter from EspoCRM"""
print("\n" + "="*80)
print("ESPOCRM - Fetching Beteiligter")
print("="*80)
context = SimpleContext()
espo = EspoCRMAPI(context=context)
try:
# Try different entity types that might contain Beteiligte
entity_types = ['CBeteiligte', 'Beteiligte', 'Contact', 'Account', 'Lead', 'CVmhErstgespraech', 'CVmhBeteiligte']
for entity_type in entity_types:
try:
print(f"\nTrying entity type: {entity_type}")
result = await espo.get_entity(entity_type, entity_id)
print(f"\n✓ Success! Found in {entity_type}")
print(f"\nEntity Structure:")
print("-" * 80)
print(json.dumps(result, indent=2, ensure_ascii=False))
return result
except Exception as e:
print(f" ✗ Not found in {entity_type}: {e}")
continue
print("\n✗ Entity not found in any known entity type")
return None
except Exception as e:
print(f"\n✗ Error fetching from EspoCRM: {e}")
return None
async def fetch_from_advoware(advoware_id: str = None, search_name: str = None):
"""Fetch Beteiligter from Advoware"""
print("\n" + "="*80)
print("ADVOWARE - Fetching Beteiligter")
print("="*80)
context = SimpleContext()
advo = AdvowareAPI(context=context)
try:
# Try to fetch by ID if provided
if advoware_id:
print(f"\nFetching by ID: {advoware_id}")
# Try correct Advoware endpoint
endpoints = [
f'/api/v1/advonet/Beteiligte/{advoware_id}',
]
for endpoint in endpoints:
try:
print(f" Trying endpoint: {endpoint}")
result = await advo.api_call(endpoint, method='GET')
if result:
# Advoware gibt oft Listen zurück, nehme erstes Element
if isinstance(result, list) and len(result) > 0:
result = result[0]
print(f"\n✓ Success! Found at {endpoint}")
print(f"\nEntity Structure:")
print("-" * 80)
print(json.dumps(result, indent=2, ensure_ascii=False))
return result
except Exception as e:
print(f" ✗ Not found at {endpoint}: {e}")
continue
# Try to search by name if EspoCRM data available
if search_name:
print(f"\nSearching by name: {search_name}")
search_endpoints = [
'/api/v1/advonet/Beteiligte',
]
for endpoint in search_endpoints:
try:
print(f" Trying endpoint: {endpoint}")
result = await advo.api_call(
endpoint,
method='GET',
params={'search': search_name, 'limit': 5}
)
if result and (isinstance(result, list) and len(result) > 0 or
isinstance(result, dict) and result.get('data')):
print(f"\n✓ Found {len(result) if isinstance(result, list) else len(result.get('data', []))} results")
print(f"\nSearch Results:")
print("-" * 80)
print(json.dumps(result, indent=2, ensure_ascii=False))
return result
except Exception as e:
print(f" ✗ Search failed at {endpoint}: {e}")
continue
print("\n✗ Entity not found in Advoware")
return None
except Exception as e:
print(f"\n✗ Error fetching from Advoware: {e}")
import traceback
traceback.print_exc()
return None
async def compare_structures(espo_data: dict, advo_data: dict):
"""Compare field structures between EspoCRM and Advoware"""
print("\n" + "="*80)
print("STRUCTURE COMPARISON")
print("="*80)
if not espo_data or not advo_data:
print("\n⚠ Cannot compare - missing data from one or both systems")
return
# Extract fields
espo_fields = set(espo_data.keys()) if isinstance(espo_data, dict) else set()
# Handle Advoware data structure (might be nested)
if isinstance(advo_data, dict):
if 'data' in advo_data:
advo_data = advo_data['data']
if isinstance(advo_data, list) and len(advo_data) > 0:
advo_data = advo_data[0]
advo_fields = set(advo_data.keys()) if isinstance(advo_data, dict) else set()
print(f"\nEspoCRM Fields ({len(espo_fields)}):")
print("-" * 40)
for field in sorted(espo_fields):
value = espo_data.get(field)
value_type = type(value).__name__
print(f" {field:<30} ({value_type})")
print(f"\nAdvoware Fields ({len(advo_fields)}):")
print("-" * 40)
for field in sorted(advo_fields):
value = advo_data.get(field)
value_type = type(value).__name__
print(f" {field:<30} ({value_type})")
# Find common fields (potential mappings)
common = espo_fields & advo_fields
espo_only = espo_fields - advo_fields
advo_only = advo_fields - espo_fields
print(f"\nCommon Fields ({len(common)}):")
print("-" * 40)
for field in sorted(common):
espo_val = espo_data.get(field)
advo_val = advo_data.get(field)
match = "" if espo_val == advo_val else ""
print(f" {match} {field}")
if espo_val != advo_val:
print(f" EspoCRM: {espo_val}")
print(f" Advoware: {advo_val}")
print(f"\nEspoCRM Only ({len(espo_only)}):")
print("-" * 40)
for field in sorted(espo_only):
print(f" {field}")
print(f"\nAdvoware Only ({len(advo_only)}):")
print("-" * 40)
for field in sorted(advo_only):
print(f" {field}")
# Suggest potential mappings based on field names
print(f"\nPotential Field Mappings:")
print("-" * 40)
mapping_suggestions = []
# Common name patterns
name_patterns = [
('name', 'name'),
('firstName', 'first_name'),
('lastName', 'last_name'),
('email', 'email'),
('emailAddress', 'email'),
('phone', 'phone'),
('phoneNumber', 'phone_number'),
('address', 'address'),
('street', 'street'),
('city', 'city'),
('postalCode', 'postal_code'),
('zipCode', 'postal_code'),
('country', 'country'),
]
for espo_field, advo_field in name_patterns:
if espo_field in espo_fields and advo_field in advo_fields:
mapping_suggestions.append((espo_field, advo_field))
print(f" {espo_field:<30}{advo_field}")
return {
'espo_fields': list(espo_fields),
'advo_fields': list(advo_fields),
'common': list(common),
'espo_only': list(espo_only),
'advo_only': list(advo_only),
'suggested_mappings': mapping_suggestions
}
async def main():
"""Main function"""
if len(sys.argv) < 2:
print(__doc__)
sys.exit(1)
espocrm_id = sys.argv[1]
advoware_id = sys.argv[2] if len(sys.argv) > 2 else None
print("\n" + "="*80)
print("BETEILIGTE STRUCTURE COMPARISON TOOL")
print("="*80)
print(f"\nEspoCRM Entity ID: {espocrm_id}")
if advoware_id:
print(f"Advoware ID: {advoware_id}")
# Check environment variables
print("\nEnvironment Check:")
print("-" * 40)
print(f"ESPOCRM_API_BASE_URL: {Config.ESPOCRM_API_BASE_URL}")
print(f"ESPOCRM_API_KEY: {'✓ Set' if Config.ESPOCRM_API_KEY else '✗ Missing'}")
print(f"ADVOWARE_API_BASE_URL: {Config.ADVOWARE_API_BASE_URL}")
print(f"ADVOWARE_API_KEY: {'✓ Set' if Config.ADVOWARE_API_KEY else '✗ Missing'}")
# Fetch from EspoCRM
espo_data = await fetch_from_espocrm(espocrm_id)
# Extract name for Advoware search
search_name = None
if espo_data:
search_name = (
espo_data.get('name') or
f"{espo_data.get('firstName', '')} {espo_data.get('lastName', '')}".strip() or
None
)
# Fetch from Advoware
advo_data = await fetch_from_advoware(advoware_id, search_name)
# Compare structures
if espo_data or advo_data:
comparison = await compare_structures(espo_data, advo_data)
# Save comparison to file
output_file = Path(__file__).parent / 'beteiligte_comparison_result.json'
with open(output_file, 'w', encoding='utf-8') as f:
json.dump({
'espocrm_data': espo_data,
'advoware_data': advo_data,
'comparison': comparison
}, f, indent=2, ensure_ascii=False)
print(f"\n\n{'='*80}")
print(f"Comparison saved to: {output_file}")
print(f"{'='*80}\n")
else:
print("\n⚠ No data available for comparison")
if __name__ == '__main__':
asyncio.run(main())