system-prompts-and-models-o.../dealix/auto_client_acquisition/platform_services/event_bus.py
Sami Assiri b13cb389cc feat(dealix): sync full Dealix package to repo
- API routers, ACA modules, integrations (draft operators)
- Docs, landing pages, scripts (launch readiness, scorecard)
- Tests and CI workflow updates for Dealix

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-01 21:01:17 +03:00

75 lines
3.1 KiB
Python

"""Unified event types and field validation — no transport."""
from __future__ import annotations
from enum import Enum
from typing import Any
class EventType(str, Enum):
"""Stable event type names for platform ingest and internal cards."""
LEAD_RECEIVED = "lead_received"
EXTERNAL_SEND_REQUESTED = "external_send_requested"
PAYMENT_INTENT = "payment_intent"
WHATSAPP_MESSAGE_REQUESTED = "whatsapp_message_requested"
REVIEW_REQUIRED = "review_required"
DRAFT_CREATED = "draft_created"
# Omni-channel extensions (dotted names) — backward compatible with existing types.
EMAIL_RECEIVED = "email.received"
CALENDAR_MEETING_SCHEDULED = "calendar.meeting_scheduled"
SOCIAL_COMMENT_RECEIVED = "social.comment_received"
SOCIAL_DM_RECEIVED = "social.dm_received"
LEAD_FORM_SUBMITTED = "lead.form_submitted"
PAYMENT_PAID = "payment.paid"
PAYMENT_FAILED = "payment.failed"
REVIEW_CREATED = "review.created"
PARTNER_SUGGESTED = "partner.suggested"
ACTION_APPROVED = "action.approved"
ACTION_BLOCKED = "action.blocked"
_REQUIRED: dict[EventType, tuple[str, ...]] = {
EventType.LEAD_RECEIVED: ("source", "channel_id"),
EventType.EXTERNAL_SEND_REQUESTED: ("channel_id", "action"),
EventType.PAYMENT_INTENT: ("amount_halalas", "currency"),
EventType.WHATSAPP_MESSAGE_REQUESTED: ("intent", "audience"),
EventType.REVIEW_REQUIRED: ("reason_code",),
EventType.DRAFT_CREATED: ("draft_kind",),
EventType.EMAIL_RECEIVED: ("channel_id", "subject_ar"),
EventType.CALENDAR_MEETING_SCHEDULED: ("channel_id", "title_ar"),
EventType.SOCIAL_COMMENT_RECEIVED: ("channel_id", "snippet_ar"),
EventType.SOCIAL_DM_RECEIVED: ("channel_id", "sender_hint"),
EventType.LEAD_FORM_SUBMITTED: ("source", "channel_id"),
EventType.PAYMENT_PAID: ("amount_halalas", "currency"),
EventType.PAYMENT_FAILED: ("amount_halalas", "reason_code"),
EventType.REVIEW_CREATED: ("channel_id", "rating"),
EventType.PARTNER_SUGGESTED: ("partner_name_ar", "sector"),
EventType.ACTION_APPROVED: ("action_id", "actor"),
EventType.ACTION_BLOCKED: ("action_id", "reason_code"),
}
def validate_event(payload: dict[str, Any]) -> dict[str, Any]:
"""
Validate ``event_type`` and required keys. Unknown types are rejected
(forces explicit extension rather than silent typos).
"""
errors: list[str] = []
raw_type = payload.get("event_type")
if not isinstance(raw_type, str) or not raw_type.strip():
return {"valid": False, "errors": ["event_type_required"], "normalized": None}
try:
et = EventType(raw_type.strip())
except ValueError:
return {"valid": False, "errors": [f"unknown_event_type:{raw_type}"], "normalized": None}
for key in _REQUIRED[et]:
if key not in payload or payload[key] in (None, ""):
errors.append(f"missing_field:{key}")
normalized = {"event_type": et.value, **{k: v for k, v in payload.items() if k != "event_type"}}
normalized["event_type"] = et.value
return {"valid": len(errors) == 0, "errors": errors, "normalized": normalized if not errors else None}