""" Notification models and Pydantic schemas. """ import uuid from datetime import datetime from typing import Optional, List, Dict, Any from enum import Enum from pydantic import BaseModel, Field class NotificationChannel(str, Enum): WHATSAPP = "whatsapp" EMAIL = "email" SMS = "sms" PUSH = "push" class NotificationStatus(str, Enum): PENDING = "pending" QUEUED = "queued" SENDING = "sending" SENT = "sent" DELIVERED = "delivered" FAILED = "failed" class NotificationPriority(str, Enum): LOW = "low" NORMAL = "normal" HIGH = "high" CRITICAL = "critical" # --- Request Schemas --- class SendNotificationRequest(BaseModel): """Send a notification via one or more channels.""" recipient: str = Field(..., description="Phone number (with country code) or email") channels: List[NotificationChannel] = Field( default=[NotificationChannel.WHATSAPP], description="Delivery channels" ) template_name: str = Field(..., description="Template identifier") template_data: Dict[str, Any] = Field(default_factory=dict) priority: NotificationPriority = Field(default=NotificationPriority.NORMAL) source: Optional[str] = Field(None, description="Originating microservice") merchant_id: str = Field(..., description="Merchant ID (required for credential lookup)") merchant_name: Optional[str] = Field("", description="Merchant name (injected into template variables at dispatch)") metadata: Optional[Dict[str, Any]] = None class SendBatchRequest(BaseModel): """Send notifications to multiple recipients.""" notifications: List[SendNotificationRequest] = Field( ..., min_length=1, max_length=100 ) class ListNotificationsRequest(BaseModel): """List notifications with filters and projection support.""" filters: Optional[Dict[str, Any]] = Field(default_factory=dict) skip: int = Field(default=0, ge=0) limit: int = Field(default=50, ge=1, le=200) projection_list: Optional[List[str]] = Field( None, description="List of fields to include in response" ) # --- Response Schemas --- class SendNotificationResponse(BaseModel): success: bool notification_id: str message: str channels: List[str] class SendBatchResponse(BaseModel): success: bool total: int queued: int failed: int results: List[SendNotificationResponse] class NotificationDetail(BaseModel): notification_id: str recipient: str channels: List[str] template_name: str template_data: Dict[str, Any] = {} status: str priority: str = "normal" source: Optional[str] = None merchant_id: Optional[str] = None merchant_name: Optional[str] = None channel_results: Dict[str, Any] = {} retry_count: int = 0 created_at: Optional[datetime] = None updated_at: Optional[datetime] = None sent_at: Optional[datetime] = None class ListNotificationsResponse(BaseModel): success: bool = True total: int skip: int limit: int data: List[Any] # --- MongoDB Document Shape --- def new_notification_doc(req: SendNotificationRequest) -> Dict[str, Any]: now = datetime.utcnow() return { "notification_id": str(uuid.uuid4()), "recipient": req.recipient, "channels": [ch.value for ch in req.channels], "template_name": req.template_name, "template_data": req.template_data, "priority": req.priority.value, "status": NotificationStatus.QUEUED.value, "source": req.source, "merchant_id": req.merchant_id, "merchant_name": req.merchant_name or "", "metadata": req.metadata or {}, "channel_results": {}, "retry_count": 0, "created_at": now, "updated_at": now, "sent_at": None, }