Files
motia/bitbylaw/services/advoware_service.py
bitbylaw ebbbf419ee feat: Implement bidirectional synchronization utilities for Advoware and EspoCRM communications
- Added KommunikationSyncManager class to handle synchronization logic.
- Implemented methods for loading data, computing diffs, and applying changes between Advoware and EspoCRM.
- Introduced 3-way diffing mechanism to intelligently resolve conflicts.
- Added helper methods for creating empty slots and detecting changes in communications.
- Enhanced logging for better traceability during synchronization processes.
2026-02-08 19:53:40 +00:00

122 lines
4.0 KiB
Python

"""
Advoware Service Wrapper für Kommunikation
Erweitert AdvowareAPI mit Kommunikation-spezifischen Methoden
"""
import asyncio
import logging
from typing import Dict, Any, Optional
from services.advoware import AdvowareAPI
logger = logging.getLogger(__name__)
class AdvowareService:
"""
Service-Layer für Advoware Kommunikation-Operations
Verwendet AdvowareAPI für API-Calls
"""
def __init__(self, context=None):
self.api = AdvowareAPI(context)
self.context = context
# ========== BETEILIGTE ==========
async def get_beteiligter(self, betnr: int) -> Optional[Dict]:
"""
Lädt Beteiligten mit Kommunikationen
Returns:
Beteiligte mit 'kommunikation' array
"""
try:
endpoint = f"api/v1/advonet/Beteiligte/{betnr}"
result = await self.api.api_call(endpoint, method='GET')
return result
except Exception as e:
logger.error(f"[ADVO] Fehler beim Laden von Beteiligte {betnr}: {e}", exc_info=True)
return None
# ========== KOMMUNIKATION ==========
async def create_kommunikation(self, betnr: int, data: Dict[str, Any]) -> Optional[Dict]:
"""
Erstellt neue Kommunikation
Args:
betnr: Beteiligten-Nummer
data: {
'tlf': str, # Required
'bemerkung': str, # Optional
'kommKz': int, # Required (1-12)
'online': bool # Optional
}
Returns:
Neue Kommunikation mit 'id'
"""
try:
endpoint = f"api/v1/advonet/Beteiligte/{betnr}/Kommunikationen"
result = await self.api.api_call(endpoint, method='POST', json_data=data)
if result:
logger.info(f"[ADVO] ✅ Created Kommunikation: betnr={betnr}, kommKz={data.get('kommKz')}")
return result
except Exception as e:
logger.error(f"[ADVO] Fehler beim Erstellen von Kommunikation: {e}", exc_info=True)
return None
async def update_kommunikation(self, betnr: int, komm_id: int, data: Dict[str, Any]) -> bool:
"""
Aktualisiert bestehende Kommunikation
Args:
betnr: Beteiligten-Nummer
komm_id: Kommunikation-ID
data: {
'tlf': str, # Optional
'bemerkung': str, # Optional
'online': bool # Optional
}
NOTE: kommKz ist READ-ONLY und kann nicht geändert werden
Returns:
True wenn erfolgreich
"""
try:
endpoint = f"api/v1/advonet/Beteiligte/{betnr}/Kommunikationen/{komm_id}"
await self.api.api_call(endpoint, method='PUT', json_data=data)
logger.info(f"[ADVO] ✅ Updated Kommunikation: betnr={betnr}, komm_id={komm_id}")
return True
except Exception as e:
logger.error(f"[ADVO] Fehler beim Update von Kommunikation: {e}", exc_info=True)
return False
def delete_kommunikation(self, betnr: int, komm_id: int) -> bool:
"""
Löscht Kommunikation (aktuell 403 Forbidden)
NOTE: DELETE ist in Advoware API deaktiviert
Verwende stattdessen: Leere Slots mit empty_slot_marker
Returns:
True wenn erfolgreich
"""
try:
endpoint = f"api/v1/advonet/Beteiligte/{betnr}/Kommunikationen/{komm_id}"
asyncio.run(self.api.api_call(endpoint, method='DELETE'))
logger.info(f"[ADVO] ✅ Deleted Kommunikation: betnr={betnr}, komm_id={komm_id}")
return True
except Exception as e:
# Expected: 403 Forbidden
logger.warning(f"[ADVO] DELETE not allowed (expected): {e}")
return False