File size: 4,908 Bytes
db4ba8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
TradeFlow AI — Notification Service (T-074)

Sends notifications via:
  1. Resend (email)
  2. WhatsApp Business API (optional, behind feature flag)

Called on:
  - REVIEW_READY → operator email
  - ACCEPTED / REJECTED → importer email + WhatsApp (if enabled)
"""
from __future__ import annotations

import logging
from typing import Any

import httpx

logger = logging.getLogger("services.notification")

RESEND_API_URL = "https://api.resend.com/emails"


class NotificationService:
    def __init__(self, settings: Any) -> None:
        self._settings = settings

    async def notify_review_ready(
        self,
        batch_id: str,
        operator_email: str,
        crs_score: int,
        risk_level: str,
    ) -> None:
        """Notify operator that a batch is ready for review."""
        if not self._settings.RESEND_API_KEY:
            logger.info("RESEND_API_KEY not set — skipping email notification")
            return

        subject = f"[TradeFlow AI] Batch {batch_id[:8]}… ready for review"
        html = f"""
        <h2>Batch Ready for Review</h2>
        <p>A new import declaration batch is ready for your review.</p>
        <table>
            <tr><td><b>Batch ID</b></td><td>{batch_id}</td></tr>
            <tr><td><b>CRS Score</b></td><td>{crs_score}/100</td></tr>
            <tr><td><b>Risk Level</b></td><td>{risk_level}</td></tr>
        </table>
        <p><a href="https://app.tradeflow.ai/batches/{batch_id}">Review Now →</a></p>
        """
        await self._send_email(to=operator_email, subject=subject, html=html)

    async def notify_ceisa_result(
        self,
        batch_id: str,
        ceisa_status: str,
        aju_number: str,
        recipient_email: str,
        recipient_phone: str | None = None,
    ) -> None:
        """Notify importer of CEISA acceptance or rejection."""
        accepted = ceisa_status == "ACCEPTED"
        subject = (
            f"[TradeFlow AI] PIB {'Diterima' if accepted else 'Ditolak'} — AJU {aju_number}"
        )
        html = f"""
        <h2>{"✅ PIB Diterima" if accepted else "❌ PIB Ditolak"}</h2>
        <p>Status PIB Anda telah diperbarui:</p>
        <table>
            <tr><td><b>Batch ID</b></td><td>{batch_id}</td></tr>
            <tr><td><b>Nomor AJU</b></td><td>{aju_number}</td></tr>
            <tr><td><b>Status</b></td><td>{ceisa_status}</td></tr>
        </table>
        <p><a href="https://app.tradeflow.ai/batches/{batch_id}">Lihat Detail →</a></p>
        """
        await self._send_email(to=recipient_email, subject=subject, html=html)

        # WhatsApp (optional)
        if (
            self._settings.ENABLE_NOTIFICATIONS_WHATSAPP
            and recipient_phone
            and self._settings.WHATSAPP_TOKEN
        ):
            msg = (
                f"TradeFlow AI: PIB Anda {'*DITERIMA*' if accepted else '*DITOLAK*'} "
                f"oleh CEISA. Nomor AJU: {aju_number}. "
                f"Detail: https://app.tradeflow.ai/batches/{batch_id}"
            )
            await self._send_whatsapp(phone=recipient_phone, message=msg)

    async def _send_email(self, to: str, subject: str, html: str) -> None:
        try:
            async with httpx.AsyncClient(timeout=10.0) as client:
                resp = await client.post(
                    RESEND_API_URL,
                    headers={
                        "Authorization": f"Bearer {self._settings.RESEND_API_KEY.get_secret_value()}",
                        "Content-Type": "application/json",
                    },
                    json={
                        "from": self._settings.NOTIFICATION_EMAIL_FROM,
                        "to": [to],
                        "subject": subject,
                        "html": html,
                    },
                )
                resp.raise_for_status()
                logger.info(f"Email sent to {to}: {subject}")
        except Exception as e:
            logger.error(f"Email send failed: {e}")

    async def _send_whatsapp(self, phone: str, message: str) -> None:
        try:
            phone_id = self._settings.WHATSAPP_PHONE_NUMBER_ID
            token = self._settings.WHATSAPP_TOKEN.get_secret_value()
            async with httpx.AsyncClient(timeout=10.0) as client:
                resp = await client.post(
                    f"https://graph.facebook.com/v20.0/{phone_id}/messages",
                    headers={"Authorization": f"Bearer {token}"},
                    json={
                        "messaging_product": "whatsapp",
                        "to": phone.replace("+", ""),
                        "type": "text",
                        "text": {"body": message},
                    },
                )
                resp.raise_for_status()
                logger.info(f"WhatsApp sent to {phone}")
        except Exception as e:
            logger.error(f"WhatsApp send failed: {e}")