40 lines
1.5 KiB
Python
40 lines
1.5 KiB
Python
"""Notification engine.
|
|
|
|
Resolves templates for a domain event from the database, renders them and
|
|
dispatches through the configured provider. Business logic only emits events.
|
|
"""
|
|
from django.utils import timezone
|
|
|
|
from apps.notifications.models import NotificationLog, NotificationTemplate
|
|
from apps.notifications.providers import get_sms_provider, render_template
|
|
|
|
|
|
class NotificationService:
|
|
def send_event(self, event: str, context: dict, recipient: str = "") -> list:
|
|
results = []
|
|
templates = NotificationTemplate.objects.filter(event=event, enabled=True)
|
|
for template in templates:
|
|
body = render_template(template.body, context)
|
|
if template.channel == NotificationTemplate.Channel.SMS:
|
|
results.append(self._send_sms(template, recipient, body))
|
|
return results
|
|
|
|
def _send_sms(self, template, recipient: str, body: str) -> dict:
|
|
status = "sent"
|
|
error = ""
|
|
reference = ""
|
|
try:
|
|
reference = get_sms_provider().send(recipient, body)
|
|
except Exception as exc: # pragma: no cover - provider failures
|
|
status = "failed"
|
|
error = str(exc)
|
|
NotificationLog.objects.create(
|
|
template=template,
|
|
recipient=recipient,
|
|
channel="sms",
|
|
status=status,
|
|
error=error,
|
|
sent_at=timezone.now() if status == "sent" else None,
|
|
)
|
|
return {"channel": "sms", "status": status, "reference": reference}
|