Dealer_Onboarding_Backend/src/common/utils/workflow-email-notifications.ts

147 lines
5.6 KiB
TypeScript

import db from '../../database/models/index.js';
import { Op } from 'sequelize';
import { sendEmail } from './email.service.js';
import { NotificationService } from '../../services/NotificationService.js';
import { REQUEST_TYPES } from '../config/constants.js';
const { RequestParticipant, User, Outlet, District } = db;
const frontendBase = () => process.env.FRONTEND_URL || 'http://localhost:5173';
/** Dealer acknowledgement + internal reviewers after resignation is created. */
export async function notifyResignationSubmittedEmails(resignation: any): Promise<void> {
const dealerUser = await User.findByPk(resignation.dealerId, {
attributes: ['id', 'email', 'fullName']
});
if (!dealerUser?.email) return;
const base = frontendBase();
const resignationCode = resignation.resignationId || resignation.id;
const lwd =
resignation.lastOperationalDateSales ||
resignation.lastOperationalDateServices ||
'As per application';
const dealerName = dealerUser.fullName || 'Dealer';
await sendEmail(
dealerUser.email,
`We received your resignation request — ${resignationCode}`,
'RESIGNATION_RECEIVED',
{
dealerName,
resignationId: resignationCode,
lwd: String(lwd),
link: `${base}/dealer-resignation/${resignation.id}`,
ctaLabel: 'View request'
}
).catch((err) => console.error('[notifyResignationSubmittedEmails] dealer ack:', err));
const participants = await RequestParticipant.findAll({
where: {
requestId: resignation.id,
requestType: REQUEST_TYPES.RESIGNATION,
userId: { [Op.ne]: resignation.dealerId }
},
include: [{ model: User, as: 'user', attributes: ['id', 'email', 'fullName'] }]
});
const internalLink = `${base}/resignation/${resignation.id}`;
for (const p of participants) {
const u = (p as any).user;
if (!u?.email) continue;
await NotificationService.notify(u.id, u.email, {
title: `New resignation request: ${resignationCode}`,
message: `Submitted by ${dealerName}.`,
channels: ['email', 'system'],
templateCode: 'RESIGNATION_SUBMITTED',
placeholders: {
dealerName,
resignationId: resignationCode,
lwd: String(lwd),
link: internalLink,
ctaLabel: 'Review resignation'
}
}).catch((err) => console.error('[notifyResignationSubmittedEmails] internal:', err));
}
}
/** Internal reviewers after constitutional request is created. */
export async function notifyConstitutionalSubmittedEmails(request: any, dealerDisplayName: string): Promise<void> {
const participants = await RequestParticipant.findAll({
where: {
requestId: request.id,
requestType: REQUEST_TYPES.CONSTITUTIONAL,
userId: { [Op.ne]: request.dealerId }
},
include: [{ model: User, as: 'user', attributes: ['id', 'email', 'fullName'] }]
});
const base = frontendBase();
const link = `${base}/constitutional-change/${request.id}`;
for (const p of participants) {
const u = (p as any).user;
if (!u?.email) continue;
await NotificationService.notify(u.id, u.email, {
title: `New constitutional change request: ${request.requestId}`,
message: `${dealerDisplayName} submitted a request.`,
channels: ['email', 'system'],
templateCode: 'CONSTITUTIONAL_CHANGE_SUBMITTED',
placeholders: {
dealerName: dealerDisplayName,
changeType: request.changeType || '',
requestId: request.requestId,
link,
ctaLabel: 'Review request'
}
}).catch((err) => console.error('[notifyConstitutionalSubmittedEmails]:', err));
}
}
/** Dealer + ASM when relocation request is submitted. */
export async function notifyRelocationSubmittedEmails(
request: any,
submitter: { email: string; fullName?: string | null }
): Promise<void> {
const base = frontendBase();
const code = request.requestId || request.id;
const dealerName = submitter.fullName?.trim() || 'Dealer';
if (submitter.email) {
await sendEmail(
submitter.email,
`Relocation request received — ${code}`,
'RELOCATION_RECEIVED',
{
dealerName,
requestId: code,
link: `${base}/relocation-requests/${request.id}`,
ctaLabel: 'View request'
}
).catch((err) => console.error('[notifyRelocationSubmittedEmails] dealer:', err));
}
const outlet = await Outlet.findByPk(request.outletId, {
include: [{ model: District, as: 'district', attributes: ['id', 'asmId'] }]
});
const asmId = (outlet as any)?.district?.asmId;
if (!asmId) return;
const asm = await User.findByPk(asmId, { attributes: ['id', 'email', 'fullName'] });
if (!asm?.email) return;
await NotificationService.notify(asm.id, asm.email, {
title: `New relocation request: ${code}`,
message: 'A dealer submitted an outlet relocation request.',
channels: ['email', 'system'],
templateCode: 'RELOCATION_SUBMITTED',
placeholders: {
dealerName,
requestId: code,
outletCode: outlet?.code || '',
link: `${base}/relocation-requests/${request.id}`,
ctaLabel: 'Review relocation'
}
}).catch((err) => console.error('[notifyRelocationSubmittedEmails] ASM:', err));
}