- 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.
324 lines
11 KiB
Python
Executable File
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())
|