blocked amount decimal accuracy fixed and the email template modified to show non-tempatized as type

This commit is contained in:
laxmanhalaki 2026-01-08 19:21:12 +05:30
parent 743f90d1a9
commit 077fe78e8a
12 changed files with 139 additions and 110 deletions

View File

@ -1,2 +1,2 @@
import{a as s}from"./index-BtWUMn8R.js";import"./radix-vendor-DIkYAdWy.js";import"./charts-vendor-Bme4E5cb.js";import"./utils-vendor-DHm03ykU.js";import"./ui-vendor-CdaLA-IN.js";import"./socket-vendor-TjCxX7sJ.js";import"./redux-vendor-tbZCm13o.js";import"./router-vendor-AvM4PHvP.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-Be7X0Sj8.js";import"./radix-vendor-DIkYAdWy.js";import"./charts-vendor-Bme4E5cb.js";import"./utils-vendor-DHm03ykU.js";import"./ui-vendor-CdaLA-IN.js";import"./socket-vendor-TjCxX7sJ.js";import"./redux-vendor-tbZCm13o.js";import"./router-vendor-AvM4PHvP.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};
//# sourceMappingURL=conclusionApi-t9LwHY2s.js.map //# sourceMappingURL=conclusionApi-92p3rlzy.js.map

View File

@ -1 +1 @@
{"version":3,"file":"conclusionApi-t9LwHY2s.js","sources":["../../src/services/conclusionApi.ts"],"sourcesContent":["import apiClient from './authApi';\r\n\r\nexport interface ConclusionRemark {\r\n conclusionId: string;\r\n requestId: string;\r\n aiGeneratedRemark: string | null;\r\n aiModelUsed: string | null;\r\n aiConfidenceScore: number | null;\r\n finalRemark: string | null;\r\n editedBy: string | null;\r\n isEdited: boolean;\r\n editCount: number;\r\n approvalSummary: any;\r\n documentSummary: any;\r\n keyDiscussionPoints: string[];\r\n generatedAt: string | null;\r\n finalizedAt: string | null;\r\n createdAt: string;\r\n updatedAt: string;\r\n}\r\n\r\n/**\r\n * Generate AI-powered conclusion remark\r\n */\r\nexport async function generateConclusion(requestId: string): Promise<{\r\n conclusionId: string;\r\n aiGeneratedRemark: string;\r\n keyDiscussionPoints: string[];\r\n confidence: number;\r\n generatedAt: string;\r\n}> {\r\n const response = await apiClient.post(`/conclusions/${requestId}/generate`);\r\n return response.data.data;\r\n}\r\n\r\n/**\r\n * Update conclusion remark (edit by initiator)\r\n */\r\nexport async function updateConclusion(requestId: string, finalRemark: string): Promise<ConclusionRemark> {\r\n const response = await apiClient.put(`/conclusions/${requestId}`, { finalRemark });\r\n return response.data.data;\r\n}\r\n\r\n/**\r\n * Finalize conclusion and close request\r\n */\r\nexport async function finalizeConclusion(requestId: string, finalRemark: string): Promise<{\r\n conclusionId: string;\r\n requestNumber: string;\r\n status: string;\r\n finalRemark: string;\r\n finalizedAt: string;\r\n}> {\r\n const response = await apiClient.post(`/conclusions/${requestId}/finalize`, { finalRemark });\r\n return response.data.data;\r\n}\r\n\r\n/**\r\n * Get conclusion for a request\r\n * Returns null if conclusion doesn't exist (404) instead of throwing error\r\n */\r\nexport async function getConclusion(requestId: string): Promise<ConclusionRemark | null> {\r\n try {\r\n const response = await apiClient.get(`/conclusions/${requestId}`);\r\n return response.data.data;\r\n } catch (error: any) {\r\n // Handle 404 gracefully - conclusion doesn't exist yet, which is normal\r\n if (error.response?.status === 404) {\r\n return null;\r\n }\r\n // Re-throw other errors\r\n throw error;\r\n }\r\n}\r\n\r\n"],"names":["generateConclusion","requestId","apiClient","finalizeConclusion","finalRemark","getConclusion","error","_a"],"mappings":"6RAwBA,eAAsBA,EAAmBC,EAMtC,CAED,OADiB,MAAMC,EAAU,KAAK,gBAAgBD,CAAS,WAAW,GAC1D,KAAK,IACvB,CAaA,eAAsBE,EAAmBF,EAAmBG,EAMzD,CAED,OADiB,MAAMF,EAAU,KAAK,gBAAgBD,CAAS,YAAa,CAAE,YAAAG,EAAa,GAC3E,KAAK,IACvB,CAMA,eAAsBC,EAAcJ,EAAqD,OACvF,GAAI,CAEF,OADiB,MAAMC,EAAU,IAAI,gBAAgBD,CAAS,EAAE,GAChD,KAAK,IACvB,OAASK,EAAY,CAEnB,KAAIC,EAAAD,EAAM,WAAN,YAAAC,EAAgB,UAAW,IAC7B,OAAO,KAGT,MAAMD,CACR,CACF"} {"version":3,"file":"conclusionApi-92p3rlzy.js","sources":["../../src/services/conclusionApi.ts"],"sourcesContent":["import apiClient from './authApi';\r\n\r\nexport interface ConclusionRemark {\r\n conclusionId: string;\r\n requestId: string;\r\n aiGeneratedRemark: string | null;\r\n aiModelUsed: string | null;\r\n aiConfidenceScore: number | null;\r\n finalRemark: string | null;\r\n editedBy: string | null;\r\n isEdited: boolean;\r\n editCount: number;\r\n approvalSummary: any;\r\n documentSummary: any;\r\n keyDiscussionPoints: string[];\r\n generatedAt: string | null;\r\n finalizedAt: string | null;\r\n createdAt: string;\r\n updatedAt: string;\r\n}\r\n\r\n/**\r\n * Generate AI-powered conclusion remark\r\n */\r\nexport async function generateConclusion(requestId: string): Promise<{\r\n conclusionId: string;\r\n aiGeneratedRemark: string;\r\n keyDiscussionPoints: string[];\r\n confidence: number;\r\n generatedAt: string;\r\n}> {\r\n const response = await apiClient.post(`/conclusions/${requestId}/generate`);\r\n return response.data.data;\r\n}\r\n\r\n/**\r\n * Update conclusion remark (edit by initiator)\r\n */\r\nexport async function updateConclusion(requestId: string, finalRemark: string): Promise<ConclusionRemark> {\r\n const response = await apiClient.put(`/conclusions/${requestId}`, { finalRemark });\r\n return response.data.data;\r\n}\r\n\r\n/**\r\n * Finalize conclusion and close request\r\n */\r\nexport async function finalizeConclusion(requestId: string, finalRemark: string): Promise<{\r\n conclusionId: string;\r\n requestNumber: string;\r\n status: string;\r\n finalRemark: string;\r\n finalizedAt: string;\r\n}> {\r\n const response = await apiClient.post(`/conclusions/${requestId}/finalize`, { finalRemark });\r\n return response.data.data;\r\n}\r\n\r\n/**\r\n * Get conclusion for a request\r\n * Returns null if conclusion doesn't exist (404) instead of throwing error\r\n */\r\nexport async function getConclusion(requestId: string): Promise<ConclusionRemark | null> {\r\n try {\r\n const response = await apiClient.get(`/conclusions/${requestId}`);\r\n return response.data.data;\r\n } catch (error: any) {\r\n // Handle 404 gracefully - conclusion doesn't exist yet, which is normal\r\n if (error.response?.status === 404) {\r\n return null;\r\n }\r\n // Re-throw other errors\r\n throw error;\r\n }\r\n}\r\n\r\n"],"names":["generateConclusion","requestId","apiClient","finalizeConclusion","finalRemark","getConclusion","error","_a"],"mappings":"6RAwBA,eAAsBA,EAAmBC,EAMtC,CAED,OADiB,MAAMC,EAAU,KAAK,gBAAgBD,CAAS,WAAW,GAC1D,KAAK,IACvB,CAaA,eAAsBE,EAAmBF,EAAmBG,EAMzD,CAED,OADiB,MAAMF,EAAU,KAAK,gBAAgBD,CAAS,YAAa,CAAE,YAAAG,EAAa,GAC3E,KAAK,IACvB,CAMA,eAAsBC,EAAcJ,EAAqD,OACvF,GAAI,CAEF,OADiB,MAAMC,EAAU,IAAI,gBAAgBD,CAAS,EAAE,GAChD,KAAK,IACvB,OAASK,EAAY,CAEnB,KAAIC,EAAAD,EAAM,WAAN,YAAAC,EAAgB,UAAW,IAC7B,OAAO,KAGT,MAAMD,CACR,CACF"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -52,7 +52,7 @@
transition: transform 0.2s ease; transition: transform 0.2s ease;
} }
</style> </style>
<script type="module" crossorigin src="/assets/index-BtWUMn8R.js"></script> <script type="module" crossorigin src="/assets/index-Be7X0Sj8.js"></script>
<link rel="modulepreload" crossorigin href="/assets/charts-vendor-Bme4E5cb.js"> <link rel="modulepreload" crossorigin href="/assets/charts-vendor-Bme4E5cb.js">
<link rel="modulepreload" crossorigin href="/assets/radix-vendor-DIkYAdWy.js"> <link rel="modulepreload" crossorigin href="/assets/radix-vendor-DIkYAdWy.js">
<link rel="modulepreload" crossorigin href="/assets/utils-vendor-DHm03ykU.js"> <link rel="modulepreload" crossorigin href="/assets/utils-vendor-DHm03ykU.js">
@ -60,7 +60,7 @@
<link rel="modulepreload" crossorigin href="/assets/socket-vendor-TjCxX7sJ.js"> <link rel="modulepreload" crossorigin href="/assets/socket-vendor-TjCxX7sJ.js">
<link rel="modulepreload" crossorigin href="/assets/redux-vendor-tbZCm13o.js"> <link rel="modulepreload" crossorigin href="/assets/redux-vendor-tbZCm13o.js">
<link rel="modulepreload" crossorigin href="/assets/router-vendor-AvM4PHvP.js"> <link rel="modulepreload" crossorigin href="/assets/router-vendor-AvM4PHvP.js">
<link rel="stylesheet" crossorigin href="/assets/index-Cki_huzr.css"> <link rel="stylesheet" crossorigin href="/assets/index-CB8CcL1-.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@ -866,3 +866,29 @@ export function getEmailFooter(config: EmailFooterConfig | string): string {
`; `;
} }
/**
* Get display label for template type
* Maps backend templateType values to user-friendly labels
*
* @param templateType - The template type from the request (e.g., 'CUSTOM', 'DEALER CLAIM', 'TEMPLATE')
* @returns User-friendly label for display in emails
*/
export function getTemplateTypeLabel(templateType?: string): string {
if (!templateType) return 'Non-Templatized';
const upper = templateType.toUpperCase();
// Handle dealer claim variations
if (upper === 'DEALER CLAIM' || upper === 'DEALER_CLAIM' || upper === 'CLAIM-MANAGEMENT' || upper === 'CLAIM_MANAGEMENT') {
return 'Dealer Claim';
}
// Handle template type
if (upper === 'TEMPLATE') {
return 'Template';
}
// Default for CUSTOM or any other value
return 'Non-Templatized';
}

View File

@ -1418,14 +1418,15 @@ export class DealerClaimService {
organizedByUserId?: string organizedByUserId?: string
): Promise<void> { ): Promise<void> {
try { try {
const blockedAmount = ioData.blockedAmount || 0; // Ensure blockedAmount is rounded to exactly 2 decimal places from the start
const blockedAmount = ioData.blockedAmount ? parseFloat(ioData.blockedAmount.toFixed(2)) : 0;
// If blocking amount > 0, proceed with SAP integration and blocking // If blocking amount > 0, proceed with SAP integration and blocking
// If blocking amount is 0 but ioNumber and ioRemark are provided, just save the IO details without blocking // If blocking amount is 0 but ioNumber is provided, just save the IO details without blocking
if (blockedAmount <= 0) { if (blockedAmount <= 0) {
// Allow saving IO details (ioNumber, ioRemark) even without blocking amount // Allow saving IO details (ioNumber only) even without blocking amount
// This is useful when Step 3 is approved but amount hasn't been blocked yet // This is useful when Requestor Evaluation is in progress but amount hasn't been blocked yet
if (ioData.ioNumber && (ioData.ioRemark !== undefined)) { if (ioData.ioNumber) {
const organizedBy = organizedByUserId || null; const organizedBy = organizedByUserId || null;
// Create or update Internal Order record with just IO details (no blocking) // Create or update Internal Order record with just IO details (no blocking)
@ -1434,7 +1435,7 @@ export class DealerClaimService {
defaults: { defaults: {
requestId, requestId,
ioNumber: ioData.ioNumber, ioNumber: ioData.ioNumber,
ioRemark: ioData.ioRemark || '', ioRemark: ioData.ioRemark || '', // Optional - kept for backward compatibility // Optional - keep for backward compatibility
ioAvailableBalance: ioData.availableBalance || 0, ioAvailableBalance: ioData.availableBalance || 0,
ioBlockedAmount: 0, ioBlockedAmount: 0,
ioRemainingBalance: ioData.remainingBalance || 0, ioRemainingBalance: ioData.remainingBalance || 0,
@ -1447,10 +1448,9 @@ export class DealerClaimService {
if (!created) { if (!created) {
// Update existing IO record with new IO details // Update existing IO record with new IO details
// IMPORTANT: When updating existing record, preserve balance fields from previous blocking // IMPORTANT: When updating existing record, preserve balance fields from previous blocking
// Only update ioNumber and ioRemark - don't overwrite balance values // Only update ioNumber - don't overwrite balance values
await internalOrder.update({ await internalOrder.update({
ioNumber: ioData.ioNumber, ioNumber: ioData.ioNumber,
ioRemark: ioData.ioRemark || '',
// Don't update balance fields for existing records - preserve values from previous blocking // Don't update balance fields for existing records - preserve values from previous blocking
// Only update organizedBy and organizedAt // Only update organizedBy and organizedAt
organizedBy: organizedBy || internalOrder.organizedBy, organizedBy: organizedBy || internalOrder.organizedBy,
@ -1459,7 +1459,6 @@ export class DealerClaimService {
logger.info(`[DealerClaimService] IO details updated (preserved existing balance values) for request: ${requestId}`, { logger.info(`[DealerClaimService] IO details updated (preserved existing balance values) for request: ${requestId}`, {
ioNumber: ioData.ioNumber, ioNumber: ioData.ioNumber,
ioRemark: ioData.ioRemark,
preservedAvailableBalance: internalOrder.ioAvailableBalance, preservedAvailableBalance: internalOrder.ioAvailableBalance,
preservedBlockedAmount: internalOrder.ioBlockedAmount, preservedBlockedAmount: internalOrder.ioBlockedAmount,
preservedRemainingBalance: internalOrder.ioRemainingBalance, preservedRemainingBalance: internalOrder.ioRemainingBalance,
@ -1467,13 +1466,12 @@ export class DealerClaimService {
} }
logger.info(`[DealerClaimService] IO details saved (without blocking) for request: ${requestId}`, { logger.info(`[DealerClaimService] IO details saved (without blocking) for request: ${requestId}`, {
ioNumber: ioData.ioNumber, ioNumber: ioData.ioNumber
ioRemark: ioData.ioRemark
}); });
return; // Exit early - no SAP blocking needed return; // Exit early - no SAP blocking needed
} else { } else {
throw new Error('Blocked amount must be greater than 0, or ioNumber and ioRemark must be provided'); throw new Error('Blocked amount must be greater than 0, or ioNumber must be provided');
} }
} }
@ -1511,7 +1509,8 @@ export class DealerClaimService {
// Extract SAP reference number from blockId (this is the Sap_Reference_no from SAP response) // Extract SAP reference number from blockId (this is the Sap_Reference_no from SAP response)
// Only use the actual SAP reference number - don't use any generated fallback // Only use the actual SAP reference number - don't use any generated fallback
const sapDocumentNumber = blockResult.blockId || undefined; const sapDocumentNumber = blockResult.blockId || undefined;
const availableBalance = ioData.availableBalance || ioValidation.availableBalance; // Ensure availableBalance is rounded to 2 decimal places for accurate calculations
const availableBalance = parseFloat((ioData.availableBalance || ioValidation.availableBalance).toFixed(2));
// Log if SAP reference number was received // Log if SAP reference number was received
if (sapDocumentNumber) { if (sapDocumentNumber) {
@ -1551,11 +1550,13 @@ export class DealerClaimService {
// Calculate remaining balance: availableBalance - requestedAmount // Calculate remaining balance: availableBalance - requestedAmount
// IMPORTANT: Use the amount we REQUESTED, not SAP's returned amount (unless SAP blocked significantly different amount) // IMPORTANT: Use the amount we REQUESTED, not SAP's returned amount (unless SAP blocked significantly different amount)
// This ensures accuracy: remaining = available - requested // This ensures accuracy: remaining = available - requested
const calculatedRemainingBalance = availableBalance - finalBlockedAmount; // Round to 2 decimal places to avoid floating point precision issues
const calculatedRemainingBalance = parseFloat((availableBalance - finalBlockedAmount).toFixed(2));
// Only use SAP's value if it's valid AND matches our calculation (within 1 rupee tolerance) // Only use SAP's value if it's valid AND matches our calculation (within 1 rupee tolerance)
// This is a safety check - if SAP's value is way off, use our calculation // This is a safety check - if SAP's value is way off, use our calculation
const sapRemainingBalance = blockResult.remainingBalance; // Round SAP's value to 2 decimal places for consistency
const sapRemainingBalance = blockResult.remainingBalance ? parseFloat(blockResult.remainingBalance.toFixed(2)) : 0;
const sapValueIsValid = sapRemainingBalance > 0 && const sapValueIsValid = sapRemainingBalance > 0 &&
sapRemainingBalance <= availableBalance && sapRemainingBalance <= availableBalance &&
Math.abs(sapRemainingBalance - calculatedRemainingBalance) < 1; Math.abs(sapRemainingBalance - calculatedRemainingBalance) < 1;
@ -1564,8 +1565,8 @@ export class DealerClaimService {
? sapRemainingBalance ? sapRemainingBalance
: calculatedRemainingBalance; : calculatedRemainingBalance;
// Ensure remaining balance is not negative // Ensure remaining balance is not negative and round to 2 decimal places
const finalRemainingBalance = Math.max(0, remainingBalance); const finalRemainingBalance = parseFloat(Math.max(0, remainingBalance).toFixed(2));
// Warn if SAP's value doesn't match our calculation // Warn if SAP's value doesn't match our calculation
if (!sapValueIsValid && sapRemainingBalance !== calculatedRemainingBalance) { if (!sapValueIsValid && sapRemainingBalance !== calculatedRemainingBalance) {
@ -1583,16 +1584,17 @@ export class DealerClaimService {
// Get the user who is blocking the IO (current user) // Get the user who is blocking the IO (current user)
const organizedBy = organizedByUserId || null; const organizedBy = organizedByUserId || null;
// Round amounts to 2 decimal places for database storage (avoid floating point precision issues) // Round amounts to exactly 2 decimal places for database storage (avoid floating point precision issues)
const roundedAvailableBalance = Math.round(availableBalance * 100) / 100; // Use parseFloat with toFixed to ensure exact 2 decimal precision
const roundedBlockedAmount = Math.round(finalBlockedAmount * 100) / 100; const roundedAvailableBalance = parseFloat(availableBalance.toFixed(2));
const roundedRemainingBalance = Math.round(finalRemainingBalance * 100) / 100; const roundedBlockedAmount = parseFloat(finalBlockedAmount.toFixed(2));
const roundedRemainingBalance = parseFloat(finalRemainingBalance.toFixed(2));
// Create or update Internal Order record (only when blocking) // Create or update Internal Order record (only when blocking)
const ioRecordData = { const ioRecordData = {
requestId, requestId,
ioNumber: ioData.ioNumber, ioNumber: ioData.ioNumber,
ioRemark: ioData.ioRemark || '', ioRemark: ioData.ioRemark || '', // Optional - kept for backward compatibility
ioAvailableBalance: roundedAvailableBalance, ioAvailableBalance: roundedAvailableBalance,
ioBlockedAmount: roundedBlockedAmount, ioBlockedAmount: roundedBlockedAmount,
ioRemainingBalance: roundedRemainingBalance, ioRemainingBalance: roundedRemainingBalance,

View File

@ -29,6 +29,7 @@ import {
getCreditNoteSentEmail, getCreditNoteSentEmail,
getAdditionalDocumentAddedEmail, getAdditionalDocumentAddedEmail,
getViewDetailsLink, getViewDetailsLink,
getTemplateTypeLabel,
CompanyInfo, CompanyInfo,
RequestCreatedData, RequestCreatedData,
ApprovalRequestData, ApprovalRequestData,
@ -107,7 +108,7 @@ export class EmailNotificationService {
requestTitle: requestData.title, requestTitle: requestData.title,
initiatorName: initiatorData.displayName || initiatorData.email, initiatorName: initiatorData.displayName || initiatorData.email,
firstApproverName: firstApproverData.displayName || firstApproverData.email, firstApproverName: firstApproverData.displayName || firstApproverData.email,
requestType: requestData.templateType || requestData.requestType || 'CUSTOM', requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
priority: requestData.priority || 'MEDIUM', priority: requestData.priority || 'MEDIUM',
requestDate: this.formatDate(requestData.createdAt), requestDate: this.formatDate(requestData.createdAt),
requestTime: this.formatTime(requestData.createdAt), requestTime: this.formatTime(requestData.createdAt),
@ -175,7 +176,7 @@ export class EmailNotificationService {
requestTitle: requestData.title, requestTitle: requestData.title,
approverName: approverData.displayName || approverData.email, approverName: approverData.displayName || approverData.email,
initiatorName: initiatorData.displayName || initiatorData.email, initiatorName: initiatorData.displayName || initiatorData.email,
requestType: requestData.templateType || requestData.requestType || 'CUSTOM', requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
requestDescription: requestData.description || '', requestDescription: requestData.description || '',
priority: requestData.priority || 'MEDIUM', priority: requestData.priority || 'MEDIUM',
requestDate: this.formatDate(requestData.createdAt), requestDate: this.formatDate(requestData.createdAt),
@ -207,7 +208,7 @@ export class EmailNotificationService {
requestTitle: requestData.title, requestTitle: requestData.title,
approverName: approverData.displayName || approverData.email, approverName: approverData.displayName || approverData.email,
initiatorName: initiatorData.displayName || initiatorData.email, initiatorName: initiatorData.displayName || initiatorData.email,
requestType: requestData.templateType || requestData.requestType || 'CUSTOM', requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
requestDescription: requestData.description || '', requestDescription: requestData.description || '',
priority: requestData.priority || 'MEDIUM', priority: requestData.priority || 'MEDIUM',
requestDate: this.formatDate(requestData.createdAt), requestDate: this.formatDate(requestData.createdAt),
@ -262,7 +263,7 @@ export class EmailNotificationService {
approverName: approverData.displayName || approverData.email, approverName: approverData.displayName || approverData.email,
approvalDate: this.formatDate(approverData.approvedAt || new Date()), approvalDate: this.formatDate(approverData.approvedAt || new Date()),
approvalTime: this.formatTime(approverData.approvedAt || new Date()), approvalTime: this.formatTime(approverData.approvedAt || new Date()),
requestType: requestData.templateType || requestData.requestType || 'CUSTOM', requestType: getTemplateTypeLabel(requestData.templateType || requestData.requestType),
approverComments: approverData.comments || undefined, approverComments: approverData.comments || undefined,
isFinalApproval, isFinalApproval,
nextApproverName: nextApproverData?.displayName || nextApproverData?.email, nextApproverName: nextApproverData?.displayName || nextApproverData?.email,
@ -315,7 +316,7 @@ export class EmailNotificationService {
approverName: approverData.displayName || approverData.email, approverName: approverData.displayName || approverData.email,
rejectionDate: this.formatDate(approverData.rejectedAt || new Date()), rejectionDate: this.formatDate(approverData.rejectedAt || new Date()),
rejectionTime: this.formatTime(approverData.rejectedAt || new Date()), rejectionTime: this.formatTime(approverData.rejectedAt || new Date()),
requestType: requestData.templateType || requestData.requestType || 'CUSTOM', 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
@ -891,7 +892,7 @@ export class EmailNotificationService {
initiatorName: initiatorName, initiatorName: initiatorName,
requestId: requestData.requestNumber, requestId: requestData.requestNumber,
requestTitle: requestData.title, requestTitle: requestData.title,
requestType: requestData.templateType || requestData.workflowType || undefined, requestType: getTemplateTypeLabel(requestData.templateType || requestData.workflowType),
currentStatus: requestData.status || undefined, currentStatus: requestData.status || undefined,
addedDate: addedDate, addedDate: addedDate,
addedTime: addedTime, addedTime: addedTime,