Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 1x 1x 7x 7x 2x 7x 1x 7x 7x 1x 1x 6x 6x 2x 1x 1x 1x 4x 4x 3x 1x 1x | /**
* Send the `import_result_admin` WhatsApp template to admins on terminal
* import events.
*
* Template body (3 variables):
* "Import for {{1}} ({{2}}): {{3}}. Review at portal.interioring.com/admin/imports"
*
* Recipient resolution order:
* 1. The submitting admin's `users.phone` (if set)
* 2. `env.IMPORT_NOTIFY_WHATSAPP` fallback
* 3. If neither — warn and no-op (never throws).
*
* This is best-effort: any failure logs and resolves false rather than
* throwing, so a WhatsApp outage cannot block the email channel running
* alongside it.
*/
import { IMPORT_RESULT_TEMPLATE as IMPORT_RESULT_TEMPLATE_SPEC } from "../../config/whatsapp-templates";
import {
requireWhatsAppClient,
WhatsAppConfigError,
} from "../../lib/whatsapp/client";
export const IMPORT_RESULT_TEMPLATE = IMPORT_RESULT_TEMPLATE_SPEC.name;
export const IMPORT_RESULT_TEMPLATE_LANG = IMPORT_RESULT_TEMPLATE_SPEC.language;
export interface AdminNotifyInput {
proName: string;
status: "completed" | "failed" | "cancelled";
summary: string;
/** Submitter's phone in E.164 (no '+'). Optional. */
submitterPhone?: string | null;
}
export interface AdminNotifyEnv {
WHATSAPP_ACCESS_TOKEN?: string;
IMPORT_NOTIFY_WHATSAPP?: string;
ENVIRONMENT?: string;
}
function resolveRecipient(
input: AdminNotifyInput,
env: AdminNotifyEnv,
): string | null {
const direct = input.submitterPhone?.trim();
if (direct) return direct.replace(/\D/g, "");
const fallback = env.IMPORT_NOTIFY_WHATSAPP?.trim();
if (fallback) return fallback.replace(/\D/g, "");
return null;
}
export async function sendImportResultWhatsApp(
input: AdminNotifyInput,
env: AdminNotifyEnv,
): Promise<{ delivered: boolean; reason?: string }> {
const recipient = resolveRecipient(input, env);
if (!recipient) {
console.warn(
"[ImportNotify] No WhatsApp recipient — skipping admin notify",
);
return { delivered: false, reason: "no_recipient" };
}
let client: ReturnType<typeof requireWhatsAppClient>;
try {
client = requireWhatsAppClient(env as never);
} catch (err) {
if (err instanceof WhatsAppConfigError) {
console.warn("[ImportNotify] WhatsApp not configured — skipping");
return { delivered: false, reason: "not_configured" };
}
throw err;
}
try {
await client.sendTemplate(
recipient,
IMPORT_RESULT_TEMPLATE,
IMPORT_RESULT_TEMPLATE_LANG,
[
{
type: "body",
parameters: [
{ type: "text", text: input.proName.slice(0, 60) || "(unknown)" },
{ type: "text", text: input.status },
{ type: "text", text: input.summary.slice(0, 200) || "—" },
],
},
],
);
return { delivered: true };
} catch (err) {
console.error(
"[ImportNotify] WhatsApp send failed:",
err instanceof Error ? err.message : String(err),
);
return {
delivered: false,
reason: err instanceof Error ? err.message : "send_failed",
};
}
}
|