317 lines
16 KiB
TypeScript
317 lines
16 KiB
TypeScript
/**
|
|
* @file seed-missing-templates.ts
|
|
* @description Seeds the 6 email templates that are referenced in workflow code
|
|
* but were missing from the DB and the allowed-email-template-codes list.
|
|
*
|
|
* Run with: npx ts-node src/scripts/seed-missing-templates.ts
|
|
*/
|
|
|
|
import db from '../database/models/index.js';
|
|
|
|
const seedMissingTemplates = async () => {
|
|
try {
|
|
console.log('--- Seeding Missing Workflow Email Templates ---');
|
|
|
|
const templates = [
|
|
// ── 1. Workflow Action Required ────────────────────────────────────────
|
|
// Used in: workflow-email-notifications.ts (next-actor, send-back notifications)
|
|
// constitutional.controller.ts
|
|
// Recipients: DD-ZM, RBM, ZBH, DD-Lead, DD-Head, NBH, Legal, Finance, FDD
|
|
// Channels: system + email + whatsapp (when phone available)
|
|
{
|
|
templateCode: 'WORKFLOW_ACTION_REQUIRED',
|
|
description: 'Sent to the next actor in any workflow when their action is required. Used across Onboarding, Resignation, Termination, Constitutional, and Relocation.',
|
|
subject: 'Action Required: {{requestId}} — {{targetStage}}',
|
|
body: `
|
|
<div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:20px;">
|
|
<div style="background:#c8102e;padding:20px;border-radius:8px 8px 0 0;">
|
|
<h2 style="color:#fff;margin:0;font-size:20px;">Action Required</h2>
|
|
</div>
|
|
<div style="background:#f9f9f9;padding:24px;border-radius:0 0 8px 8px;border:1px solid #eee;">
|
|
<p>Hi,</p>
|
|
<p>
|
|
The request <strong>{{requestId}}</strong>
|
|
{{#if dealerName}}(Dealer: <strong>{{dealerName}}</strong>){{/if}}
|
|
has reached the <strong>{{targetStage}}</strong> stage and requires your review and action.
|
|
</p>
|
|
{{#if remarks}}
|
|
<div style="background:#fff8e1;border-left:4px solid #fb8c00;padding:12px 16px;margin:16px 0;">
|
|
<strong>Remarks:</strong><br/>{{remarks}}
|
|
</div>
|
|
{{/if}}
|
|
<p>Please log in to the RE Dealer Management Portal to review and act:</p>
|
|
<div style="text-align:center;margin:24px 0;">
|
|
<a href="{{link}}" style="background:#c8102e;color:#fff;padding:12px 28px;border-radius:6px;text-decoration:none;font-weight:bold;">
|
|
{{#if ctaLabel}}{{ctaLabel}}{{else}}Review & Take Action{{/if}}
|
|
</a>
|
|
</div>
|
|
<p style="color:#888;font-size:12px;">This is an automated notification. Do not reply to this email.</p>
|
|
</div>
|
|
</div>`,
|
|
placeholders: ['requestId', 'dealerName', 'targetStage', 'link', 'remarks', 'ctaLabel']
|
|
},
|
|
|
|
// ── 2. Workflow Status Update — Dealer ─────────────────────────────────
|
|
// Used in: workflow-email-notifications.ts (dealer on interim + terminal events)
|
|
// Recipients: Dealer / Applicant
|
|
// Channels: system always; email+whatsapp on terminal (rejection/completion)
|
|
{
|
|
templateCode: 'WORKFLOW_STATUS_UPDATE_DEALER',
|
|
description: 'Milestone/status update sent to the dealer or applicant when their request moves to a new stage.',
|
|
subject: 'Update on Your Request — {{requestId}}',
|
|
body: `
|
|
<div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:20px;">
|
|
<div style="background:#c8102e;padding:20px;border-radius:8px 8px 0 0;">
|
|
<h2 style="color:#fff;margin:0;font-size:20px;">Request Status Update</h2>
|
|
</div>
|
|
<div style="background:#f9f9f9;padding:24px;border-radius:0 0 8px 8px;border:1px solid #eee;">
|
|
<p>Dear {{dealerName}},</p>
|
|
<p>
|
|
Your request <strong>{{requestId}}</strong> has been updated.
|
|
Current status: <strong>{{targetStage}}</strong>.
|
|
</p>
|
|
{{#if remarks}}
|
|
<div style="background:#f0f4ff;border-left:4px solid #3d6be8;padding:12px 16px;margin:16px 0;">
|
|
<strong>Note:</strong> {{remarks}}
|
|
</div>
|
|
{{/if}}
|
|
<p>Track the live progress of your request:</p>
|
|
<div style="text-align:center;margin:24px 0;">
|
|
<a href="{{link}}" style="background:#c8102e;color:#fff;padding:12px 28px;border-radius:6px;text-decoration:none;font-weight:bold;">
|
|
View Request
|
|
</a>
|
|
</div>
|
|
<p style="color:#888;font-size:12px;">
|
|
For queries, contact your assigned Area Sales Manager.
|
|
</p>
|
|
</div>
|
|
</div>`,
|
|
placeholders: ['requestId', 'dealerName', 'targetStage', 'link', 'remarks']
|
|
},
|
|
|
|
// ── 3. F&F Initiated ───────────────────────────────────────────────────
|
|
// Used in: resignation.controller.ts (when F&F is triggered on LWD)
|
|
// termination.controller.ts (post-termination F&F)
|
|
// Recipients: Finance team, Department heads, DD-Admin
|
|
// Channels: system + email
|
|
{
|
|
templateCode: 'FNF_INITIATED',
|
|
description: 'Notifies Finance and department heads when Full & Final (F&F) settlement is triggered on the Last Working Day.',
|
|
subject: 'F&F Settlement Initiated — {{requestId}}',
|
|
body: `
|
|
<div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:20px;">
|
|
<div style="background:#c8102e;padding:20px;border-radius:8px 8px 0 0;">
|
|
<h2 style="color:#fff;margin:0;font-size:20px;">Full & Final Settlement Initiated</h2>
|
|
</div>
|
|
<div style="background:#f9f9f9;padding:24px;border-radius:0 0 8px 8px;border:1px solid #eee;">
|
|
<p>Dear {{recipientName}},</p>
|
|
<p>
|
|
The Full & Final (F&F) settlement process has been initiated for dealer
|
|
<strong>{{dealerName}}</strong> (Request: <strong>{{requestId}}</strong>).
|
|
</p>
|
|
<table style="width:100%;border-collapse:collapse;margin:16px 0;">
|
|
<tr style="background:#f0f0f0;">
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Request ID</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{requestId}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Dealer Name</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{dealerName}}</td>
|
|
</tr>
|
|
<tr style="background:#f0f0f0;">
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Last Working Day</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{lwd}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Initiated By</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{initiatedBy}}</td>
|
|
</tr>
|
|
</table>
|
|
<p>Please update your department clearance status promptly.</p>
|
|
<div style="text-align:center;margin:24px 0;">
|
|
<a href="{{link}}" style="background:#c8102e;color:#fff;padding:12px 28px;border-radius:6px;text-decoration:none;font-weight:bold;">
|
|
View F&F Settlement
|
|
</a>
|
|
</div>
|
|
<p style="color:#888;font-size:12px;">
|
|
Per Royal Enfield policy, F&F settlement is initiated only on or after the Last Working Day.
|
|
</p>
|
|
</div>
|
|
</div>`,
|
|
placeholders: ['recipientName', 'dealerName', 'requestId', 'lwd', 'initiatedBy', 'link']
|
|
},
|
|
|
|
// ── 4. EOR Completed ───────────────────────────────────────────────────
|
|
// Used in: eor.controller.ts (when all EOR checklist items are complete)
|
|
// Recipients: DD-Head, NBH
|
|
// Channels: system (alert only — no email per SRS §6.19.3.4 design choice)
|
|
// Adding email template so Admin can optionally enable
|
|
{
|
|
templateCode: 'EOR_COMPLETED',
|
|
description: 'Alert to DD-Head and NBH when 100% of EOR (Essential Operating Requirements) checklist items are verified. Signals readiness for Inauguration stage.',
|
|
subject: 'EOR Checklist Complete — Ready for Inauguration: {{requestId}}',
|
|
body: `
|
|
<div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:20px;">
|
|
<div style="background:#2e7d32;padding:20px;border-radius:8px 8px 0 0;">
|
|
<h2 style="color:#fff;margin:0;font-size:20px;">✓ EOR Checklist — 100% Complete</h2>
|
|
</div>
|
|
<div style="background:#f9f9f9;padding:24px;border-radius:0 0 8px 8px;border:1px solid #eee;">
|
|
<p>Dear {{recipientName}},</p>
|
|
<p>
|
|
All <strong>Essential Operating Requirements (EOR)</strong> for dealer application
|
|
<strong>{{requestId}}</strong> (Applicant: <strong>{{applicantName}}</strong>)
|
|
have been completed and verified.
|
|
</p>
|
|
<div style="background:#e8f5e9;border-left:4px solid #43a047;padding:12px 16px;margin:16px 0;">
|
|
<strong>EOR Status: 100% Complete</strong><br/>
|
|
The dealership is now ready for Inauguration review.
|
|
</div>
|
|
<table style="width:100%;border-collapse:collapse;margin:16px 0;">
|
|
<tr style="background:#f0f0f0;">
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Application ID</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{requestId}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Applicant</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{applicantName}}</td>
|
|
</tr>
|
|
<tr style="background:#f0f0f0;">
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Location</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{location}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Completed On</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{completedOn}}</td>
|
|
</tr>
|
|
</table>
|
|
<p>Please review and authorize the <strong>Inauguration</strong> stage to mark this dealership as Live.</p>
|
|
<div style="text-align:center;margin:24px 0;">
|
|
<a href="{{link}}" style="background:#2e7d32;color:#fff;padding:12px 28px;border-radius:6px;text-decoration:none;font-weight:bold;">
|
|
Authorize Inauguration
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>`,
|
|
placeholders: ['recipientName', 'applicantName', 'requestId', 'location', 'completedOn', 'link']
|
|
},
|
|
|
|
// ── 5. Applicant Rejected ──────────────────────────────────────────────
|
|
// Used in: WorkflowService.transitionApplication (any rejection)
|
|
// Recipients: Applicant (external)
|
|
// Channels: email (SRS §6.12.3 — rejection via email)
|
|
// WhatsApp if mobileNumber present
|
|
{
|
|
templateCode: 'APPLICANT_REJECTED',
|
|
description: 'Sent to the applicant/dealer when their application is rejected at any stage of the onboarding process.',
|
|
subject: 'Update on Your Dealership Application — {{applicationId}}',
|
|
body: `
|
|
<div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:20px;">
|
|
<div style="background:#b71c1c;padding:20px;border-radius:8px 8px 0 0;">
|
|
<h2 style="color:#fff;margin:0;font-size:20px;">Application Status Update</h2>
|
|
</div>
|
|
<div style="background:#f9f9f9;padding:24px;border-radius:0 0 8px 8px;border:1px solid #eee;">
|
|
<p>Dear {{applicantName}},</p>
|
|
<p>
|
|
We regret to inform you that your Royal Enfield Dealership Application
|
|
(<strong>{{applicationId}}</strong>) for location <strong>{{location}}</strong>
|
|
has been <strong>rejected</strong> after careful evaluation.
|
|
</p>
|
|
{{#if rejectionReason}}
|
|
<div style="background:#fff3f3;border-left:4px solid #e53935;padding:12px 16px;margin:16px 0;">
|
|
<strong>Reason:</strong><br/>{{rejectionReason}}
|
|
</div>
|
|
{{/if}}
|
|
<p>
|
|
We appreciate your interest in partnering with Royal Enfield. You may reapply
|
|
when opportunities are available in your area in the future.
|
|
</p>
|
|
<p>
|
|
For any queries, contact us at
|
|
<a href="mailto:dealer-support@royalenfield.com">dealer-support@royalenfield.com</a>.
|
|
</p>
|
|
<p>Best Regards,<br/><strong>Royal Enfield Dealer Development Team</strong></p>
|
|
</div>
|
|
</div>`,
|
|
placeholders: ['applicantName', 'applicationId', 'location', 'rejectionReason']
|
|
},
|
|
|
|
// ── 6. Termination Initiated ───────────────────────────────────────────
|
|
// Used in: termination.controller.ts (case creation)
|
|
// Recipients: RBM, DD-ZM, ZBH, DD-Lead, Legal, NBH
|
|
// Channels: system + email + whatsapp
|
|
{
|
|
templateCode: 'TERMINATION_INITIATED',
|
|
description: 'Notifies internal stakeholders (RBM, DD-ZM, ZBH, Legal, NBH) when a dealer termination case is formally initiated by ASM.',
|
|
subject: 'Dealer Termination Case Initiated — {{requestId}}',
|
|
body: `
|
|
<div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:20px;">
|
|
<div style="background:#4a148c;padding:20px;border-radius:8px 8px 0 0;">
|
|
<h2 style="color:#fff;margin:0;font-size:20px;">Dealer Termination Case Initiated</h2>
|
|
</div>
|
|
<div style="background:#f9f9f9;padding:24px;border-radius:0 0 8px 8px;border:1px solid #eee;">
|
|
<p>Dear {{recipientName}},</p>
|
|
<p>
|
|
A formal termination process has been initiated for dealer
|
|
<strong>{{dealerName}}</strong> (Request ID: <strong>{{requestId}}</strong>).
|
|
</p>
|
|
<table style="width:100%;border-collapse:collapse;margin:16px 0;">
|
|
<tr style="background:#f0f0f0;">
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Request ID</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{requestId}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Dealer Name</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{dealerName}}</td>
|
|
</tr>
|
|
<tr style="background:#f0f0f0;">
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Termination Category</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{category}}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Initiated By</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{initiatedBy}}</td>
|
|
</tr>
|
|
<tr style="background:#f0f0f0;">
|
|
<td style="padding:8px;border:1px solid #ddd;"><strong>Current Stage</strong></td>
|
|
<td style="padding:8px;border:1px solid #ddd;">{{currentStage}}</td>
|
|
</tr>
|
|
</table>
|
|
{{#if remarks}}
|
|
<div style="background:#fff8e1;border-left:4px solid #fb8c00;padding:12px 16px;margin:16px 0;">
|
|
<strong>Remarks:</strong><br/>{{remarks}}
|
|
</div>
|
|
{{/if}}
|
|
<p>Please review the case and provide your evaluation with mandatory work notes.</p>
|
|
<div style="text-align:center;margin:24px 0;">
|
|
<a href="{{link}}" style="background:#4a148c;color:#fff;padding:12px 28px;border-radius:6px;text-decoration:none;font-weight:bold;">
|
|
Review Termination Case
|
|
</a>
|
|
</div>
|
|
<p style="color:#888;font-size:12px;">
|
|
This notification is confidential. Do not share externally without authorization.
|
|
</p>
|
|
</div>
|
|
</div>`,
|
|
placeholders: ['recipientName', 'dealerName', 'requestId', 'category', 'initiatedBy', 'currentStage', 'remarks', 'link']
|
|
}
|
|
];
|
|
|
|
for (const t of templates) {
|
|
const [, created] = await db.EmailTemplate.upsert({
|
|
...t,
|
|
isActive: true
|
|
});
|
|
console.log(`${created ? 'Created' : 'Updated'}: ${t.templateCode}`);
|
|
}
|
|
|
|
console.log('\n--- Missing Templates Seeded Successfully ---');
|
|
console.log(`Total: ${templates.length} templates seeded.`);
|
|
process.exit(0);
|
|
} catch (error) {
|
|
console.error('Error seeding missing templates:', error);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
seedMissingTemplates();
|