From 68c8b398aa86fced3b779e85df0a030e25eb513d Mon Sep 17 00:00:00 2001 From: bitbylaw Date: Sun, 8 Feb 2026 12:49:14 +0000 Subject: [PATCH] feat: Implement VMH Bankverbindungen sync handlers and API steps for create, update, and delete operations --- bitbylaw/motia-workbench.json | 58 ++-- bitbylaw/services/bankverbindungen_mapper.py | 174 ++++++++++++ .../vmh/bankverbindungen_sync_event_step.py | 251 ++++++++++++++++++ .../bankverbindungen_create_api_step.py | 61 +++++ .../bankverbindungen_delete_api_step.py | 61 +++++ .../bankverbindungen_update_api_step.py | 61 +++++ bitbylaw/types.d.ts | 4 + 7 files changed, 649 insertions(+), 21 deletions(-) create mode 100644 bitbylaw/services/bankverbindungen_mapper.py create mode 100644 bitbylaw/steps/vmh/bankverbindungen_sync_event_step.py create mode 100644 bitbylaw/steps/vmh/webhook/bankverbindungen_create_api_step.py create mode 100644 bitbylaw/steps/vmh/webhook/bankverbindungen_delete_api_step.py create mode 100644 bitbylaw/steps/vmh/webhook/bankverbindungen_update_api_step.py diff --git a/bitbylaw/motia-workbench.json b/bitbylaw/motia-workbench.json index b150ad32..9775f23f 100644 --- a/bitbylaw/motia-workbench.json +++ b/bitbylaw/motia-workbench.json @@ -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 + } + } } ] \ No newline at end of file diff --git a/bitbylaw/services/bankverbindungen_mapper.py b/bitbylaw/services/bankverbindungen_mapper.py new file mode 100644 index 00000000..8880b566 --- /dev/null +++ b/bitbylaw/services/bankverbindungen_mapper.py @@ -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 diff --git a/bitbylaw/steps/vmh/bankverbindungen_sync_event_step.py b/bitbylaw/steps/vmh/bankverbindungen_sync_event_step.py new file mode 100644 index 00000000..09422219 --- /dev/null +++ b/bitbylaw/steps/vmh/bankverbindungen_sync_event_step.py @@ -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) diff --git a/bitbylaw/steps/vmh/webhook/bankverbindungen_create_api_step.py b/bitbylaw/steps/vmh/webhook/bankverbindungen_create_api_step.py new file mode 100644 index 00000000..b8c17669 --- /dev/null +++ b/bitbylaw/steps/vmh/webhook/bankverbindungen_create_api_step.py @@ -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)} + } diff --git a/bitbylaw/steps/vmh/webhook/bankverbindungen_delete_api_step.py b/bitbylaw/steps/vmh/webhook/bankverbindungen_delete_api_step.py new file mode 100644 index 00000000..7b09c29d --- /dev/null +++ b/bitbylaw/steps/vmh/webhook/bankverbindungen_delete_api_step.py @@ -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)} + } diff --git a/bitbylaw/steps/vmh/webhook/bankverbindungen_update_api_step.py b/bitbylaw/steps/vmh/webhook/bankverbindungen_update_api_step.py new file mode 100644 index 00000000..dd768658 --- /dev/null +++ b/bitbylaw/steps/vmh/webhook/bankverbindungen_update_api_step.py @@ -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)} + } diff --git a/bitbylaw/types.d.ts b/bitbylaw/types.d.ts index 26fe1fa5..86fee4ff 100644 --- a/bitbylaw/types.d.ts +++ b/bitbylaw/types.d.ts @@ -13,9 +13,13 @@ declare module 'motia' { interface Handlers { 'VMH Beteiligte Sync Handler': EventHandler + 'VMH Bankverbindungen Sync Handler': EventHandler 'VMH Webhook Beteiligte Update': ApiRouteHandler, unknown, { topic: 'vmh.beteiligte.update'; data: never }> 'VMH Webhook Beteiligte Delete': ApiRouteHandler, unknown, { topic: 'vmh.beteiligte.delete'; data: never }> 'VMH Webhook Beteiligte Create': ApiRouteHandler, unknown, { topic: 'vmh.beteiligte.create'; data: never }> + 'VMH Webhook Bankverbindungen Update': ApiRouteHandler, unknown, { topic: 'vmh.bankverbindungen.update'; data: never }> + 'VMH Webhook Bankverbindungen Delete': ApiRouteHandler, unknown, { topic: 'vmh.bankverbindungen.delete'; data: never }> + 'VMH Webhook Bankverbindungen Create': ApiRouteHandler, unknown, { topic: 'vmh.bankverbindungen.create'; data: never }> 'Advoware Proxy PUT': ApiRouteHandler, unknown, never> 'Advoware Proxy POST': ApiRouteHandler, unknown, never> 'Advoware Proxy GET': ApiRouteHandler, unknown, never>