feat: Integrate NotificationManager for handling notifications in sync operations
This commit is contained in:
@@ -16,6 +16,7 @@ import logging
|
|||||||
import redis
|
import redis
|
||||||
from config import Config
|
from config import Config
|
||||||
from services.espocrm import EspoCRMAPI
|
from services.espocrm import EspoCRMAPI
|
||||||
|
from services.notification_utils import NotificationManager
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ class BeteiligteSync:
|
|||||||
self.espocrm = espocrm_api
|
self.espocrm = espocrm_api
|
||||||
self.context = context
|
self.context = context
|
||||||
self.redis = redis_client or self._init_redis()
|
self.redis = redis_client or self._init_redis()
|
||||||
|
self.notification_manager = NotificationManager(espocrm_api=self.espocrm, context=context)
|
||||||
|
|
||||||
def _init_redis(self) -> redis.Redis:
|
def _init_redis(self) -> redis.Redis:
|
||||||
"""Initialize Redis client for distributed locking"""
|
"""Initialize Redis client for distributed locking"""
|
||||||
@@ -395,11 +397,11 @@ class BeteiligteSync:
|
|||||||
extra_data: Optional[Dict[str, Any]] = None
|
extra_data: Optional[Dict[str, Any]] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Sendet EspoCRM In-App Notification
|
Sendet EspoCRM Notification via NotificationManager
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
entity_id: CBeteiligte Entity ID
|
entity_id: CBeteiligte Entity ID
|
||||||
notification_type: "conflict" oder "deleted"
|
notification_type: "conflict", "deleted" oder "error"
|
||||||
extra_data: Zusätzliche Daten für Nachricht
|
extra_data: Zusätzliche Daten für Nachricht
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@@ -407,45 +409,58 @@ class BeteiligteSync:
|
|||||||
entity = await self.espocrm.get_entity('CBeteiligte', entity_id)
|
entity = await self.espocrm.get_entity('CBeteiligte', entity_id)
|
||||||
name = entity.get('name', 'Unbekannt')
|
name = entity.get('name', 'Unbekannt')
|
||||||
betnr = entity.get('betnr')
|
betnr = entity.get('betnr')
|
||||||
assigned_user = entity.get('assignedUserId')
|
|
||||||
|
|
||||||
# Erstelle Nachricht basierend auf Typ
|
# Map notification_type zu action_type
|
||||||
if notification_type == "conflict":
|
if notification_type == "conflict":
|
||||||
message = (
|
action_type = 'sync_conflict'
|
||||||
f"⚠️ Sync-Konflikt bei Beteiligten '{name}' (betNr: {betnr}). "
|
details = {
|
||||||
f"EspoCRM hat Vorrang - Änderungen wurden nach Advoware übertragen. "
|
'message': f"Sync-Konflikt bei Beteiligten '{name}' (betNr: {betnr})",
|
||||||
f"Bitte prüfen Sie die Details."
|
'description': (
|
||||||
)
|
f"EspoCRM hat Vorrang - Änderungen wurden nach Advoware übertragen.\n\n"
|
||||||
|
f"Bitte prüfen Sie die Details und stellen Sie sicher, dass die Daten korrekt sind."
|
||||||
|
),
|
||||||
|
'entity_name': name,
|
||||||
|
'betnr': betnr,
|
||||||
|
'priority': 'Normal'
|
||||||
|
}
|
||||||
elif notification_type == "deleted":
|
elif notification_type == "deleted":
|
||||||
deleted_at = entity.get('advowareDeletedAt', 'unbekannt')
|
deleted_at = entity.get('advowareDeletedAt', 'unbekannt')
|
||||||
message = (
|
action_type = 'entity_deleted_in_source'
|
||||||
f"🗑️ Beteiligter '{name}' (betNr: {betnr}) wurde in Advoware gelöscht "
|
details = {
|
||||||
f"(am {deleted_at}). Der Datensatz wurde in EspoCRM markiert, aber nicht gelöscht. "
|
'message': f"Beteiligter '{name}' wurde in Advoware gelöscht",
|
||||||
f"Bitte prüfen Sie, ob dies beabsichtigt war."
|
'description': (
|
||||||
)
|
f"Der Beteiligte '{name}' (betNr: {betnr}) wurde am {deleted_at} "
|
||||||
|
f"in Advoware gelöscht.\n\n"
|
||||||
|
f"Der Datensatz wurde in EspoCRM markiert, aber nicht gelöscht. "
|
||||||
|
f"Bitte prüfen Sie, ob dies beabsichtigt war."
|
||||||
|
),
|
||||||
|
'entity_name': name,
|
||||||
|
'betnr': betnr,
|
||||||
|
'deleted_at': deleted_at,
|
||||||
|
'priority': 'High'
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
message = f"Benachrichtigung für Beteiligten '{name}'"
|
action_type = 'general_manual_action'
|
||||||
|
details = {
|
||||||
|
'message': f"Benachrichtigung für Beteiligten '{name}'",
|
||||||
|
'entity_name': name,
|
||||||
|
'betnr': betnr
|
||||||
|
}
|
||||||
|
|
||||||
# Erstelle Notification in EspoCRM
|
# Merge extra_data if provided
|
||||||
notification_data = {
|
if extra_data:
|
||||||
'type': 'message',
|
details.update(extra_data)
|
||||||
'message': message,
|
|
||||||
'relatedType': 'CBeteiligte',
|
|
||||||
'relatedId': entity_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Wenn assigned user vorhanden, sende an diesen
|
# Sende via NotificationManager
|
||||||
if assigned_user:
|
await self.notification_manager.notify_manual_action_required(
|
||||||
notification_data['userId'] = assigned_user
|
entity_type='CBeteiligte',
|
||||||
|
entity_id=entity_id,
|
||||||
# Sende via API
|
action_type=action_type,
|
||||||
result = await self.espocrm.api_call(
|
details=details,
|
||||||
'Notification',
|
create_task=True
|
||||||
method='POST',
|
|
||||||
data=notification_data
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self._log(f"Notification gesendet für {entity_id}: {notification_type}")
|
self._log(f"Notification via NotificationManager gesendet: {notification_type} für {entity_id}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._log(f"Fehler beim Senden der Notification: {e}", level='error')
|
self._log(f"Fehler beim Senden der Notification: {e}", level='error')
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from services.advoware import AdvowareAPI
|
|||||||
from services.espocrm import EspoCRMAPI
|
from services.espocrm import EspoCRMAPI
|
||||||
from services.bankverbindungen_mapper import BankverbindungenMapper
|
from services.bankverbindungen_mapper import BankverbindungenMapper
|
||||||
from services.beteiligte_sync_utils import BeteiligteSync
|
from services.beteiligte_sync_utils import BeteiligteSync
|
||||||
|
from services.notification_utils import NotificationManager
|
||||||
import json
|
import json
|
||||||
import redis
|
import redis
|
||||||
from config import Config
|
from config import Config
|
||||||
@@ -53,6 +54,7 @@ async def handler(event_data, context):
|
|||||||
advoware = AdvowareAPI(context)
|
advoware = AdvowareAPI(context)
|
||||||
sync_utils = BeteiligteSync(espocrm, redis_client, context) # Reuse utils
|
sync_utils = BeteiligteSync(espocrm, redis_client, context) # Reuse utils
|
||||||
mapper = BankverbindungenMapper()
|
mapper = BankverbindungenMapper()
|
||||||
|
notification_mgr = NotificationManager(espocrm_api=espocrm, context=context)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 1. ACQUIRE LOCK
|
# 1. ACQUIRE LOCK
|
||||||
@@ -98,11 +100,11 @@ async def handler(event_data, context):
|
|||||||
|
|
||||||
# FALL B: Existiert (hat advowareId) → UPDATE oder CHECK
|
# FALL B: Existiert (hat advowareId) → UPDATE oder CHECK
|
||||||
elif advoware_id:
|
elif advoware_id:
|
||||||
await handle_update(entity_id, betnr, advoware_id, espo_entity, espocrm, advoware, mapper, context, redis_client, lock_key)
|
await handle_update(entity_id, betnr, advoware_id, espo_entity, espocrm, advoware, mapper, notification_mgr, context, redis_client, lock_key)
|
||||||
|
|
||||||
# FALL C: DELETE
|
# FALL C: DELETE
|
||||||
elif action == 'delete':
|
elif action == 'delete':
|
||||||
await handle_delete(entity_id, betnr, advoware_id, espocrm, advoware, context, redis_client, lock_key)
|
await handle_delete(entity_id, betnr, advoware_id, espo_entity, espocrm, advoware, notification_mgr, context, redis_client, lock_key)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
context.logger.warn(f"⚠️ Unbekannte Kombination: action={action}, advowareId={advoware_id}")
|
context.logger.warn(f"⚠️ Unbekannte Kombination: action={action}, advowareId={advoware_id}")
|
||||||
@@ -165,35 +167,44 @@ async def handle_create(entity_id, betnr, espo_entity, espocrm, advoware, mapper
|
|||||||
redis_client.delete(lock_key)
|
redis_client.delete(lock_key)
|
||||||
|
|
||||||
|
|
||||||
async def handle_update(entity_id, betnr, advoware_id, espo_entity, espocrm, advoware, mapper, context, redis_client, lock_key):
|
async def handle_update(entity_id, betnr, advoware_id, espo_entity, espocrm, advoware, mapper, notification_mgr, context, redis_client, lock_key):
|
||||||
"""Update nicht möglich - Sendet Notification an User"""
|
"""Update nicht möglich - Sendet Notification an User via NotificationManager"""
|
||||||
try:
|
try:
|
||||||
context.logger.warn(f"⚠️ UPDATE: Advoware API unterstützt kein PUT für Bankverbindungen")
|
context.logger.warn(f"⚠️ UPDATE: Advoware API unterstützt kein PUT für Bankverbindungen")
|
||||||
|
|
||||||
# Erstelle Notification für User in EspoCRM
|
|
||||||
iban = espo_entity.get('iban', 'N/A')
|
iban = espo_entity.get('iban', 'N/A')
|
||||||
bank = espo_entity.get('bank', 'N/A')
|
bank = espo_entity.get('bank', 'N/A')
|
||||||
|
name = espo_entity.get('name', 'Unbenannt')
|
||||||
|
|
||||||
notification_message = (
|
# Sende via NotificationManager
|
||||||
f"Bankverbindung wurde in EspoCRM geändert, aber die Advoware API unterstützt keine Updates.\n\n"
|
await notification_mgr.notify_manual_action_required(
|
||||||
f"**Bitte manuell in Advoware aktualisieren:**\n"
|
entity_type='CBankverbindungen',
|
||||||
f"- Bank: {bank}\n"
|
entity_id=entity_id,
|
||||||
f"- IBAN: {iban}\n"
|
action_type='api_limitation',
|
||||||
f"- Beteiligter betNr: {betnr}\n"
|
details={
|
||||||
f"- Advoware ID: {advoware_id}\n\n"
|
'message': f'UPDATE nicht möglich für Bankverbindung: {name}',
|
||||||
f"**Workaround:** Löschen und neu erstellen in EspoCRM, dann wird neue Bankverbindung in Advoware angelegt."
|
'description': (
|
||||||
|
f"Die Advoware API unterstützt keine Updates für Bankverbindungen.\n\n"
|
||||||
|
f"**Details:**\n"
|
||||||
|
f"- Bank: {bank}\n"
|
||||||
|
f"- IBAN: {iban}\n"
|
||||||
|
f"- Beteiligter betNr: {betnr}\n"
|
||||||
|
f"- Advoware ID: {advoware_id}\n\n"
|
||||||
|
f"**Workaround:**\n"
|
||||||
|
f"Löschen Sie die Bankverbindung in EspoCRM und erstellen Sie sie neu. "
|
||||||
|
f"Die neue Bankverbindung wird dann automatisch in Advoware angelegt."
|
||||||
|
),
|
||||||
|
'entity_name': name,
|
||||||
|
'iban': iban,
|
||||||
|
'bank': bank,
|
||||||
|
'betnr': betnr,
|
||||||
|
'advoware_id': advoware_id,
|
||||||
|
'priority': 'Normal'
|
||||||
|
},
|
||||||
|
create_task=True
|
||||||
)
|
)
|
||||||
|
|
||||||
# Sende Notification via EspoCRM API
|
context.logger.info(f"📧 Notification via NotificationManager gesendet: Update-Limitation")
|
||||||
await espocrm.api_call('/Notification', method='POST', json_data={
|
|
||||||
'type': 'message',
|
|
||||||
'message': notification_message,
|
|
||||||
'userId': espo_entity.get('createdById') or espo_entity.get('modifiedById'),
|
|
||||||
'relatedType': 'CBankverbindungen',
|
|
||||||
'relatedId': entity_id
|
|
||||||
})
|
|
||||||
|
|
||||||
context.logger.info(f"📧 Notification an User gesendet: Manuelle Aktualisierung erforderlich")
|
|
||||||
redis_client.delete(lock_key)
|
redis_client.delete(lock_key)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -203,8 +214,8 @@ async def handle_update(entity_id, betnr, advoware_id, espo_entity, espocrm, adv
|
|||||||
redis_client.delete(lock_key)
|
redis_client.delete(lock_key)
|
||||||
|
|
||||||
|
|
||||||
async def handle_delete(entity_id, betnr, advoware_id, espocrm, advoware, context, redis_client, lock_key):
|
async def handle_delete(entity_id, betnr, advoware_id, espo_entity, espocrm, advoware, notification_mgr, context, redis_client, lock_key):
|
||||||
"""Delete nicht möglich - Sendet Notification an User"""
|
"""Delete nicht möglich - Sendet Notification an User via NotificationManager"""
|
||||||
try:
|
try:
|
||||||
context.logger.warn(f"⚠️ DELETE: Advoware API unterstützt kein DELETE für Bankverbindungen")
|
context.logger.warn(f"⚠️ DELETE: Advoware API unterstützt kein DELETE für Bankverbindungen")
|
||||||
|
|
||||||
@@ -213,37 +224,38 @@ async def handle_delete(entity_id, betnr, advoware_id, espocrm, advoware, contex
|
|||||||
redis_client.delete(lock_key)
|
redis_client.delete(lock_key)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Hole Entity-Details für Notification (vor dem Delete)
|
iban = espo_entity.get('iban', 'N/A')
|
||||||
try:
|
bank = espo_entity.get('bank', 'N/A')
|
||||||
espo_entity = await espocrm.get_entity('CBankverbindungen', entity_id)
|
name = espo_entity.get('name', 'Unbenannt')
|
||||||
iban = espo_entity.get('iban', 'N/A')
|
|
||||||
bank = espo_entity.get('bank', 'N/A')
|
|
||||||
user_id = espo_entity.get('createdById') or espo_entity.get('modifiedById')
|
|
||||||
except:
|
|
||||||
iban = 'N/A'
|
|
||||||
bank = 'N/A'
|
|
||||||
user_id = None
|
|
||||||
|
|
||||||
# Erstelle Notification für User in EspoCRM
|
# Sende via NotificationManager
|
||||||
notification_message = (
|
await notification_mgr.notify_manual_action_required(
|
||||||
f"Bankverbindung wurde in EspoCRM gelöscht, aber die Advoware API unterstützt keine Löschungen.\n\n"
|
entity_type='CBankverbindungen',
|
||||||
f"**Bitte manuell in Advoware löschen:**\n"
|
entity_id=entity_id,
|
||||||
f"- Bank: {bank}\n"
|
action_type='delete_not_supported',
|
||||||
f"- IBAN: {iban}\n"
|
details={
|
||||||
f"- Beteiligter betNr: {betnr}\n"
|
'message': f'DELETE erforderlich für Bankverbindung: {name}',
|
||||||
f"- Advoware ID: {advoware_id}\n\n"
|
'description': (
|
||||||
f"Die Bankverbindung bleibt in Advoware bestehen bis zur manuellen Löschung."
|
f"Die Advoware API unterstützt keine Löschungen für Bankverbindungen.\n\n"
|
||||||
|
f"**Bitte manuell in Advoware löschen:**\n"
|
||||||
|
f"- Bank: {bank}\n"
|
||||||
|
f"- IBAN: {iban}\n"
|
||||||
|
f"- Beteiligter betNr: {betnr}\n"
|
||||||
|
f"- Advoware ID: {advoware_id}\n\n"
|
||||||
|
f"Die Bankverbindung wurde in EspoCRM gelöscht, bleibt aber in Advoware "
|
||||||
|
f"bestehen bis zur manuellen Löschung."
|
||||||
|
),
|
||||||
|
'entity_name': name,
|
||||||
|
'iban': iban,
|
||||||
|
'bank': bank,
|
||||||
|
'betnr': betnr,
|
||||||
|
'advoware_id': advoware_id,
|
||||||
|
'priority': 'Normal'
|
||||||
|
},
|
||||||
|
create_task=True
|
||||||
)
|
)
|
||||||
|
|
||||||
# Sende Notification
|
context.logger.info(f"📧 Notification via NotificationManager gesendet: Delete erforderlich")
|
||||||
if user_id:
|
|
||||||
await espocrm.api_call('/Notification', method='POST', json_data={
|
|
||||||
'type': 'message',
|
|
||||||
'message': notification_message,
|
|
||||||
'userId': user_id
|
|
||||||
})
|
|
||||||
|
|
||||||
context.logger.info(f"📧 Notification an User gesendet: Manuelle Löschung erforderlich")
|
|
||||||
redis_client.delete(lock_key)
|
redis_client.delete(lock_key)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user