Compare commits
2 Commits
2e449d2928
...
f392ec0f06
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f392ec0f06 | ||
|
|
2532bd89ee |
@@ -17,7 +17,7 @@ import pytz
|
|||||||
from services.exceptions import LockAcquisitionError, SyncError, ValidationError
|
from services.exceptions import LockAcquisitionError, SyncError, ValidationError
|
||||||
from services.redis_client import get_redis_client
|
from services.redis_client import get_redis_client
|
||||||
from services.config import SYNC_CONFIG, get_lock_key, get_retry_delay_seconds
|
from services.config import SYNC_CONFIG, get_lock_key, get_retry_delay_seconds
|
||||||
from services.logging_utils import get_logger
|
from services.logging_utils import get_service_logger
|
||||||
|
|
||||||
import redis
|
import redis
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class BeteiligteSync:
|
|||||||
def __init__(self, espocrm_api, redis_client: Optional[redis.Redis] = None, context=None):
|
def __init__(self, espocrm_api, redis_client: Optional[redis.Redis] = None, context=None):
|
||||||
self.espocrm = espocrm_api
|
self.espocrm = espocrm_api
|
||||||
self.context = context
|
self.context = context
|
||||||
self.logger = get_logger('beteiligte_sync', context)
|
self.logger = get_service_logger('beteiligte_sync', context)
|
||||||
|
|
||||||
# Use provided Redis client or get from factory
|
# Use provided Redis client or get from factory
|
||||||
self.redis = redis_client or get_redis_client(strict=False)
|
self.redis = redis_client or get_redis_client(strict=False)
|
||||||
@@ -46,6 +46,11 @@ class BeteiligteSync:
|
|||||||
from services.notification_utils import NotificationManager
|
from services.notification_utils import NotificationManager
|
||||||
self.notification_manager = NotificationManager(espocrm_api=self.espocrm, context=context)
|
self.notification_manager = NotificationManager(espocrm_api=self.espocrm, context=context)
|
||||||
|
|
||||||
|
def _log(self, message: str, level: str = 'info') -> None:
|
||||||
|
"""Delegate logging to the logger with optional level"""
|
||||||
|
log_func = getattr(self.logger, level, self.logger.info)
|
||||||
|
log_func(message)
|
||||||
|
|
||||||
async def acquire_sync_lock(self, entity_id: str) -> bool:
|
async def acquire_sync_lock(self, entity_id: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Atomic distributed lock via Redis + syncStatus update
|
Atomic distributed lock via Redis + syncStatus update
|
||||||
|
|||||||
@@ -10,12 +10,9 @@ Hilfsfunktionen für Document-Synchronisation mit xAI:
|
|||||||
|
|
||||||
from typing import Dict, Any, Optional, List, Tuple
|
from typing import Dict, Any, Optional, List, Tuple
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import logging
|
|
||||||
|
|
||||||
from services.sync_utils_base import BaseSyncUtils
|
from services.sync_utils_base import BaseSyncUtils
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Max retry before permanent failure
|
# Max retry before permanent failure
|
||||||
MAX_SYNC_RETRIES = 5
|
MAX_SYNC_RETRIES = 5
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,59 @@ Vereinheitlicht Logging über:
|
|||||||
- Standard Python Logger
|
- Standard Python Logger
|
||||||
- Motia FlowContext Logger
|
- Motia FlowContext Logger
|
||||||
- Structured Logging
|
- Structured Logging
|
||||||
|
|
||||||
|
Usage Guidelines:
|
||||||
|
=================
|
||||||
|
|
||||||
|
FOR SERVICES: Use get_service_logger('service_name', context)
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
Example:
|
||||||
|
from services.logging_utils import get_service_logger
|
||||||
|
|
||||||
|
class XAIService:
|
||||||
|
def __init__(self, ctx=None):
|
||||||
|
self.logger = get_service_logger('xai', ctx)
|
||||||
|
|
||||||
|
def upload(self):
|
||||||
|
self.logger.info("Uploading file...")
|
||||||
|
|
||||||
|
FOR STEPS: Use ctx.logger directly (preferred)
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
Steps already have ctx.logger available - use it directly:
|
||||||
|
async def handler(event_data, ctx: FlowContext):
|
||||||
|
ctx.logger.info("Processing event")
|
||||||
|
|
||||||
|
Alternative: Use get_step_logger() for additional loggers:
|
||||||
|
step_logger = get_step_logger('beteiligte_sync', ctx)
|
||||||
|
|
||||||
|
FOR SYNC UTILS: Inherit from BaseSyncUtils (provides self.logger)
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
from services.sync_utils_base import BaseSyncUtils
|
||||||
|
|
||||||
|
class MySync(BaseSyncUtils):
|
||||||
|
def __init__(self, espocrm, redis, context):
|
||||||
|
super().__init__(espocrm, redis, context)
|
||||||
|
# self.logger is now available
|
||||||
|
|
||||||
|
def sync(self):
|
||||||
|
self._log("Syncing...", level='info')
|
||||||
|
|
||||||
|
FOR STANDALONE UTILITIES: Use get_logger()
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
from services.logging_utils import get_logger
|
||||||
|
|
||||||
|
logger = get_logger('my_module', context)
|
||||||
|
logger.info("Processing...")
|
||||||
|
|
||||||
|
CONSISTENCY RULES:
|
||||||
|
==================
|
||||||
|
✅ Services: get_service_logger('service_name', ctx)
|
||||||
|
✅ Steps: ctx.logger (direct) or get_step_logger('step_name', ctx)
|
||||||
|
✅ Sync Utils: Inherit from BaseSyncUtils → use self._log() or self.logger
|
||||||
|
✅ Standalone: get_logger('module_name', ctx)
|
||||||
|
|
||||||
|
❌ DO NOT: Use module-level logging.getLogger(__name__)
|
||||||
|
❌ DO NOT: Mix get_logger() and get_service_logger() in same module
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import pytz
|
|||||||
from services.exceptions import RedisConnectionError, LockAcquisitionError
|
from services.exceptions import RedisConnectionError, LockAcquisitionError
|
||||||
from services.redis_client import get_redis_client
|
from services.redis_client import get_redis_client
|
||||||
from services.config import SYNC_CONFIG, get_lock_key
|
from services.config import SYNC_CONFIG, get_lock_key
|
||||||
from services.logging_utils import get_logger
|
from services.logging_utils import get_service_logger
|
||||||
|
|
||||||
import redis
|
import redis
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class BaseSyncUtils:
|
|||||||
"""
|
"""
|
||||||
self.espocrm = espocrm_api
|
self.espocrm = espocrm_api
|
||||||
self.context = context
|
self.context = context
|
||||||
self.logger = get_logger('sync_utils', context)
|
self.logger = get_service_logger('sync_utils', context)
|
||||||
|
|
||||||
# Use provided Redis client or get from factory
|
# Use provided Redis client or get from factory
|
||||||
self.redis = redis_client or get_redis_client(strict=False)
|
self.redis = redis_client or get_redis_client(strict=False)
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
"""xAI Files & Collections Service"""
|
"""xAI Files & Collections Service"""
|
||||||
import os
|
import os
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import logging
|
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
|
from services.logging_utils import get_service_logger
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
XAI_FILES_URL = "https://api.x.ai"
|
XAI_FILES_URL = "https://api.x.ai"
|
||||||
XAI_MANAGEMENT_URL = "https://management-api.x.ai"
|
XAI_MANAGEMENT_URL = "https://management-api.x.ai"
|
||||||
@@ -23,6 +21,7 @@ class XAIService:
|
|||||||
self.api_key = os.getenv('XAI_API_KEY', '')
|
self.api_key = os.getenv('XAI_API_KEY', '')
|
||||||
self.management_key = os.getenv('XAI_MANAGEMENT_KEY', '')
|
self.management_key = os.getenv('XAI_MANAGEMENT_KEY', '')
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
|
self.logger = get_service_logger('xai', ctx)
|
||||||
self._session: Optional[aiohttp.ClientSession] = None
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
if not self.api_key:
|
if not self.api_key:
|
||||||
@@ -31,10 +30,9 @@ class XAIService:
|
|||||||
raise ValueError("XAI_MANAGEMENT_KEY not configured in environment")
|
raise ValueError("XAI_MANAGEMENT_KEY not configured in environment")
|
||||||
|
|
||||||
def _log(self, msg: str, level: str = 'info') -> None:
|
def _log(self, msg: str, level: str = 'info') -> None:
|
||||||
if self.ctx:
|
"""Delegate logging to service logger"""
|
||||||
getattr(self.ctx.logger, level, self.ctx.logger.info)(msg)
|
log_func = getattr(self.logger, level, self.logger.info)
|
||||||
else:
|
log_func(msg)
|
||||||
getattr(logger, level, logger.info)(msg)
|
|
||||||
|
|
||||||
async def _get_session(self) -> aiohttp.ClientSession:
|
async def _get_session(self) -> aiohttp.ClientSession:
|
||||||
if self._session is None or self._session.closed:
|
if self._session is None or self._session.closed:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from calendar_sync_utils import (
|
|||||||
import math
|
import math
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
from typing import Any, Dict
|
||||||
from motia import queue, FlowContext
|
from motia import queue, FlowContext
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from services.advoware_service import AdvowareService
|
from services.advoware_service import AdvowareService
|
||||||
@@ -33,7 +33,7 @@ config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def handler(input_data: dict, ctx: FlowContext):
|
async def handler(input_data: Dict[str, Any], ctx: FlowContext) -> None:
|
||||||
"""
|
"""
|
||||||
Handler that fetches all employees, sorts by last sync time,
|
Handler that fetches all employees, sorts by last sync time,
|
||||||
and emits calendar_sync_employee events for the oldest ones.
|
and emits calendar_sync_employee events for the oldest ones.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from pathlib import Path
|
|||||||
sys.path.insert(0, str(Path(__file__).parent))
|
sys.path.insert(0, str(Path(__file__).parent))
|
||||||
from calendar_sync_utils import log_operation
|
from calendar_sync_utils import log_operation
|
||||||
|
|
||||||
|
from typing import Dict, Any
|
||||||
from motia import cron, FlowContext
|
from motia import cron, FlowContext
|
||||||
|
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def handler(input_data: dict, ctx: FlowContext):
|
async def handler(input_data: Dict[str, Any], ctx: FlowContext) -> None:
|
||||||
"""Cron handler that triggers the calendar sync cascade."""
|
"""Cron handler that triggers the calendar sync cascade."""
|
||||||
try:
|
try:
|
||||||
log_operation('info', "Calendar Sync Cron: Starting to emit sync-all event", context=ctx)
|
log_operation('info', "Calendar Sync Cron: Starting to emit sync-all event", context=ctx)
|
||||||
@@ -37,14 +38,6 @@ async def handler(input_data: dict, ctx: FlowContext):
|
|||||||
})
|
})
|
||||||
|
|
||||||
log_operation('info', "Calendar Sync Cron: Emitted sync-all event", context=ctx)
|
log_operation('info', "Calendar Sync Cron: Emitted sync-all event", context=ctx)
|
||||||
return {
|
|
||||||
'status': 'completed',
|
|
||||||
'triggered_by': 'cron'
|
|
||||||
}
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_operation('error', f"Fehler beim Cron-Job: {e}", context=ctx)
|
log_operation('error', f"Fehler beim Cron-Job: {e}", context=ctx)
|
||||||
return {
|
|
||||||
'status': 'error',
|
|
||||||
'error': str(e)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import asyncio
|
|||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from typing import Dict, Any
|
||||||
import pytz
|
import pytz
|
||||||
import backoff
|
import backoff
|
||||||
import time
|
import time
|
||||||
@@ -945,14 +946,14 @@ config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def handler(input_data: dict, ctx: FlowContext):
|
async def handler(input_data: Dict[str, Any], ctx: FlowContext) -> None:
|
||||||
"""Main event handler for calendar sync."""
|
"""Main event handler for calendar sync."""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
kuerzel = input_data.get('kuerzel')
|
kuerzel = input_data.get('kuerzel')
|
||||||
if not kuerzel:
|
if not kuerzel:
|
||||||
log_operation('error', "No kuerzel provided in event", context=ctx)
|
log_operation('error', "No kuerzel provided in event", context=ctx)
|
||||||
return {'status': 400, 'body': {'error': 'No kuerzel provided'}}
|
return
|
||||||
|
|
||||||
log_operation('info', f"Starting calendar sync for employee {kuerzel}", context=ctx)
|
log_operation('info', f"Starting calendar sync for employee {kuerzel}", context=ctx)
|
||||||
|
|
||||||
|
|||||||
@@ -32,23 +32,33 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
body={'error': 'Endpoint required as query parameter'}
|
body={'error': 'Endpoint required as query parameter'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("🔄 ADVOWARE PROXY: DELETE REQUEST")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info(f"Endpoint: {endpoint}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Initialize Advoware client
|
# Initialize Advoware client
|
||||||
advoware = AdvowareAPI(ctx)
|
advoware = AdvowareAPI(ctx)
|
||||||
|
|
||||||
# Forward all query params except 'endpoint'
|
# Forward all query params except 'endpoint'
|
||||||
params = {k: v for k, v in request.query_params.items() if k != 'endpoint'}
|
params = {k: v for k, v in request.query_params.items() if k != 'endpoint'}
|
||||||
|
|
||||||
ctx.logger.info(f"Proxying DELETE request to Advoware: {endpoint}")
|
|
||||||
result = await advoware.api_call(
|
result = await advoware.api_call(
|
||||||
endpoint,
|
endpoint,
|
||||||
method='DELETE',
|
method='DELETE',
|
||||||
params=params
|
params=params
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx.logger.info("✅ Proxy DELETE erfolgreich")
|
||||||
return ApiResponse(status=200, body={'result': result})
|
return ApiResponse(status=200, body={'result': result})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Proxy error: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ ADVOWARE PROXY DELETE FEHLER")
|
||||||
|
ctx.logger.error(f"Endpoint: {request.query_params.get('endpoint', 'N/A')}")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={'error': 'Internal server error', 'details': str(e)}
|
body={'error': 'Internal server error', 'details': str(e)}
|
||||||
|
|||||||
@@ -32,23 +32,33 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
body={'error': 'Endpoint required as query parameter'}
|
body={'error': 'Endpoint required as query parameter'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("🔄 ADVOWARE PROXY: GET REQUEST")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info(f"Endpoint: {endpoint}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Initialize Advoware client
|
# Initialize Advoware client
|
||||||
advoware = AdvowareAPI(ctx)
|
advoware = AdvowareAPI(ctx)
|
||||||
|
|
||||||
# Forward all query params except 'endpoint'
|
# Forward all query params except 'endpoint'
|
||||||
params = {k: v for k, v in request.query_params.items() if k != 'endpoint'}
|
params = {k: v for k, v in request.query_params.items() if k != 'endpoint'}
|
||||||
|
|
||||||
ctx.logger.info(f"Proxying GET request to Advoware: {endpoint}")
|
|
||||||
result = await advoware.api_call(
|
result = await advoware.api_call(
|
||||||
endpoint,
|
endpoint,
|
||||||
method='GET',
|
method='GET',
|
||||||
params=params
|
params=params
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx.logger.info("✅ Proxy GET erfolgreich")
|
||||||
return ApiResponse(status=200, body={'result': result})
|
return ApiResponse(status=200, body={'result': result})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Proxy error: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ ADVOWARE PROXY GET FEHLER")
|
||||||
|
ctx.logger.error(f"Endpoint: {request.query_params.get('endpoint', 'N/A')}")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={'error': 'Internal server error', 'details': str(e)}
|
body={'error': 'Internal server error', 'details': str(e)}
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
body={'error': 'Endpoint required as query parameter'}
|
body={'error': 'Endpoint required as query parameter'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("🔄 ADVOWARE PROXY: POST REQUEST")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info(f"Endpoint: {endpoint}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Initialize Advoware client
|
# Initialize Advoware client
|
||||||
advoware = AdvowareAPI(ctx)
|
advoware = AdvowareAPI(ctx)
|
||||||
|
|
||||||
@@ -43,7 +49,6 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
# Get request body
|
# Get request body
|
||||||
json_data = request.body
|
json_data = request.body
|
||||||
|
|
||||||
ctx.logger.info(f"Proxying POST request to Advoware: {endpoint}")
|
|
||||||
result = await advoware.api_call(
|
result = await advoware.api_call(
|
||||||
endpoint,
|
endpoint,
|
||||||
method='POST',
|
method='POST',
|
||||||
@@ -51,11 +56,17 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
json_data=json_data
|
json_data=json_data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx.logger.info("✅ Proxy POST erfolgreich")
|
||||||
return ApiResponse(status=200, body={'result': result})
|
return ApiResponse(status=200, body={'result': result})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Proxy error: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ ADVOWARE PROXY POST FEHLER")
|
||||||
|
ctx.logger.error(f"Endpoint: {request.query_params.get('endpoint', 'N/A')}")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={'error': 'Internal server error', 'details': str(e)}
|
body={'error': 'Internal server error', 'details': str(e)}
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
body={'error': 'Endpoint required as query parameter'}
|
body={'error': 'Endpoint required as query parameter'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("🔄 ADVOWARE PROXY: PUT REQUEST")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info(f"Endpoint: {endpoint}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Initialize Advoware client
|
# Initialize Advoware client
|
||||||
advoware = AdvowareAPI(ctx)
|
advoware = AdvowareAPI(ctx)
|
||||||
|
|
||||||
@@ -43,7 +49,6 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
# Get request body
|
# Get request body
|
||||||
json_data = request.body
|
json_data = request.body
|
||||||
|
|
||||||
ctx.logger.info(f"Proxying PUT request to Advoware: {endpoint}")
|
|
||||||
result = await advoware.api_call(
|
result = await advoware.api_call(
|
||||||
endpoint,
|
endpoint,
|
||||||
method='PUT',
|
method='PUT',
|
||||||
@@ -51,11 +56,17 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
json_data=json_data
|
json_data=json_data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ctx.logger.info("✅ Proxy PUT erfolgreich")
|
||||||
return ApiResponse(status=200, body={'result': result})
|
return ApiResponse(status=200, body={'result': result})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Proxy error: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ ADVOWARE PROXY PUT FEHLER")
|
||||||
|
ctx.logger.error(f"Endpoint: {request.query_params.get('endpoint', 'N/A')}")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={'error': 'Internal server error', 'details': str(e)}
|
body={'error': 'Internal server error', 'details': str(e)}
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]):
|
async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
|
||||||
"""Zentraler Sync-Handler für Bankverbindungen"""
|
"""Zentraler Sync-Handler für Bankverbindungen"""
|
||||||
|
|
||||||
entity_id = event_data.get('entity_id')
|
entity_id = event_data.get('entity_id')
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def handler(input_data: Dict[str, Any], ctx: FlowContext):
|
async def handler(input_data: Dict[str, Any], ctx: FlowContext) -> None:
|
||||||
"""
|
"""
|
||||||
Cron-Handler: Findet alle Beteiligte die Sync benötigen und emittiert Events
|
Cron-Handler: Findet alle Beteiligte die Sync benötigen und emittiert Events
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -42,16 +42,13 @@ config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> Optional[Dict[str, Any]]:
|
async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Zentraler Sync-Handler für Beteiligte
|
Zentraler Sync-Handler für Beteiligte
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
event_data: Event data mit entity_id, action, source
|
event_data: Event data mit entity_id, action, source
|
||||||
ctx: Motia FlowContext
|
ctx: Motia FlowContext
|
||||||
|
|
||||||
Returns:
|
|
||||||
Optional result dict
|
|
||||||
"""
|
"""
|
||||||
entity_id = event_data.get('entity_id')
|
entity_id = event_data.get('entity_id')
|
||||||
action = event_data.get('action')
|
action = event_data.get('action')
|
||||||
@@ -61,11 +58,13 @@ async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> Optional
|
|||||||
|
|
||||||
if not entity_id:
|
if not entity_id:
|
||||||
step_logger.error("Keine entity_id im Event gefunden")
|
step_logger.error("Keine entity_id im Event gefunden")
|
||||||
return None
|
return
|
||||||
|
|
||||||
step_logger.info(
|
step_logger.info("=" * 80)
|
||||||
f"🔄 Sync-Handler gestartet: {action.upper()} | Entity: {entity_id} | Source: {source}"
|
step_logger.info(f"🔄 BETEILIGTE SYNC HANDLER: {action.upper()}")
|
||||||
)
|
step_logger.info("=" * 80)
|
||||||
|
step_logger.info(f"Entity: {entity_id} | Source: {source}")
|
||||||
|
step_logger.info("=" * 80)
|
||||||
|
|
||||||
# Get shared Redis client (centralized)
|
# Get shared Redis client (centralized)
|
||||||
redis_client = get_redis_client(strict=False)
|
redis_client = get_redis_client(strict=False)
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ from motia import FlowContext
|
|||||||
from services.espocrm import EspoCRMAPI
|
from services.espocrm import EspoCRMAPI
|
||||||
from services.document_sync_utils import DocumentSync
|
from services.document_sync_utils import DocumentSync
|
||||||
from services.xai_service import XAIService
|
from services.xai_service import XAIService
|
||||||
|
from services.redis_client import get_redis_client
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import redis
|
|
||||||
import os
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"name": "VMH Document Sync Handler",
|
"name": "VMH Document Sync Handler",
|
||||||
@@ -32,7 +31,7 @@ config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]):
|
async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
|
||||||
"""Zentraler Sync-Handler für Documents"""
|
"""Zentraler Sync-Handler für Documents"""
|
||||||
entity_id = event_data.get('entity_id')
|
entity_id = event_data.get('entity_id')
|
||||||
entity_type = event_data.get('entity_type', 'CDokumente') # Default: CDokumente
|
entity_type = event_data.get('entity_type', 'CDokumente') # Default: CDokumente
|
||||||
@@ -52,20 +51,11 @@ async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]):
|
|||||||
ctx.logger.info(f"Source: {source}")
|
ctx.logger.info(f"Source: {source}")
|
||||||
ctx.logger.info("=" * 80)
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Shared Redis client for distributed locking
|
# Shared Redis client for distributed locking (centralized factory)
|
||||||
redis_host = os.getenv('REDIS_HOST', 'localhost')
|
redis_client = get_redis_client(strict=False)
|
||||||
redis_port = int(os.getenv('REDIS_PORT', '6379'))
|
|
||||||
redis_db = int(os.getenv('REDIS_DB_ADVOWARE_CACHE', '1'))
|
|
||||||
|
|
||||||
redis_client = redis.Redis(
|
# APIs initialisieren (mit Context für besseres Logging)
|
||||||
host=redis_host,
|
espocrm = EspoCRMAPI(ctx)
|
||||||
port=redis_port,
|
|
||||||
db=redis_db,
|
|
||||||
decode_responses=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# APIs initialisieren
|
|
||||||
espocrm = EspoCRMAPI()
|
|
||||||
sync_utils = DocumentSync(espocrm, redis_client, ctx)
|
sync_utils = DocumentSync(espocrm, redis_client, ctx)
|
||||||
xai_service = XAIService(ctx)
|
xai_service = XAIService(ctx)
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Bankverbindungen Create empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: BANKVERBINDUNGEN CREATE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Sammle alle IDs aus dem Batch
|
# Sammle alle IDs aus dem Batch
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
@@ -50,7 +53,8 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.logger.info(f"VMH Create Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
ctx.logger.info("✅ VMH Create Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
@@ -62,7 +66,10 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler beim Verarbeiten des VMH Create Webhooks: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: BANKVERBINDUNGEN CREATE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={'error': 'Internal server error', 'details': str(e)}
|
body={'error': 'Internal server error', 'details': str(e)}
|
||||||
|
|||||||
@@ -23,8 +23,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Bankverbindungen Delete empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: BANKVERBINDUNGEN DELETE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Sammle alle IDs
|
# Sammle alle IDs
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
@@ -50,7 +53,8 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.logger.info(f"VMH Delete Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
ctx.logger.info("✅ VMH Delete Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
@@ -62,7 +66,10 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler beim Verarbeiten des VMH Delete Webhooks: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: BANKVERBINDUNGEN DELETE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={'error': 'Internal server error', 'details': str(e)}
|
body={'error': 'Internal server error', 'details': str(e)}
|
||||||
|
|||||||
@@ -23,8 +23,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Bankverbindungen Update empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: BANKVERBINDUNGEN UPDATE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Sammle alle IDs
|
# Sammle alle IDs
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
@@ -50,7 +53,8 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.logger.info(f"VMH Update Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
ctx.logger.info("✅ VMH Update Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
@@ -62,7 +66,10 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler beim Verarbeiten des VMH Update Webhooks: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: BANKVERBINDUNGEN UPDATE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={'error': 'Internal server error', 'details': str(e)}
|
body={'error': 'Internal server error', 'details': str(e)}
|
||||||
|
|||||||
@@ -26,8 +26,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Beteiligte Create empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: BETEILIGTE CREATE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Sammle alle IDs aus dem Batch
|
# Sammle alle IDs aus dem Batch
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
@@ -53,7 +56,8 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.logger.info(f"VMH Create Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
ctx.logger.info("✅ VMH Create Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
@@ -65,7 +69,10 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler beim Verarbeiten des VMH Create Webhooks: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: VMH CREATE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={
|
body={
|
||||||
|
|||||||
@@ -23,8 +23,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Beteiligte Delete empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: BETEILIGTE DELETE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Sammle alle IDs aus dem Batch
|
# Sammle alle IDs aus dem Batch
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
@@ -50,7 +53,8 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.logger.info(f"VMH Delete Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
ctx.logger.info("✅ VMH Delete Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
@@ -62,7 +66,10 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler beim Delete-Webhook: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: BETEILIGTE DELETE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={'error': 'Internal server error', 'details': str(e)}
|
body={'error': 'Internal server error', 'details': str(e)}
|
||||||
|
|||||||
@@ -26,8 +26,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Beteiligte Update empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: BETEILIGTE UPDATE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.info(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
|
|
||||||
# Sammle alle IDs aus dem Batch
|
# Sammle alle IDs aus dem Batch
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
@@ -53,7 +56,8 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.logger.info(f"VMH Update Webhook verarbeitet: {len(entity_ids)} Events emittiert")
|
ctx.logger.info("✅ VMH Update Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
@@ -65,7 +69,10 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler beim Verarbeiten des VMH Update Webhooks: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: VMH UPDATE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
body={
|
body={
|
||||||
|
|||||||
@@ -25,17 +25,21 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Document Create empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: DOCUMENT CREATE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.debug(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.debug(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
|
||||||
# Sammle alle IDs aus dem Batch
|
# Sammle alle IDs aus dem Batch
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
|
entity_type = 'CDokumente' # Default
|
||||||
|
|
||||||
if isinstance(payload, list):
|
if isinstance(payload, list):
|
||||||
for entity in payload:
|
for entity in payload:
|
||||||
if isinstance(entity, dict) and 'id' in entity:
|
if isinstance(entity, dict) and 'id' in entity:
|
||||||
entity_ids.add(entity['id'])
|
entity_ids.add(entity['id'])
|
||||||
# Extrahiere entityType falls vorhanden
|
# Take entityType from first entity if present
|
||||||
|
if entity_type == 'CDokumente':
|
||||||
entity_type = entity.get('entityType', 'CDokumente')
|
entity_type = entity.get('entityType', 'CDokumente')
|
||||||
elif isinstance(payload, dict) and 'id' in payload:
|
elif isinstance(payload, dict) and 'id' in payload:
|
||||||
entity_ids.add(payload['id'])
|
entity_ids.add(payload['id'])
|
||||||
@@ -49,12 +53,15 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
'topic': 'vmh.document.create',
|
'topic': 'vmh.document.create',
|
||||||
'data': {
|
'data': {
|
||||||
'entity_id': entity_id,
|
'entity_id': entity_id,
|
||||||
'entity_type': entity_type if 'entity_type' in locals() else 'CDokumente',
|
'entity_type': entity_type,
|
||||||
'action': 'create',
|
'action': 'create',
|
||||||
'timestamp': payload[0].get('modifiedAt') if isinstance(payload, list) and payload else None
|
'timestamp': payload[0].get('modifiedAt') if isinstance(payload, list) and payload else None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ctx.logger.info("✅ Document Create Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
body={
|
body={
|
||||||
@@ -65,8 +72,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler im Document Create Webhook: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: DOCUMENT CREATE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
ctx.logger.error(f"Payload: {request.body}")
|
ctx.logger.error(f"Payload: {request.body}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
|
|||||||
@@ -25,16 +25,21 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Document Delete empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: DOCUMENT DELETE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.debug(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.debug(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
|
||||||
# Sammle alle IDs aus dem Batch
|
# Sammle alle IDs aus dem Batch
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
|
entity_type = 'CDokumente' # Default
|
||||||
|
|
||||||
if isinstance(payload, list):
|
if isinstance(payload, list):
|
||||||
for entity in payload:
|
for entity in payload:
|
||||||
if isinstance(entity, dict) and 'id' in entity:
|
if isinstance(entity, dict) and 'id' in entity:
|
||||||
entity_ids.add(entity['id'])
|
entity_ids.add(entity['id'])
|
||||||
|
# Take entityType from first entity if present
|
||||||
|
if entity_type == 'CDokumente':
|
||||||
entity_type = entity.get('entityType', 'CDokumente')
|
entity_type = entity.get('entityType', 'CDokumente')
|
||||||
elif isinstance(payload, dict) and 'id' in payload:
|
elif isinstance(payload, dict) and 'id' in payload:
|
||||||
entity_ids.add(payload['id'])
|
entity_ids.add(payload['id'])
|
||||||
@@ -48,12 +53,15 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
'topic': 'vmh.document.delete',
|
'topic': 'vmh.document.delete',
|
||||||
'data': {
|
'data': {
|
||||||
'entity_id': entity_id,
|
'entity_id': entity_id,
|
||||||
'entity_type': entity_type if 'entity_type' in locals() else 'CDokumente',
|
'entity_type': entity_type,
|
||||||
'action': 'delete',
|
'action': 'delete',
|
||||||
'timestamp': payload[0].get('deletedAt') if isinstance(payload, list) and payload else None
|
'timestamp': payload[0].get('deletedAt') if isinstance(payload, list) and payload else None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ctx.logger.info("✅ Document Delete Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
body={
|
body={
|
||||||
@@ -64,8 +72,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler im Document Delete Webhook: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: DOCUMENT DELETE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
ctx.logger.error(f"Payload: {request.body}")
|
ctx.logger.error(f"Payload: {request.body}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
|
|||||||
@@ -25,16 +25,21 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
try:
|
try:
|
||||||
payload = request.body or []
|
payload = request.body or []
|
||||||
|
|
||||||
ctx.logger.info("VMH Webhook Document Update empfangen")
|
ctx.logger.info("=" * 80)
|
||||||
|
ctx.logger.info("📥 VMH WEBHOOK: DOCUMENT UPDATE")
|
||||||
|
ctx.logger.info("=" * 80)
|
||||||
ctx.logger.debug(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
ctx.logger.debug(f"Payload: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
|
||||||
# Sammle alle IDs aus dem Batch
|
# Sammle alle IDs aus dem Batch
|
||||||
entity_ids = set()
|
entity_ids = set()
|
||||||
|
entity_type = 'CDokumente' # Default
|
||||||
|
|
||||||
if isinstance(payload, list):
|
if isinstance(payload, list):
|
||||||
for entity in payload:
|
for entity in payload:
|
||||||
if isinstance(entity, dict) and 'id' in entity:
|
if isinstance(entity, dict) and 'id' in entity:
|
||||||
entity_ids.add(entity['id'])
|
entity_ids.add(entity['id'])
|
||||||
|
# Take entityType from first entity if present
|
||||||
|
if entity_type == 'CDokumente':
|
||||||
entity_type = entity.get('entityType', 'CDokumente')
|
entity_type = entity.get('entityType', 'CDokumente')
|
||||||
elif isinstance(payload, dict) and 'id' in payload:
|
elif isinstance(payload, dict) and 'id' in payload:
|
||||||
entity_ids.add(payload['id'])
|
entity_ids.add(payload['id'])
|
||||||
@@ -48,12 +53,15 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
'topic': 'vmh.document.update',
|
'topic': 'vmh.document.update',
|
||||||
'data': {
|
'data': {
|
||||||
'entity_id': entity_id,
|
'entity_id': entity_id,
|
||||||
'entity_type': entity_type if 'entity_type' in locals() else 'CDokumente',
|
'entity_type': entity_type,
|
||||||
'action': 'update',
|
'action': 'update',
|
||||||
'timestamp': payload[0].get('modifiedAt') if isinstance(payload, list) and payload else None
|
'timestamp': payload[0].get('modifiedAt') if isinstance(payload, list) and payload else None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ctx.logger.info("✅ Document Update Webhook verarbeitet: "
|
||||||
|
f"{len(entity_ids)} Events emittiert")
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=200,
|
status=200,
|
||||||
body={
|
body={
|
||||||
@@ -64,8 +72,11 @@ async def handler(request: ApiRequest, ctx: FlowContext[Any]) -> ApiResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ctx.logger.error(f"Fehler im Document Update Webhook: {e}")
|
ctx.logger.error("=" * 80)
|
||||||
|
ctx.logger.error("❌ FEHLER: DOCUMENT UPDATE WEBHOOK")
|
||||||
|
ctx.logger.error(f"Error: {e}")
|
||||||
ctx.logger.error(f"Payload: {request.body}")
|
ctx.logger.error(f"Payload: {request.body}")
|
||||||
|
ctx.logger.error("=" * 80)
|
||||||
|
|
||||||
return ApiResponse(
|
return ApiResponse(
|
||||||
status=500,
|
status=500,
|
||||||
|
|||||||
Reference in New Issue
Block a user