feat: Implement VMH Bankverbindungen sync handlers and API steps for create, update, and delete operations
This commit is contained in:
@@ -1,25 +1,4 @@
|
||||
[
|
||||
{
|
||||
"id": "vmh",
|
||||
"config": {
|
||||
"steps/vmh/beteiligte_sync_event_step.py": {
|
||||
"x": 805,
|
||||
"y": 188
|
||||
},
|
||||
"steps/vmh/webhook/beteiligte_update_api_step.py": {
|
||||
"x": 13,
|
||||
"y": 154
|
||||
},
|
||||
"steps/vmh/webhook/beteiligte_delete_api_step.py": {
|
||||
"x": 14,
|
||||
"y": -72
|
||||
},
|
||||
"steps/vmh/webhook/beteiligte_create_api_step.py": {
|
||||
"x": 7,
|
||||
"y": 373
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "advoware_cal_sync",
|
||||
"config": {
|
||||
@@ -107,5 +86,42 @@
|
||||
"y": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "vmh",
|
||||
"config": {
|
||||
"steps/vmh/beteiligte_sync_event_step.py": {
|
||||
"x": 805,
|
||||
"y": 188
|
||||
},
|
||||
"steps/vmh/bankverbindungen_sync_event_step.py": {
|
||||
"x": 350,
|
||||
"y": 1006
|
||||
},
|
||||
"steps/vmh/webhook/beteiligte_update_api_step.py": {
|
||||
"x": 13,
|
||||
"y": 154
|
||||
},
|
||||
"steps/vmh/webhook/beteiligte_delete_api_step.py": {
|
||||
"x": 14,
|
||||
"y": -72
|
||||
},
|
||||
"steps/vmh/webhook/beteiligte_create_api_step.py": {
|
||||
"x": 7,
|
||||
"y": 373
|
||||
},
|
||||
"steps/vmh/webhook/bankverbindungen_update_api_step.py": {
|
||||
"x": 0,
|
||||
"y": 729
|
||||
},
|
||||
"steps/vmh/webhook/bankverbindungen_delete_api_step.py": {
|
||||
"x": 0,
|
||||
"y": 972
|
||||
},
|
||||
"steps/vmh/webhook/bankverbindungen_create_api_step.py": {
|
||||
"x": 0,
|
||||
"y": 1215
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
174
bitbylaw/services/bankverbindungen_mapper.py
Normal file
174
bitbylaw/services/bankverbindungen_mapper.py
Normal file
@@ -0,0 +1,174 @@
|
||||
"""
|
||||
EspoCRM ↔ Advoware Bankverbindungen Mapper
|
||||
|
||||
Transformiert Bankverbindungen zwischen den beiden Systemen
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional, List
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BankverbindungenMapper:
|
||||
"""Mapper für CBankverbindungen (EspoCRM) ↔ Bankverbindung (Advoware)"""
|
||||
|
||||
@staticmethod
|
||||
def map_cbankverbindungen_to_advoware(espo_entity: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Transformiert EspoCRM CBankverbindungen → Advoware Bankverbindung Format
|
||||
|
||||
Args:
|
||||
espo_entity: CBankverbindungen Entity von EspoCRM
|
||||
|
||||
Returns:
|
||||
Dict für Advoware API (POST/PUT /api/v1/advonet/Beteiligte/{id}/Bankverbindungen)
|
||||
"""
|
||||
logger.debug(f"Mapping EspoCRM → Advoware Bankverbindung: {espo_entity.get('id')}")
|
||||
|
||||
advo_data = {}
|
||||
|
||||
# Bankname
|
||||
bank = espo_entity.get('bank')
|
||||
if bank:
|
||||
advo_data['bank'] = bank
|
||||
|
||||
# Kontonummer (deprecated, aber noch supported)
|
||||
kto_nr = espo_entity.get('kontoNummer')
|
||||
if kto_nr:
|
||||
advo_data['ktoNr'] = kto_nr
|
||||
|
||||
# BLZ (deprecated, aber noch supported)
|
||||
blz = espo_entity.get('blz')
|
||||
if blz:
|
||||
advo_data['blz'] = blz
|
||||
|
||||
# IBAN
|
||||
iban = espo_entity.get('iban')
|
||||
if iban:
|
||||
advo_data['iban'] = iban
|
||||
|
||||
# BIC
|
||||
bic = espo_entity.get('bic')
|
||||
if bic:
|
||||
advo_data['bic'] = bic
|
||||
|
||||
# Kontoinhaber
|
||||
kontoinhaber = espo_entity.get('kontoinhaber')
|
||||
if kontoinhaber:
|
||||
advo_data['kontoinhaber'] = kontoinhaber
|
||||
|
||||
# SEPA Mandat
|
||||
mandatsreferenz = espo_entity.get('mandatsreferenz')
|
||||
if mandatsreferenz:
|
||||
advo_data['mandatsreferenz'] = mandatsreferenz
|
||||
|
||||
mandat_vom = espo_entity.get('mandatVom')
|
||||
if mandat_vom:
|
||||
advo_data['mandatVom'] = mandat_vom
|
||||
|
||||
logger.debug(f"Mapped to Advoware: IBAN={advo_data.get('iban')}, Bank={advo_data.get('bank')}")
|
||||
|
||||
return advo_data
|
||||
|
||||
@staticmethod
|
||||
def map_advoware_to_cbankverbindungen(advo_entity: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Transformiert Advoware Bankverbindung → EspoCRM CBankverbindungen Format
|
||||
|
||||
Args:
|
||||
advo_entity: Bankverbindung von Advoware API
|
||||
|
||||
Returns:
|
||||
Dict für EspoCRM API (POST/PUT /api/v1/CBankverbindungen)
|
||||
"""
|
||||
logger.debug(f"Mapping Advoware → EspoCRM: id={advo_entity.get('id')}")
|
||||
|
||||
espo_data = {
|
||||
'advowareId': advo_entity.get('id'), # Link zu Advoware
|
||||
'advowareRowId': advo_entity.get('rowId'), # Änderungserkennung
|
||||
}
|
||||
|
||||
# Bankname
|
||||
bank = advo_entity.get('bank')
|
||||
if bank:
|
||||
espo_data['bank'] = bank
|
||||
|
||||
# Kontonummer
|
||||
kto_nr = advo_entity.get('ktoNr')
|
||||
if kto_nr:
|
||||
espo_data['kontoNummer'] = kto_nr
|
||||
|
||||
# BLZ
|
||||
blz = advo_entity.get('blz')
|
||||
if blz:
|
||||
espo_data['blz'] = blz
|
||||
|
||||
# IBAN
|
||||
iban = advo_entity.get('iban')
|
||||
if iban:
|
||||
espo_data['iban'] = iban
|
||||
|
||||
# BIC
|
||||
bic = advo_entity.get('bic')
|
||||
if bic:
|
||||
espo_data['bic'] = bic
|
||||
|
||||
# Kontoinhaber
|
||||
kontoinhaber = advo_entity.get('kontoinhaber')
|
||||
if kontoinhaber:
|
||||
espo_data['kontoinhaber'] = kontoinhaber
|
||||
|
||||
# SEPA Mandat
|
||||
mandatsreferenz = advo_entity.get('mandatsreferenz')
|
||||
if mandatsreferenz:
|
||||
espo_data['mandatsreferenz'] = mandatsreferenz
|
||||
|
||||
mandat_vom = advo_entity.get('mandatVom')
|
||||
if mandat_vom:
|
||||
# Konvertiere DateTime zu Date (EspoCRM Format: YYYY-MM-DD)
|
||||
espo_data['mandatVom'] = mandat_vom.split('T')[0] if 'T' in mandat_vom else mandat_vom
|
||||
|
||||
logger.debug(f"Mapped to EspoCRM: IBAN={espo_data.get('iban')}")
|
||||
|
||||
# Entferne None-Werte (EspoCRM Validierung)
|
||||
espo_data = {k: v for k, v in espo_data.items() if v is not None}
|
||||
|
||||
return espo_data
|
||||
|
||||
@staticmethod
|
||||
def get_changed_fields(espo_entity: Dict[str, Any], advo_entity: Dict[str, Any]) -> List[str]:
|
||||
"""
|
||||
Vergleicht zwei Entities und gibt Liste der geänderten Felder zurück
|
||||
|
||||
Args:
|
||||
espo_entity: EspoCRM CBankverbindungen
|
||||
advo_entity: Advoware Bankverbindung
|
||||
|
||||
Returns:
|
||||
Liste von Feldnamen die unterschiedlich sind
|
||||
"""
|
||||
mapped_advo = BankverbindungenMapper.map_advoware_to_cbankverbindungen(advo_entity)
|
||||
|
||||
changed = []
|
||||
|
||||
compare_fields = [
|
||||
'bank', 'iban', 'bic', 'kontoNummer', 'blz',
|
||||
'kontoinhaber', 'mandatsreferenz', 'mandatVom',
|
||||
'advowareId', 'advowareRowId'
|
||||
]
|
||||
|
||||
for field in compare_fields:
|
||||
espo_val = espo_entity.get(field)
|
||||
advo_val = mapped_advo.get(field)
|
||||
|
||||
# Normalisiere None und leere Strings
|
||||
espo_val = espo_val if espo_val else None
|
||||
advo_val = advo_val if advo_val else None
|
||||
|
||||
if espo_val != advo_val:
|
||||
changed.append(field)
|
||||
logger.debug(f"Field '{field}' changed: EspoCRM='{espo_val}' vs Advoware='{advo_val}'")
|
||||
|
||||
return changed
|
||||
251
bitbylaw/steps/vmh/bankverbindungen_sync_event_step.py
Normal file
251
bitbylaw/steps/vmh/bankverbindungen_sync_event_step.py
Normal file
@@ -0,0 +1,251 @@
|
||||
from services.advoware import AdvowareAPI
|
||||
from services.espocrm import EspoCRMAPI
|
||||
from services.bankverbindungen_mapper import BankverbindungenMapper
|
||||
from services.beteiligte_sync_utils import BeteiligteSync
|
||||
import json
|
||||
import redis
|
||||
from config import Config
|
||||
|
||||
config = {
|
||||
'type': 'event',
|
||||
'name': 'VMH Bankverbindungen Sync Handler',
|
||||
'description': 'Zentraler Sync-Handler für Bankverbindungen (Webhooks + Cron Events)',
|
||||
'subscribes': [
|
||||
'vmh.bankverbindungen.create',
|
||||
'vmh.bankverbindungen.update',
|
||||
'vmh.bankverbindungen.delete',
|
||||
'vmh.bankverbindungen.sync_check'
|
||||
],
|
||||
'flows': ['vmh'],
|
||||
'emits': []
|
||||
}
|
||||
|
||||
async def handler(event_data, context):
|
||||
"""
|
||||
Zentraler Sync-Handler für Bankverbindungen
|
||||
|
||||
Verarbeitet:
|
||||
- vmh.bankverbindungen.create: Neu in EspoCRM → Create in Advoware
|
||||
- vmh.bankverbindungen.update: Geändert in EspoCRM → Update in Advoware
|
||||
- vmh.bankverbindungen.delete: Gelöscht in EspoCRM → Delete in Advoware
|
||||
- vmh.bankverbindungen.sync_check: Cron-Check → Sync wenn nötig
|
||||
"""
|
||||
entity_id = event_data.get('entity_id')
|
||||
action = event_data.get('action', 'sync_check')
|
||||
source = event_data.get('source', 'unknown')
|
||||
|
||||
if not entity_id:
|
||||
context.logger.error("Keine entity_id im Event gefunden")
|
||||
return
|
||||
|
||||
context.logger.info(f"🔄 Bankverbindungen Sync gestartet: {action.upper()} | Entity: {entity_id} | Source: {source}")
|
||||
|
||||
# Shared Redis client
|
||||
redis_client = redis.Redis(
|
||||
host=Config.REDIS_HOST,
|
||||
port=int(Config.REDIS_PORT),
|
||||
db=int(Config.REDIS_DB_ADVOWARE_CACHE),
|
||||
decode_responses=True
|
||||
)
|
||||
|
||||
# APIs initialisieren
|
||||
espocrm = EspoCRMAPI()
|
||||
advoware = AdvowareAPI(context)
|
||||
sync_utils = BeteiligteSync(espocrm, redis_client, context) # Reuse utils
|
||||
mapper = BankverbindungenMapper()
|
||||
|
||||
try:
|
||||
# 1. ACQUIRE LOCK
|
||||
lock_key = f"sync_lock:cbankverbindungen:{entity_id}"
|
||||
acquired = redis_client.set(lock_key, "locked", nx=True, ex=900) # 15min TTL
|
||||
|
||||
if not acquired:
|
||||
context.logger.warn(f"⏸️ Sync bereits aktiv für {entity_id}, überspringe")
|
||||
return
|
||||
|
||||
# 2. FETCH ENTITY VON ESPOCRM
|
||||
try:
|
||||
espo_entity = await espocrm.get_entity('CBankverbindungen', entity_id)
|
||||
except Exception as e:
|
||||
context.logger.error(f"❌ Fehler beim Laden von EspoCRM Entity: {e}")
|
||||
redis_client.delete(lock_key)
|
||||
return
|
||||
|
||||
context.logger.info(f"📋 Entity geladen: {espo_entity.get('name', 'Unbenannt')} (IBAN: {espo_entity.get('iban', 'N/A')})")
|
||||
|
||||
advoware_id = espo_entity.get('advowareId')
|
||||
beteiligte_id = espo_entity.get('cBeteiligteId') # Parent Beteiligter
|
||||
|
||||
if not beteiligte_id:
|
||||
context.logger.error(f"❌ Keine cBeteiligteId gefunden - Bankverbindung muss einem Beteiligten zugeordnet sein")
|
||||
redis_client.delete(lock_key)
|
||||
return
|
||||
|
||||
# Hole betNr vom Parent
|
||||
parent = await espocrm.get_entity('CBeteiligte', beteiligte_id)
|
||||
betnr = parent.get('betnr')
|
||||
|
||||
if not betnr:
|
||||
context.logger.error(f"❌ Parent Beteiligter {beteiligte_id} hat keine betNr")
|
||||
redis_client.delete(lock_key)
|
||||
return
|
||||
|
||||
# 3. BESTIMME SYNC-AKTION
|
||||
|
||||
# FALL A: Neu (kein advowareId) → CREATE in Advoware
|
||||
if not advoware_id and action in ['create', 'sync_check']:
|
||||
await handle_create(entity_id, betnr, espo_entity, espocrm, advoware, mapper, context, redis_client, lock_key)
|
||||
|
||||
# FALL B: Existiert (hat advowareId) → UPDATE oder CHECK
|
||||
elif advoware_id:
|
||||
await handle_update(entity_id, betnr, advoware_id, espo_entity, espocrm, advoware, mapper, context, redis_client, lock_key)
|
||||
|
||||
# FALL C: DELETE
|
||||
elif action == 'delete':
|
||||
await handle_delete(entity_id, betnr, advoware_id, espocrm, advoware, context, redis_client, lock_key)
|
||||
|
||||
else:
|
||||
context.logger.warn(f"⚠️ Unbekannte Kombination: action={action}, advowareId={advoware_id}")
|
||||
redis_client.delete(lock_key)
|
||||
|
||||
except Exception as e:
|
||||
context.logger.error(f"❌ Unerwarteter Fehler im Sync-Handler: {e}")
|
||||
import traceback
|
||||
context.logger.error(traceback.format_exc())
|
||||
|
||||
try:
|
||||
redis_client.delete(lock_key)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
async def handle_create(entity_id, betnr, espo_entity, espocrm, advoware, mapper, context, redis_client, lock_key):
|
||||
"""Erstellt neue Bankverbindung in Advoware"""
|
||||
try:
|
||||
context.logger.info(f"🔨 CREATE Bankverbindung in Advoware für Beteiligter {betnr}...")
|
||||
|
||||
advo_data = mapper.map_cbankverbindungen_to_advoware(espo_entity)
|
||||
|
||||
context.logger.info(f"📤 Sende an Advoware: {json.dumps(advo_data, ensure_ascii=False)[:200]}...")
|
||||
|
||||
# POST zu Advoware (Beteiligten-spezifischer Endpoint!)
|
||||
result = await advoware.api_call(
|
||||
f'api/v1/advonet/Beteiligte/{betnr}/Bankverbindungen',
|
||||
method='POST',
|
||||
data=advo_data
|
||||
)
|
||||
|
||||
# Extrahiere ID und rowId
|
||||
if isinstance(result, list) and len(result) > 0:
|
||||
new_entity = result[0]
|
||||
elif isinstance(result, dict):
|
||||
new_entity = result
|
||||
else:
|
||||
raise Exception(f"Unexpected response format: {result}")
|
||||
|
||||
new_id = new_entity.get('id')
|
||||
new_rowid = new_entity.get('rowId')
|
||||
|
||||
if not new_id:
|
||||
raise Exception(f"Keine ID in Advoware Response: {result}")
|
||||
|
||||
context.logger.info(f"✅ In Advoware erstellt: ID={new_id}, rowId={new_rowid[:20] if new_rowid else 'N/A'}...")
|
||||
|
||||
# Schreibe advowareId + rowId zurück
|
||||
await espocrm.update_entity('CBankverbindungen', entity_id, {
|
||||
'advowareId': new_id,
|
||||
'advowareRowId': new_rowid
|
||||
})
|
||||
|
||||
redis_client.delete(lock_key)
|
||||
context.logger.info(f"✅ CREATE erfolgreich: {entity_id} → Advoware ID {new_id}")
|
||||
|
||||
except Exception as e:
|
||||
context.logger.error(f"❌ CREATE fehlgeschlagen: {e}")
|
||||
redis_client.delete(lock_key)
|
||||
|
||||
|
||||
async def handle_update(entity_id, betnr, advoware_id, espo_entity, espocrm, advoware, mapper, context, redis_client, lock_key):
|
||||
"""Update nicht möglich - Sendet Notification an User"""
|
||||
try:
|
||||
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')
|
||||
bank = espo_entity.get('bank', 'N/A')
|
||||
|
||||
notification_message = (
|
||||
f"Bankverbindung wurde in EspoCRM geändert, aber die Advoware API unterstützt keine Updates.\n\n"
|
||||
f"**Bitte manuell in Advoware aktualisieren:**\n"
|
||||
f"- Bank: {bank}\n"
|
||||
f"- IBAN: {iban}\n"
|
||||
f"- Beteiligter betNr: {betnr}\n"
|
||||
f"- Advoware ID: {advoware_id}\n\n"
|
||||
f"**Workaround:** Löschen und neu erstellen in EspoCRM, dann wird neue Bankverbindung in Advoware angelegt."
|
||||
)
|
||||
|
||||
# Sende Notification via EspoCRM API
|
||||
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)
|
||||
|
||||
except Exception as e:
|
||||
context.logger.error(f"❌ UPDATE Notification fehlgeschlagen: {e}")
|
||||
import traceback
|
||||
context.logger.error(traceback.format_exc())
|
||||
redis_client.delete(lock_key)
|
||||
|
||||
|
||||
async def handle_delete(entity_id, betnr, advoware_id, espocrm, advoware, context, redis_client, lock_key):
|
||||
"""Delete nicht möglich - Sendet Notification an User"""
|
||||
try:
|
||||
context.logger.warn(f"⚠️ DELETE: Advoware API unterstützt kein DELETE für Bankverbindungen")
|
||||
|
||||
if not advoware_id:
|
||||
context.logger.info(f"ℹ️ Keine advowareId vorhanden, nur EspoCRM-seitiges Delete")
|
||||
redis_client.delete(lock_key)
|
||||
return
|
||||
|
||||
# Hole Entity-Details für Notification (vor dem Delete)
|
||||
try:
|
||||
espo_entity = await espocrm.get_entity('CBankverbindungen', entity_id)
|
||||
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
|
||||
notification_message = (
|
||||
f"Bankverbindung wurde in EspoCRM gelöscht, aber die Advoware API unterstützt keine Löschungen.\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 bleibt in Advoware bestehen bis zur manuellen Löschung."
|
||||
)
|
||||
|
||||
# Sende Notification
|
||||
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)
|
||||
|
||||
except Exception as e:
|
||||
context.logger.error(f"❌ DELETE Notification fehlgeschlagen: {e}")
|
||||
redis_client.delete(lock_key)
|
||||
@@ -0,0 +1,61 @@
|
||||
import json
|
||||
import datetime
|
||||
|
||||
config = {
|
||||
'type': 'api',
|
||||
'name': 'VMH Webhook Bankverbindungen Create',
|
||||
'description': 'Empfängt Create-Webhooks von EspoCRM für Bankverbindungen',
|
||||
'path': '/vmh/webhook/bankverbindungen/create',
|
||||
'method': 'POST',
|
||||
'flows': ['vmh'],
|
||||
'emits': ['vmh.bankverbindungen.create']
|
||||
}
|
||||
|
||||
async def handler(req, context):
|
||||
try:
|
||||
payload = req.get('body', [])
|
||||
|
||||
context.logger.info("VMH Webhook Bankverbindungen Create empfangen")
|
||||
context.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||
|
||||
# Sammle alle IDs aus dem Batch
|
||||
entity_ids = set()
|
||||
|
||||
if isinstance(payload, list):
|
||||
for entity in payload:
|
||||
if isinstance(entity, dict) and 'id' in entity:
|
||||
entity_ids.add(entity['id'])
|
||||
elif isinstance(payload, dict) and 'id' in payload:
|
||||
entity_ids.add(payload['id'])
|
||||
|
||||
context.logger.info(f"{len(entity_ids)} IDs zum Create-Sync gefunden")
|
||||
|
||||
# Emittiere Events
|
||||
for entity_id in entity_ids:
|
||||
await context.emit({
|
||||
'topic': 'vmh.bankverbindungen.create',
|
||||
'data': {
|
||||
'entity_id': entity_id,
|
||||
'action': 'create',
|
||||
'source': 'webhook',
|
||||
'timestamp': req.get('timestamp') or datetime.datetime.now().isoformat()
|
||||
}
|
||||
})
|
||||
|
||||
context.logger.info(f"VMH Create Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
||||
|
||||
return {
|
||||
'status': 200,
|
||||
'body': {
|
||||
'status': 'received',
|
||||
'action': 'create',
|
||||
'ids_count': len(entity_ids)
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
context.logger.error(f"Fehler beim Verarbeiten des VMH Create Webhooks: {e}")
|
||||
return {
|
||||
'status': 500,
|
||||
'body': {'error': str(e)}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import json
|
||||
import datetime
|
||||
|
||||
config = {
|
||||
'type': 'api',
|
||||
'name': 'VMH Webhook Bankverbindungen Delete',
|
||||
'description': 'Empfängt Delete-Webhooks von EspoCRM für Bankverbindungen',
|
||||
'path': '/vmh/webhook/bankverbindungen/delete',
|
||||
'method': 'POST',
|
||||
'flows': ['vmh'],
|
||||
'emits': ['vmh.bankverbindungen.delete']
|
||||
}
|
||||
|
||||
async def handler(req, context):
|
||||
try:
|
||||
payload = req.get('body', [])
|
||||
|
||||
context.logger.info("VMH Webhook Bankverbindungen Delete empfangen")
|
||||
context.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||
|
||||
# Sammle alle IDs
|
||||
entity_ids = set()
|
||||
|
||||
if isinstance(payload, list):
|
||||
for entity in payload:
|
||||
if isinstance(entity, dict) and 'id' in entity:
|
||||
entity_ids.add(entity['id'])
|
||||
elif isinstance(payload, dict) and 'id' in payload:
|
||||
entity_ids.add(payload['id'])
|
||||
|
||||
context.logger.info(f"{len(entity_ids)} IDs zum Delete-Sync gefunden")
|
||||
|
||||
# Emittiere Events
|
||||
for entity_id in entity_ids:
|
||||
await context.emit({
|
||||
'topic': 'vmh.bankverbindungen.delete',
|
||||
'data': {
|
||||
'entity_id': entity_id,
|
||||
'action': 'delete',
|
||||
'source': 'webhook',
|
||||
'timestamp': req.get('timestamp') or datetime.datetime.now().isoformat()
|
||||
}
|
||||
})
|
||||
|
||||
context.logger.info(f"VMH Delete Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
||||
|
||||
return {
|
||||
'status': 200,
|
||||
'body': {
|
||||
'status': 'received',
|
||||
'action': 'delete',
|
||||
'ids_count': len(entity_ids)
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
context.logger.error(f"Fehler beim Verarbeiten des VMH Delete Webhooks: {e}")
|
||||
return {
|
||||
'status': 500,
|
||||
'body': {'error': str(e)}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import json
|
||||
import datetime
|
||||
|
||||
config = {
|
||||
'type': 'api',
|
||||
'name': 'VMH Webhook Bankverbindungen Update',
|
||||
'description': 'Empfängt Update-Webhooks von EspoCRM für Bankverbindungen',
|
||||
'path': '/vmh/webhook/bankverbindungen/update',
|
||||
'method': 'POST',
|
||||
'flows': ['vmh'],
|
||||
'emits': ['vmh.bankverbindungen.update']
|
||||
}
|
||||
|
||||
async def handler(req, context):
|
||||
try:
|
||||
payload = req.get('body', [])
|
||||
|
||||
context.logger.info("VMH Webhook Bankverbindungen Update empfangen")
|
||||
context.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||
|
||||
# Sammle alle IDs
|
||||
entity_ids = set()
|
||||
|
||||
if isinstance(payload, list):
|
||||
for entity in payload:
|
||||
if isinstance(entity, dict) and 'id' in entity:
|
||||
entity_ids.add(entity['id'])
|
||||
elif isinstance(payload, dict) and 'id' in payload:
|
||||
entity_ids.add(payload['id'])
|
||||
|
||||
context.logger.info(f"{len(entity_ids)} IDs zum Update-Sync gefunden")
|
||||
|
||||
# Emittiere Events
|
||||
for entity_id in entity_ids:
|
||||
await context.emit({
|
||||
'topic': 'vmh.bankverbindungen.update',
|
||||
'data': {
|
||||
'entity_id': entity_id,
|
||||
'action': 'update',
|
||||
'source': 'webhook',
|
||||
'timestamp': req.get('timestamp') or datetime.datetime.now().isoformat()
|
||||
}
|
||||
})
|
||||
|
||||
context.logger.info(f"VMH Update Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
||||
|
||||
return {
|
||||
'status': 200,
|
||||
'body': {
|
||||
'status': 'received',
|
||||
'action': 'update',
|
||||
'ids_count': len(entity_ids)
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
context.logger.error(f"Fehler beim Verarbeiten des VMH Update Webhooks: {e}")
|
||||
return {
|
||||
'status': 500,
|
||||
'body': {'error': str(e)}
|
||||
}
|
||||
4
bitbylaw/types.d.ts
vendored
4
bitbylaw/types.d.ts
vendored
@@ -13,9 +13,13 @@ declare module 'motia' {
|
||||
|
||||
interface Handlers {
|
||||
'VMH Beteiligte Sync Handler': EventHandler<never, never>
|
||||
'VMH Bankverbindungen Sync Handler': EventHandler<never, never>
|
||||
'VMH Webhook Beteiligte Update': ApiRouteHandler<Record<string, unknown>, unknown, { topic: 'vmh.beteiligte.update'; data: never }>
|
||||
'VMH Webhook Beteiligte Delete': ApiRouteHandler<Record<string, unknown>, unknown, { topic: 'vmh.beteiligte.delete'; data: never }>
|
||||
'VMH Webhook Beteiligte Create': ApiRouteHandler<Record<string, unknown>, unknown, { topic: 'vmh.beteiligte.create'; data: never }>
|
||||
'VMH Webhook Bankverbindungen Update': ApiRouteHandler<Record<string, unknown>, unknown, { topic: 'vmh.bankverbindungen.update'; data: never }>
|
||||
'VMH Webhook Bankverbindungen Delete': ApiRouteHandler<Record<string, unknown>, unknown, { topic: 'vmh.bankverbindungen.delete'; data: never }>
|
||||
'VMH Webhook Bankverbindungen Create': ApiRouteHandler<Record<string, unknown>, unknown, { topic: 'vmh.bankverbindungen.create'; data: never }>
|
||||
'Advoware Proxy PUT': ApiRouteHandler<Record<string, unknown>, unknown, never>
|
||||
'Advoware Proxy POST': ApiRouteHandler<Record<string, unknown>, unknown, never>
|
||||
'Advoware Proxy GET': ApiRouteHandler<Record<string, unknown>, unknown, never>
|
||||
|
||||
Reference in New Issue
Block a user