csv filed issue on unique transaction no and also dealer claim templates enhanced
This commit is contained in:
parent
89beffee2e
commit
9c003e9a16
@ -1 +1 @@
|
|||||||
import{a as s}from"./index-DDuRVIKn.js";import"./radix-vendor-CYvDqP9X.js";import"./charts-vendor-BVfwAPj-.js";import"./utils-vendor-BTBPSQfW.js";import"./ui-vendor-CxsBWvVP.js";import"./socket-vendor-TjCxX7sJ.js";import"./redux-vendor-tbZCm13o.js";import"./router-vendor-BATWUvr6.js";async function m(n){return(await s.post(`/conclusions/${n}/generate`)).data.data}async function f(n,t){return(await s.post(`/conclusions/${n}/finalize`,{finalRemark:t})).data.data}async function d(n){var t;try{return(await s.get(`/conclusions/${n}`)).data.data}catch(o){if(((t=o.response)==null?void 0:t.status)===404)return null;throw o}}export{f as finalizeConclusion,m as generateConclusion,d as getConclusion};
|
import{a as s}from"./index-DK9CP9m9.js";import"./radix-vendor-CYvDqP9X.js";import"./charts-vendor-BVfwAPj-.js";import"./utils-vendor-BTBPSQfW.js";import"./ui-vendor-CxsBWvVP.js";import"./socket-vendor-TjCxX7sJ.js";import"./redux-vendor-tbZCm13o.js";import"./router-vendor-BATWUvr6.js";async function m(n){return(await s.post(`/conclusions/${n}/generate`)).data.data}async function f(n,t){return(await s.post(`/conclusions/${n}/finalize`,{finalRemark:t})).data.data}async function d(n){var t;try{return(await s.get(`/conclusions/${n}`)).data.data}catch(o){if(((t=o.response)==null?void 0:t.status)===404)return null;throw o}}export{f as finalizeConclusion,m as generateConclusion,d as getConclusion};
|
||||||
File diff suppressed because one or more lines are too long
@ -13,7 +13,7 @@
|
|||||||
<!-- Preload essential fonts and icons -->
|
<!-- Preload essential fonts and icons -->
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<script type="module" crossorigin src="/assets/index-DDuRVIKn.js"></script>
|
<script type="module" crossorigin src="/assets/index-DK9CP9m9.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="/assets/charts-vendor-BVfwAPj-.js">
|
<link rel="modulepreload" crossorigin href="/assets/charts-vendor-BVfwAPj-.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/radix-vendor-CYvDqP9X.js">
|
<link rel="modulepreload" crossorigin href="/assets/radix-vendor-CYvDqP9X.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/utils-vendor-BTBPSQfW.js">
|
<link rel="modulepreload" crossorigin href="/assets/utils-vendor-BTBPSQfW.js">
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ApprovalRequestData } from './types';
|
import { ApprovalRequestData } from './types';
|
||||||
import { getEmailFooter, getPrioritySection, getEmailHeader, HeaderStyles, getResponsiveStyles, wrapRichText, getEmailContainerStyles } from './helpers';
|
import { getEmailFooter, getPrioritySection, getEmailHeader, HeaderStyles, getResponsiveStyles, wrapRichText, getEmailContainerStyles, getCustomMessageSection } from './helpers';
|
||||||
import { getBrandedHeader } from './branding.config';
|
import { getBrandedHeader } from './branding.config';
|
||||||
|
|
||||||
export function getApprovalRequestEmail(data: ApprovalRequestData): string {
|
export function getApprovalRequestEmail(data: ApprovalRequestData): string {
|
||||||
@ -102,6 +102,9 @@ export function getApprovalRequestEmail(data: ApprovalRequestData): string {
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- Custom Message Section -->
|
||||||
|
${getCustomMessageSection(data.customMessage)}
|
||||||
|
|
||||||
<!-- Description (supports rich text HTML including tables) -->
|
<!-- Description (supports rich text HTML including tables) -->
|
||||||
<div style="margin-bottom: 30px;">
|
<div style="margin-bottom: 30px;">
|
||||||
<h3 style="margin: 0 0 15px; color: #333333; font-size: 16px; font-weight: 600;">Description:</h3>
|
<h3 style="margin: 0 0 15px; color: #333333; font-size: 16px; font-weight: 600;">Description:</h3>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DealerProposalRequiredData } from './types';
|
import { DealerProposalRequiredData } from './types';
|
||||||
import { getEmailFooter, getPrioritySection, getEmailHeader, HeaderStyles, getResponsiveStyles, wrapRichText, getEmailContainerStyles } from './helpers';
|
import { getEmailFooter, getPrioritySection, getEmailHeader, HeaderStyles, getResponsiveStyles, wrapRichText, getEmailContainerStyles, getCustomMessageSection } from './helpers';
|
||||||
import { getBrandedHeader } from './branding.config';
|
import { getBrandedHeader } from './branding.config';
|
||||||
|
|
||||||
export function getDealerCompletionRequiredEmail(data: DealerProposalRequiredData): string {
|
export function getDealerCompletionRequiredEmail(data: DealerProposalRequiredData): string {
|
||||||
@ -103,6 +103,9 @@ export function getDealerCompletionRequiredEmail(data: DealerProposalRequiredDat
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- Custom Message Section -->
|
||||||
|
${getCustomMessageSection(data.customMessage)}
|
||||||
|
|
||||||
<div style="padding: 20px; background-color: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px; margin-bottom: 30px;">
|
<div style="padding: 20px; background-color: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px; margin-bottom: 30px;">
|
||||||
<h3 style="margin: 0 0 10px; color: #856404; font-size: 16px; font-weight: 600;">What You Need to Submit:</h3>
|
<h3 style="margin: 0 0 10px; color: #856404; font-size: 16px; font-weight: 600;">What You Need to Submit:</h3>
|
||||||
<ul style="margin: 0; padding: 0 0 0 20px; color: #666666; font-size: 14px; line-height: 1.6;">
|
<ul style="margin: 0; padding: 0 0 0 20px; color: #666666; font-size: 14px; line-height: 1.6;">
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DealerProposalRequiredData } from './types';
|
import { DealerProposalRequiredData } from './types';
|
||||||
import { getEmailFooter, getPrioritySection, getEmailHeader, HeaderStyles, getResponsiveStyles, wrapRichText, getEmailContainerStyles } from './helpers';
|
import { getEmailFooter, getPrioritySection, getEmailHeader, HeaderStyles, getResponsiveStyles, wrapRichText, getEmailContainerStyles, getCustomMessageSection } from './helpers';
|
||||||
import { getBrandedHeader } from './branding.config';
|
import { getBrandedHeader } from './branding.config';
|
||||||
|
|
||||||
export function getDealerProposalRequiredEmail(data: DealerProposalRequiredData): string {
|
export function getDealerProposalRequiredEmail(data: DealerProposalRequiredData): string {
|
||||||
@ -152,6 +152,9 @@ export function getDealerProposalRequiredEmail(data: DealerProposalRequiredData)
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- Custom Message Section -->
|
||||||
|
${getCustomMessageSection(data.customMessage)}
|
||||||
|
|
||||||
<!-- Description (supports rich text HTML including tables) -->
|
<!-- Description (supports rich text HTML including tables) -->
|
||||||
${data.requestDescription ? `
|
${data.requestDescription ? `
|
||||||
<div style="margin-bottom: 30px;">
|
<div style="margin-bottom: 30px;">
|
||||||
|
|||||||
@ -32,7 +32,8 @@ export enum EmailNotificationType {
|
|||||||
COMPLETION_DOCUMENTS_SUBMITTED = 'completion_documents_submitted',
|
COMPLETION_DOCUMENTS_SUBMITTED = 'completion_documents_submitted',
|
||||||
EINVOICE_GENERATED = 'einvoice_generated',
|
EINVOICE_GENERATED = 'einvoice_generated',
|
||||||
CREDIT_NOTE_SENT = 'credit_note_sent',
|
CREDIT_NOTE_SENT = 'credit_note_sent',
|
||||||
ADDITIONAL_DOCUMENT_ADDED = 'additional_document_added'
|
ADDITIONAL_DOCUMENT_ADDED = 'additional_document_added',
|
||||||
|
RE_QUOTATION = 're_quotation',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -799,6 +799,22 @@ export function getRoleDescription(role: 'Approver' | 'Spectator'): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate custom message section (e.g., for re-quotation notes)
|
||||||
|
*/
|
||||||
|
export function getCustomMessageSection(message?: string): string {
|
||||||
|
if (!message) return '';
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div style="margin-bottom: 30px; padding: 20px; background-color: #f0f7ff; border-left: 4px solid #667eea; border-radius: 4px;">
|
||||||
|
<h3 style="margin: 0 0 10px; color: #333333; font-size: 16px; font-weight: 600;">Note/Instructions:</h3>
|
||||||
|
<p style="margin: 0; color: #444444; font-size: 15px; line-height: 1.6; font-style: italic;">
|
||||||
|
"${message}"
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate action required section for workflow resumed
|
* Generate action required section for workflow resumed
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -15,7 +15,7 @@ export function getRejectionNotificationEmail(data: RejectionNotificationData):
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<title>Request Rejected</title>
|
<title>${data.isReturnedForRevision ? 'Request Returned for Revision' : 'Request Rejected'}</title>
|
||||||
${getResponsiveStyles()}
|
${getResponsiveStyles()}
|
||||||
</head>
|
</head>
|
||||||
<body style="margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; background-color: #f4f4f4;">
|
<body style="margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; background-color: #f4f4f4;">
|
||||||
@ -24,63 +24,65 @@ export function getRejectionNotificationEmail(data: RejectionNotificationData):
|
|||||||
<td style="padding: 40px 0;">
|
<td style="padding: 40px 0;">
|
||||||
<table role="presentation" class="email-container" style="${getEmailContainerStyles()}" cellpadding="0" cellspacing="0">
|
<table role="presentation" class="email-container" style="${getEmailContainerStyles()}" cellpadding="0" cellspacing="0">
|
||||||
${getEmailHeader(getBrandedHeader({
|
${getEmailHeader(getBrandedHeader({
|
||||||
title: 'Request Rejected',
|
title: data.isReturnedForRevision ? 'Revision Required' : 'Request Rejected',
|
||||||
...HeaderStyles.error
|
...(data.isReturnedForRevision ? HeaderStyles.warning : HeaderStyles.error)
|
||||||
}))}
|
}))}
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 40px 30px;">
|
<td style="padding: 40px 30px;">
|
||||||
<p style="margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;">
|
<p style="margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;">
|
||||||
Dear <strong style="color: #dc3545;">${data.initiatorName}</strong>,
|
Dear <strong style="color: ${data.isReturnedForRevision ? '#856404' : '#dc3545'};">${data.initiatorName}</strong>,
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p style="margin: 0 0 30px; color: #666666; font-size: 16px; line-height: 1.6;">
|
<p style="margin: 0 0 30px; color: #666666; font-size: 16px; line-height: 1.6;">
|
||||||
We regret to inform you that your request has been <strong style="color: #dc3545;">rejected</strong> by <strong>${data.approverName}</strong>.
|
${data.isReturnedForRevision
|
||||||
|
? `Your request has been <strong>returned for revision</strong> by <strong>${data.approverName}</strong>.`
|
||||||
|
: `We regret to inform you that your request has been <strong style="color: #dc3545;">rejected</strong> by <strong>${data.approverName}</strong>.`}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<table role="presentation" style="width: 100%; border-collapse: collapse; background-color: #f8d7da; border: 1px solid #f5c6cb; border-radius: 6px; margin-bottom: 30px;" cellpadding="0" cellspacing="0">
|
<table role="presentation" style="width: 100%; border-collapse: collapse; background-color: ${data.isReturnedForRevision ? '#fff3cd' : '#f8d7da'}; border: 1px solid ${data.isReturnedForRevision ? '#ffeeba' : '#f5c6cb'}; border-radius: 6px; margin-bottom: 30px;" cellpadding="0" cellspacing="0">
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 25px;">
|
<td style="padding: 25px;">
|
||||||
<h2 style="margin: 0 0 20px; color: #721c24; font-size: 18px; font-weight: 600;">Request Summary</h2>
|
<h2 style="margin: 0 0 20px; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 18px; font-weight: 600;">Request Summary</h2>
|
||||||
|
|
||||||
<table role="presentation" style="width: 100%; border-collapse: collapse;" cellpadding="0" cellspacing="0">
|
<table role="presentation" style="width: 100%; border-collapse: collapse;" cellpadding="0" cellspacing="0">
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px; width: 140px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px; width: 140px;">
|
||||||
<strong>Request ID:</strong>
|
<strong>Request ID:</strong>
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
${data.requestId}
|
${data.requestId}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
<strong>Rejected By:</strong>
|
<strong>Action By:</strong>
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
${data.approverName}
|
${data.approverName}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
<strong>Rejected On:</strong>
|
<strong>Action On:</strong>
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
${data.rejectionDate}
|
${data.rejectionDate}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
<strong>Time:</strong>
|
<strong>Time:</strong>
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
${data.rejectionTime}
|
${data.rejectionTime}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
<strong>Request Type:</strong>
|
<strong>Request Type:</strong>
|
||||||
</td>
|
</td>
|
||||||
<td style="padding: 8px 0; color: #721c24; font-size: 14px;">
|
<td style="padding: 8px 0; color: ${data.isReturnedForRevision ? '#856404' : '#721c24'}; font-size: 14px;">
|
||||||
${data.requestType}
|
${data.requestType}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -90,8 +92,8 @@ export function getRejectionNotificationEmail(data: RejectionNotificationData):
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div style="margin-bottom: 30px;">
|
<div style="margin-bottom: 30px;">
|
||||||
<h3 style="margin: 0 0 15px; color: #333333; font-size: 16px; font-weight: 600;">Reason for Rejection:</h3>
|
<h3 style="margin: 0 0 15px; color: #333333; font-size: 16px; font-weight: 600;">${data.isReturnedForRevision ? 'Reason for Revision:' : 'Reason for Rejection:'}</h3>
|
||||||
<div style="padding: 15px; background-color: #f8f9fa; border-left: 4px solid #dc3545; border-radius: 4px; overflow-x: auto;">
|
<div style="padding: 15px; background-color: #f8f9fa; border-left: 4px solid ${data.isReturnedForRevision ? '#ffc107' : '#dc3545'}; border-radius: 4px; overflow-x: auto;">
|
||||||
${wrapRichText(data.rejectionReason)}
|
${wrapRichText(data.rejectionReason)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -99,9 +101,13 @@ export function getRejectionNotificationEmail(data: RejectionNotificationData):
|
|||||||
<div style="padding: 20px; background-color: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px; margin-bottom: 30px;">
|
<div style="padding: 20px; background-color: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px; margin-bottom: 30px;">
|
||||||
<h3 style="margin: 0 0 10px; color: #856404; font-size: 16px; font-weight: 600;">What You Can Do:</h3>
|
<h3 style="margin: 0 0 10px; color: #856404; font-size: 16px; font-weight: 600;">What You Can Do:</h3>
|
||||||
<ul style="margin: 10px 0 0 0; padding-left: 20px; color: #856404; font-size: 14px; line-height: 1.8;">
|
<ul style="margin: 10px 0 0 0; padding-left: 20px; color: #856404; font-size: 14px; line-height: 1.8;">
|
||||||
<li>Review the rejection reason carefully</li>
|
${data.isReturnedForRevision
|
||||||
|
? `<li>Review the requested changes carefully</li>
|
||||||
|
<li>Adjust the proposal or documents as needed</li>
|
||||||
|
<li>Resubmit the request for approval</li>`
|
||||||
|
: `<li>Review the rejection reason carefully</li>
|
||||||
<li>Make necessary adjustments to your request</li>
|
<li>Make necessary adjustments to your request</li>
|
||||||
<li>Submit a new request with the required changes</li>
|
<li>Submit a new request with the required changes</li>`}
|
||||||
<li>Contact ${data.approverName} for more clarification if needed</li>
|
<li>Contact ${data.approverName} for more clarification if needed</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -47,6 +47,7 @@ export interface ApprovalRequestData extends BaseEmailData {
|
|||||||
requestType: string;
|
requestType: string;
|
||||||
requestDescription: string;
|
requestDescription: string;
|
||||||
priority: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
priority: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
||||||
|
customMessage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MultiApproverRequestData extends ApprovalRequestData {
|
export interface MultiApproverRequestData extends ApprovalRequestData {
|
||||||
@ -80,6 +81,7 @@ export interface RejectionNotificationData extends BaseEmailData {
|
|||||||
rejectionTime: string;
|
rejectionTime: string;
|
||||||
requestType: string;
|
requestType: string;
|
||||||
rejectionReason: string;
|
rejectionReason: string;
|
||||||
|
isReturnedForRevision?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TATReminderData extends BaseEmailData {
|
export interface TATReminderData extends BaseEmailData {
|
||||||
@ -250,6 +252,7 @@ export interface DealerProposalRequiredData extends BaseEmailData {
|
|||||||
priority: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
priority: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
||||||
tatHours?: number;
|
tatHours?: number;
|
||||||
dueDate?: string;
|
dueDate?: string;
|
||||||
|
customMessage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AdditionalDocumentAddedData extends BaseEmailData {
|
export interface AdditionalDocumentAddedData extends BaseEmailData {
|
||||||
|
|||||||
@ -3615,7 +3615,7 @@ export class DealerClaimService {
|
|||||||
|
|
||||||
const csvData = invoiceItems.map((item: any) => {
|
const csvData = invoiceItems.map((item: any) => {
|
||||||
const row: any = {
|
const row: any = {
|
||||||
TRNS_UNIQ_NO: isNonGst ? '' : (item.transactionCode || ''),
|
TRNS_UNIQ_NO: item.transactionCode || '',
|
||||||
CLAIM_NUMBER: requestNumber,
|
CLAIM_NUMBER: requestNumber,
|
||||||
INV_NUMBER: invoice.invoiceNumber || '',
|
INV_NUMBER: invoice.invoiceNumber || '',
|
||||||
DEALER_CODE: claimDetails.dealerCode,
|
DEALER_CODE: claimDetails.dealerCode,
|
||||||
|
|||||||
@ -849,6 +849,23 @@ export class DealerClaimApprovalService {
|
|||||||
tatPercentageUsed: 0
|
tatPercentageUsed: 0
|
||||||
} as any);
|
} as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger Re-Quotation Notification (Email + Push)
|
||||||
|
if (step1.approverId) {
|
||||||
|
await notificationService.sendToUsers([step1.approverId], {
|
||||||
|
title: `Revised Quotation Requested: ${(wf as any).requestNumber}`,
|
||||||
|
body: action.rejectionReason || action.comments || 'Please revise and resubmit your quotation.',
|
||||||
|
requestNumber: (wf as any).requestNumber,
|
||||||
|
requestId: level.requestId,
|
||||||
|
url: `/request/${(wf as any).requestNumber}`,
|
||||||
|
type: 're_quotation',
|
||||||
|
priority: 'HIGH',
|
||||||
|
actionRequired: true,
|
||||||
|
metadata: {
|
||||||
|
rejectionReason: action.rejectionReason || action.comments
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -888,10 +905,10 @@ export class DealerClaimApprovalService {
|
|||||||
userAgent: requestMetadata?.userAgent || undefined
|
userAgent: requestMetadata?.userAgent || undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
// Notify the approver of the target level
|
// Notify the approver of the target level (skip if specific re-quotation notification was already sent)
|
||||||
if (targetLevel.approverId) {
|
if (targetLevel.approverId && !isReQuotation) {
|
||||||
await notificationService.sendToUsers([targetLevel.approverId], {
|
await notificationService.sendToUsers([targetLevel.approverId], {
|
||||||
title: `Request Returned: ${(wf as any).requestNumber}`,
|
title: `Request Returned for Revision: ${(wf as any).requestNumber}`,
|
||||||
body: `Request "${(wf as any).title}" has been returned to your level for revision. Reason: ${action.rejectionReason || action.comments || 'No reason provided'}`,
|
body: `Request "${(wf as any).title}" has been returned to your level for revision. Reason: ${action.rejectionReason || action.comments || 'No reason provided'}`,
|
||||||
requestNumber: (wf as any).requestNumber,
|
requestNumber: (wf as any).requestNumber,
|
||||||
requestId: level.requestId,
|
requestId: level.requestId,
|
||||||
@ -903,9 +920,12 @@ export class DealerClaimApprovalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify initiator when request is returned
|
// Notify initiator when request is returned
|
||||||
|
// Skip if they are the same as the dealer (who already got a more specific notification)
|
||||||
|
const dealerId = targetLevel.approverId;
|
||||||
|
if ((wf as any).initiatorId && (wf as any).initiatorId !== dealerId) {
|
||||||
await notificationService.sendToUsers([(wf as any).initiatorId], {
|
await notificationService.sendToUsers([(wf as any).initiatorId], {
|
||||||
title: `Request Returned: ${(wf as any).requestNumber}`,
|
title: `Request Returned: ${(wf as any).requestNumber}`,
|
||||||
body: `Request "${(wf as any).title}" has been returned to level ${targetLevel.levelNumber} for revision. Reason: ${action.rejectionReason || action.comments || 'No reason provided'}`,
|
body: `Request "${(wf as any).title}" has been returned to Step ${targetLevel.levelNumber} for revision. Reason: ${action.rejectionReason || action.comments || 'No reason provided'}`,
|
||||||
requestNumber: (wf as any).requestNumber,
|
requestNumber: (wf as any).requestNumber,
|
||||||
requestId: level.requestId,
|
requestId: level.requestId,
|
||||||
url: `/request/${(wf as any).requestNumber}`,
|
url: `/request/${(wf as any).requestNumber}`,
|
||||||
@ -913,6 +933,7 @@ export class DealerClaimApprovalService {
|
|||||||
priority: 'MEDIUM'
|
priority: 'MEDIUM'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Emit real-time update to all users viewing this request
|
// Emit real-time update to all users viewing this request
|
||||||
emitToRequestRoom(level.requestId, 'request:updated', {
|
emitToRequestRoom(level.requestId, 'request:updated', {
|
||||||
|
|||||||
@ -92,26 +92,6 @@ export class DealerClaimEmailService implements IWorkflowEmailService {
|
|||||||
(levelName.includes('completion') || levelName.includes('documents')) &&
|
(levelName.includes('completion') || levelName.includes('documents')) &&
|
||||||
!levelName.includes('proposal'); // Explicitly exclude proposal
|
!levelName.includes('proposal'); // Explicitly exclude proposal
|
||||||
|
|
||||||
// Safety check: If proposal already submitted, don't send proposal email
|
|
||||||
// This prevents sending proposal email if levelName somehow matches both conditions
|
|
||||||
if (isDealerProposalStep && requestData.requestId) {
|
|
||||||
try {
|
|
||||||
const { DealerProposalDetails } = await import('@models/DealerProposalDetails');
|
|
||||||
const existingProposal = await DealerProposalDetails.findOne({
|
|
||||||
where: { requestId: requestData.requestId }
|
|
||||||
});
|
|
||||||
if (existingProposal) {
|
|
||||||
logger.warn(`[DealerClaimEmail] ⚠️ Proposal already submitted but levelName indicates proposal step. Forcing completion step.`);
|
|
||||||
// If proposal exists, this MUST be completion step, not proposal
|
|
||||||
await this.sendDealerCompletionRequiredEmail(requestData, approverUser, initiatorData, level);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
logger.error(`[DealerClaimEmail] Error checking proposal:`, e);
|
|
||||||
// Continue with normal flow if check fails
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Route to appropriate template
|
// Route to appropriate template
|
||||||
if (isDealerCompletionStep) {
|
if (isDealerCompletionStep) {
|
||||||
logger.info(`[DealerClaimEmail] ✅ DEALER COMPLETION step - sending completion documents required email`);
|
logger.info(`[DealerClaimEmail] ✅ DEALER COMPLETION step - sending completion documents required email`);
|
||||||
@ -224,6 +204,18 @@ export class DealerClaimEmailService implements IWorkflowEmailService {
|
|||||||
where: { requestId: requestData.requestId }
|
where: { requestId: requestData.requestId }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Determine stage-specific instructions
|
||||||
|
let stageInstructions = '';
|
||||||
|
const name = (currentLevel?.levelName || '').toLowerCase();
|
||||||
|
|
||||||
|
if (name.includes('evaluation') || name.includes('requestor evaluation')) {
|
||||||
|
stageInstructions = 'Please evaluate the proposal submitted by the dealer. Verify the activity details and estimated budget.';
|
||||||
|
} else if (name.includes('lead') || name.includes('department lead')) {
|
||||||
|
stageInstructions = 'The requestor has evaluated this proposal and recommended it for your approval. Please review and provide your authorization.';
|
||||||
|
} else if (name.includes('claim approval') && name.includes('requestor')) {
|
||||||
|
stageInstructions = 'The dealer has submitted completion documents. Please verify the expenses and documents before providing final claim approval.';
|
||||||
|
}
|
||||||
|
|
||||||
// Enrich requestData with dealer claim-specific information
|
// Enrich requestData with dealer claim-specific information
|
||||||
const enrichedRequestData = {
|
const enrichedRequestData = {
|
||||||
...requestData,
|
...requestData,
|
||||||
@ -256,7 +248,8 @@ export class DealerClaimEmailService implements IWorkflowEmailService {
|
|||||||
approverData,
|
approverData,
|
||||||
initiatorData,
|
initiatorData,
|
||||||
false, // isMultiLevel = false for dealer claim workflows
|
false, // isMultiLevel = false for dealer claim workflows
|
||||||
undefined // No approval chain needed
|
undefined, // No approval chain needed
|
||||||
|
stageInstructions // Pass as customMessage (contextual instruction)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -144,7 +144,8 @@ export class EmailNotificationService {
|
|||||||
approverData: any,
|
approverData: any,
|
||||||
initiatorData: any,
|
initiatorData: any,
|
||||||
isMultiLevel: boolean,
|
isMultiLevel: boolean,
|
||||||
approvalChain?: any[]
|
approvalChain?: any[],
|
||||||
|
customMessage?: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
// Check preferences
|
// Check preferences
|
||||||
@ -185,7 +186,8 @@ export class EmailNotificationService {
|
|||||||
totalApprovers: approvalChain.length,
|
totalApprovers: approvalChain.length,
|
||||||
approversList: chainData,
|
approversList: chainData,
|
||||||
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
||||||
companyName: CompanyInfo.name
|
companyName: CompanyInfo.name,
|
||||||
|
customMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
const html = getMultiApproverRequestEmail(data);
|
const html = getMultiApproverRequestEmail(data);
|
||||||
@ -214,7 +216,8 @@ export class EmailNotificationService {
|
|||||||
requestDate: this.formatDate(requestData.createdAt),
|
requestDate: this.formatDate(requestData.createdAt),
|
||||||
requestTime: this.formatTime(requestData.createdAt),
|
requestTime: this.formatTime(requestData.createdAt),
|
||||||
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
||||||
companyName: CompanyInfo.name
|
companyName: CompanyInfo.name,
|
||||||
|
customMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
const html = getApprovalRequestEmail(data);
|
const html = getApprovalRequestEmail(data);
|
||||||
@ -298,6 +301,14 @@ export class EmailNotificationService {
|
|||||||
rejectionReason: string
|
rejectionReason: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
// 1. Skip if approver is the same as initiator
|
||||||
|
if (approverData.userId && initiatorData.userId && approverData.userId === initiatorData.userId) {
|
||||||
|
logger.info(`Email skipped: Approver ${approverData.userId} is the initiator, no need to notify self of rejection/return`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isReturnedForRevision = rejectionReason.includes('Revised Quotation Requested');
|
||||||
|
|
||||||
// Use override for high-priority emails
|
// Use override for high-priority emails
|
||||||
const canSend = await shouldSendEmailWithOverride(
|
const canSend = await shouldSendEmailWithOverride(
|
||||||
initiatorData.userId,
|
initiatorData.userId,
|
||||||
@ -319,11 +330,14 @@ export class EmailNotificationService {
|
|||||||
requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
|
requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
|
||||||
rejectionReason,
|
rejectionReason,
|
||||||
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
||||||
companyName: CompanyInfo.name
|
companyName: CompanyInfo.name,
|
||||||
|
isReturnedForRevision
|
||||||
};
|
};
|
||||||
|
|
||||||
const html = getRejectionNotificationEmail(data);
|
const html = getRejectionNotificationEmail(data);
|
||||||
const subject = `${requestData.requestNumber} - ${requestData.title} - Request Rejected`;
|
const subject = isReturnedForRevision
|
||||||
|
? `${requestData.requestNumber} - ${requestData.title} - Request Returned for Revision`
|
||||||
|
: `${requestData.requestNumber} - ${requestData.title} - Request Rejected`;
|
||||||
|
|
||||||
const result = await emailService.sendEmail({
|
const result = await emailService.sendEmail({
|
||||||
to: initiatorData.email,
|
to: initiatorData.email,
|
||||||
@ -927,7 +941,8 @@ export class EmailNotificationService {
|
|||||||
requestData: any,
|
requestData: any,
|
||||||
dealerData: any,
|
dealerData: any,
|
||||||
initiatorData: any,
|
initiatorData: any,
|
||||||
claimData?: any
|
claimData?: any,
|
||||||
|
customMessage?: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const canSend = await shouldSendEmail(
|
const canSend = await shouldSendEmail(
|
||||||
@ -944,7 +959,7 @@ export class EmailNotificationService {
|
|||||||
let dueDate: string | undefined;
|
let dueDate: string | undefined;
|
||||||
if (claimData?.tatHours) {
|
if (claimData?.tatHours) {
|
||||||
const dueDateObj = dayjs().add(claimData.tatHours, 'hour');
|
const dueDateObj = dayjs().add(claimData.tatHours, 'hour');
|
||||||
dueDate = dueDateObj.format('MMMM D, YYYY [at] h:mm A');
|
dueDate = dueDateObj.format('MMMM D, YYYY');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: DealerProposalRequiredData = {
|
const data: DealerProposalRequiredData = {
|
||||||
@ -965,7 +980,8 @@ export class EmailNotificationService {
|
|||||||
tatHours: claimData?.tatHours,
|
tatHours: claimData?.tatHours,
|
||||||
dueDate: dueDate,
|
dueDate: dueDate,
|
||||||
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
||||||
companyName: CompanyInfo.name
|
companyName: CompanyInfo.name,
|
||||||
|
customMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
const html = getDealerProposalRequiredEmail(data);
|
const html = getDealerProposalRequiredEmail(data);
|
||||||
@ -988,22 +1004,24 @@ export class EmailNotificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 12b. Send Dealer Completion Documents Required Email
|
* 12a. Send Re-Quotation Required Email
|
||||||
|
* (Uses Proposal Required template with custom subject and rejection reason)
|
||||||
*/
|
*/
|
||||||
async sendDealerCompletionRequired(
|
async sendReQuotationRequired(
|
||||||
requestData: any,
|
requestData: any,
|
||||||
dealerData: any,
|
dealerData: any,
|
||||||
initiatorData: any,
|
initiatorData: any,
|
||||||
claimData?: any
|
claimData: any,
|
||||||
|
rejectionReason: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const canSend = await shouldSendEmail(
|
const canSend = await shouldSendEmail(
|
||||||
dealerData.userId,
|
dealerData.userId,
|
||||||
EmailNotificationType.APPROVAL_REQUEST // Use approval_request type for preferences
|
EmailNotificationType.RE_QUOTATION
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!canSend) {
|
if (!canSend) {
|
||||||
logger.info(`Email skipped (preferences): Dealer Completion Required for ${dealerData.email}`);
|
logger.info(`Email skipped (preferences): Re-Quotation Required for ${dealerData.email}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,7 +1029,7 @@ export class EmailNotificationService {
|
|||||||
let dueDate: string | undefined;
|
let dueDate: string | undefined;
|
||||||
if (claimData?.tatHours) {
|
if (claimData?.tatHours) {
|
||||||
const dueDateObj = dayjs().add(claimData.tatHours, 'hour');
|
const dueDateObj = dayjs().add(claimData.tatHours, 'hour');
|
||||||
dueDate = dueDateObj.format('MMMM D, YYYY [at] h:mm A');
|
dueDate = dueDateObj.format('MMMM D, YYYY');
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: DealerProposalRequiredData = {
|
const data: DealerProposalRequiredData = {
|
||||||
@ -1032,7 +1050,77 @@ export class EmailNotificationService {
|
|||||||
tatHours: claimData?.tatHours,
|
tatHours: claimData?.tatHours,
|
||||||
dueDate: dueDate,
|
dueDate: dueDate,
|
||||||
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
||||||
companyName: CompanyInfo.name
|
companyName: CompanyInfo.name,
|
||||||
|
customMessage: rejectionReason
|
||||||
|
};
|
||||||
|
|
||||||
|
const html = getDealerProposalRequiredEmail(data);
|
||||||
|
const subject = `[${requestData.requestNumber}] Revised Quotation Requested - ${data.activityName}`;
|
||||||
|
|
||||||
|
const result = await emailService.sendEmail({
|
||||||
|
to: dealerData.email,
|
||||||
|
subject,
|
||||||
|
html
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.previewUrl) {
|
||||||
|
logger.info(`📧 Re-Quotation Required Email Preview: ${result.previewUrl}`);
|
||||||
|
}
|
||||||
|
logger.info(`✅ Re-Quotation Required email sent to ${dealerData.email} for request ${requestData.requestNumber}`);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Failed to send Re-Quotation Required email:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 12b. Send Dealer Completion Documents Required Email
|
||||||
|
*/
|
||||||
|
async sendDealerCompletionRequired(
|
||||||
|
requestData: any,
|
||||||
|
dealerData: any,
|
||||||
|
initiatorData: any,
|
||||||
|
claimData?: any,
|
||||||
|
customMessage?: string
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
const canSend = await shouldSendEmail(
|
||||||
|
dealerData.userId,
|
||||||
|
EmailNotificationType.APPROVAL_REQUEST // Use approval_request type for preferences
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!canSend) {
|
||||||
|
logger.info(`Email skipped (preferences): Dealer Completion Required for ${dealerData.email}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate due date from TAT if available
|
||||||
|
let dueDate: string | undefined;
|
||||||
|
if (claimData?.tatHours) {
|
||||||
|
const dueDateObj = dayjs().add(claimData.tatHours, 'hour');
|
||||||
|
dueDate = dueDateObj.format('MMMM D, YYYY');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: DealerProposalRequiredData = {
|
||||||
|
recipientName: dealerData.displayName || dealerData.email,
|
||||||
|
requestId: requestData.requestNumber,
|
||||||
|
requestTitle: requestData.title,
|
||||||
|
dealerName: dealerData.displayName || dealerData.email || claimData?.dealerName || 'Dealer',
|
||||||
|
initiatorName: initiatorData.displayName || initiatorData.email,
|
||||||
|
activityName: claimData?.activityName || requestData.title,
|
||||||
|
activityType: claimData?.activityType || 'N/A',
|
||||||
|
activityDate: claimData?.activityDate ? this.formatDate(claimData.activityDate) : undefined,
|
||||||
|
location: claimData?.location,
|
||||||
|
estimatedBudget: claimData?.estimatedBudget,
|
||||||
|
requestDate: this.formatDate(requestData.createdAt),
|
||||||
|
requestTime: this.formatTime(requestData.createdAt),
|
||||||
|
requestDescription: requestData.description || '',
|
||||||
|
priority: requestData.priority || 'MEDIUM',
|
||||||
|
tatHours: claimData?.tatHours,
|
||||||
|
dueDate: dueDate,
|
||||||
|
viewDetailsLink: getViewDetailsLink(requestData.requestNumber, this.frontendUrl),
|
||||||
|
companyName: CompanyInfo.name,
|
||||||
|
customMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
const html = getDealerCompletionRequiredEmail(data);
|
const html = getDealerCompletionRequiredEmail(data);
|
||||||
|
|||||||
@ -315,6 +315,7 @@ class NotificationService {
|
|||||||
'form16_debit_note': null,
|
'form16_debit_note': null,
|
||||||
'form16_alert_submit': null,
|
'form16_alert_submit': null,
|
||||||
'form16_reminder': null,
|
'form16_reminder': null,
|
||||||
|
're_quotation': EmailNotificationType.RE_QUOTATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
const emailType = emailTypeMap[payload.type || ''];
|
const emailType = emailTypeMap[payload.type || ''];
|
||||||
@ -482,12 +483,16 @@ class NotificationService {
|
|||||||
order: [['levelNumber', 'ASC']]
|
order: [['levelNumber', 'ASC']]
|
||||||
});
|
});
|
||||||
|
|
||||||
// Find the level that matches this approver - PRIORITIZE PENDING LEVEL
|
// Find the level that matches this approver and the current request level
|
||||||
// This ensures that if a user has multiple steps (e.g., Step 1 and Step 2),
|
// This ensures we pick the step that actually needs action (e.g. Step 1 for re-quotation)
|
||||||
// we pick the one that actually needs action (Step 2) rather than the first one (Step 1)
|
const currentLevelNumber = requestData.currentLevel;
|
||||||
let matchingLevel = allLevels.find((l: any) => l.approverId === userId && l.status === 'PENDING');
|
let matchingLevel = allLevels.find((l: any) => l.approverId === userId && l.levelNumber === currentLevelNumber);
|
||||||
|
|
||||||
|
// Fallback to any level if no exact match found (e.g. if currentLevel isn't set yet)
|
||||||
|
if (!matchingLevel) {
|
||||||
|
matchingLevel = allLevels.find((l: any) => l.approverId === userId && l.status === 'PENDING');
|
||||||
|
}
|
||||||
|
|
||||||
// Fallback to any level if no pending level found (though for assignment there should be one)
|
|
||||||
if (!matchingLevel) {
|
if (!matchingLevel) {
|
||||||
matchingLevel = allLevels.find((l: any) => l.approverId === userId);
|
matchingLevel = allLevels.find((l: any) => l.approverId === userId);
|
||||||
}
|
}
|
||||||
@ -1138,6 +1143,25 @@ class NotificationService {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 're_quotation':
|
||||||
|
{
|
||||||
|
const dealerData = payload.metadata?.dealerData || { userId: null, email: payload.metadata?.dealerEmail, displayName: payload.metadata?.dealerName };
|
||||||
|
const rejectionReason = payload.body || payload.metadata?.rejectionReason || 'Revised Quotation Requested';
|
||||||
|
|
||||||
|
// Get claim info if available
|
||||||
|
const { DealerClaimDetails } = await import('@models/index');
|
||||||
|
const claim = await DealerClaimDetails.findOne({ where: { requestId: payload.requestId } });
|
||||||
|
|
||||||
|
await emailNotificationService.sendReQuotationRequired(
|
||||||
|
requestData,
|
||||||
|
dealerData,
|
||||||
|
initiatorData,
|
||||||
|
claim ? claim.toJSON() : {},
|
||||||
|
rejectionReason
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger.info(`[Email] No email configured for notification type: ${notificationType}`);
|
logger.info(`[Email] No email configured for notification type: ${notificationType}`);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user