new folder structure for the WFM added and credit note outgoing csv read flow added

This commit is contained in:
laxmanhalaki 2026-03-12 16:48:24 +05:30
parent 07577b4156
commit e4948e5cab
10 changed files with 147 additions and 50 deletions

View File

@ -1 +1 @@
import{a as s}from"./index-DyTD6GiQ.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-CrKGije_.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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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-DyTD6GiQ.js"></script> <script type="module" crossorigin src="/assets/index-CrKGije_.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">
@ -21,7 +21,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-BATWUvr6.js"> <link rel="modulepreload" crossorigin href="/assets/router-vendor-BATWUvr6.js">
<link rel="stylesheet" crossorigin href="/assets/index-8M2GI2Jv.css"> <link rel="stylesheet" crossorigin href="/assets/index-By1vJg8g.css">
</head> </head>
<body> <body>

View File

@ -73,6 +73,13 @@ RATE_LIMIT_MAX_REQUESTS=100
MAX_FILE_SIZE_MB=10 MAX_FILE_SIZE_MB=10
ALLOWED_FILE_TYPES=pdf,doc,docx,xls,xlsx,ppt,pptx,jpg,jpeg,png,gif ALLOWED_FILE_TYPES=pdf,doc,docx,xls,xlsx,ppt,pptx,jpg,jpeg,png,gif
# WFM Folder Structure Configuration
WFM_BASE_PATH=C:\\WFM
WFM_INCOMING_GST_CLAIMS_PATH=WFM-QRE\\INCOMING\\WFM_MAIN\\DLR_INC_CLAIMS_GST
WFM_INCOMING_NON_GST_CLAIMS_PATH=WFM-QRE\\INCOMING\\WFM_MAIN\\DLR_INC_CLAIMS_NON_GST
WFM_OUTGOING_GST_CLAIMS_PATH=WFM-QRE\\OUTGOING\\WFM_SAP_MAIN\\DLR_INC_CLAIMS_GST
WFM_OUTGOING_NON_GST_CLAIMS_PATH=WFM-QRE\\OUTGOING\\WFM_SAP_MAIN\\DLR_INC_CLAIMS_NON_GST
# TAT Monitoring # TAT Monitoring
TAT_CHECK_INTERVAL_MINUTES=30 TAT_CHECK_INTERVAL_MINUTES=30
TAT_REMINDER_THRESHOLD_1=50 TAT_REMINDER_THRESHOLD_1=50

View File

@ -1024,6 +1024,8 @@ export class DealerClaimController {
taxationType = activity?.taxationType || (claimDetails.activityType.toLowerCase().includes('non') ? 'Non GST' : 'GST'); taxationType = activity?.taxationType || (claimDetails.activityType.toLowerCase().includes('non') ? 'Non GST' : 'GST');
} }
const isNonGst = taxationType === 'Non GST' || taxationType === 'Non-GST';
// Construct CSV with pipe separator // Construct CSV with pipe separator
const headers = [ const headers = [
'TRNS_UNIQ_NO', 'TRNS_UNIQ_NO',
@ -1034,15 +1036,15 @@ export class DealerClaimController {
'CLAIM_DOC_TYP', 'CLAIM_DOC_TYP',
'CLAIM_TYPE', 'CLAIM_TYPE',
'CLAIM_DATE', 'CLAIM_DATE',
'CLAIM_AMT', 'CLAIM_AMT'
'GST_AMT',
'GST_PERCENTAGE'
]; ];
const rows = items.map(item => { if (!isNonGst) {
const isNonGst = taxationType === 'Non GST' || taxationType === 'Non-GST'; headers.push('GST_AMT', 'GST_PERCENTAGE');
}
// For Non-GST, we hide HSN (often stored in transactionCode) and GST details const rows = items.map(item => {
// For Non-GST, we hide HSN (often stored in transactionCode)
const trnsUniqNo = isNonGst ? '' : (item.transactionCode || ''); const trnsUniqNo = isNonGst ? '' : (item.transactionCode || '');
const claimNumber = requestNumber; const claimNumber = requestNumber;
const invNumber = invoice?.invoiceNumber || ''; const invNumber = invoice?.invoiceNumber || '';
@ -1053,11 +1055,7 @@ export class DealerClaimController {
const claimDate = invoice?.createdAt ? new Date(invoice.createdAt).toISOString().split('T')[0] : ''; const claimDate = invoice?.createdAt ? new Date(invoice.createdAt).toISOString().split('T')[0] : '';
const claimAmt = item.assAmt; const claimAmt = item.assAmt;
// Zero out tax for Non-GST const rowItems = [
const totalTax = isNonGst ? 0 : (Number(item.igstAmt || 0) + Number(item.cgstAmt || 0) + Number(item.sgstAmt || 0) + Number(item.utgstAmt || 0));
const gstPercentage = isNonGst ? 0 : (item.gstRt || 0);
return [
trnsUniqNo, trnsUniqNo,
claimNumber, claimNumber,
invNumber, invNumber,
@ -1066,10 +1064,15 @@ export class DealerClaimController {
claimDocTyp, claimDocTyp,
claimType, claimType,
claimDate, claimDate,
claimAmt, claimAmt
totalTax.toFixed(2), ];
gstPercentage
].join('|'); if (!isNonGst) {
const totalTax = Number(item.igstAmt || 0) + Number(item.cgstAmt || 0) + Number(item.sgstAmt || 0) + Number(item.utgstAmt || 0);
rowItems.push(totalTax.toFixed(2), item.gstRt || 0);
}
return rowItems.join('|');
}); });
const csvContent = [headers.join('|'), ...rows].join('\n'); const csvContent = [headers.join('|'), ...rows].join('\n');
@ -1112,4 +1115,43 @@ export class DealerClaimController {
return ResponseHandler.error(res, 'Failed to re-trigger WFM push', 500, errorMessage); return ResponseHandler.error(res, 'Failed to re-trigger WFM push', 500, errorMessage);
} }
} }
/**
* Fetch parsed WFM credit note CSV from outgoing folder
* GET /api/v1/dealer-claims/:requestId/credit-note-wfm
*/
async fetchCreditNoteWfm(req: Request, res: Response): Promise<void> {
try {
const identifier = req.params.requestId;
const workflow = await this.findWorkflowByIdentifier(identifier);
if (!workflow) {
return ResponseHandler.error(res, 'Workflow request not found', 404);
}
const requestId = (workflow as any).requestId || (workflow as any).request_id;
const requestNumber = (workflow as any).requestNumber || (workflow as any).request_number;
const claimDetails = await DealerClaimDetails.findOne({ where: { requestId } });
if (!claimDetails) {
return ResponseHandler.error(res, 'Dealer claim details not found', 404);
}
let isNonGst = false;
if (claimDetails.activityType) {
const activity = await ActivityType.findOne({ where: { title: claimDetails.activityType } });
const taxationType = activity?.taxationType || (claimDetails.activityType.toLowerCase().includes('non') ? 'Non GST' : 'GST');
isNonGst = taxationType === 'Non GST' || taxationType === 'Non-GST';
}
const { wfmFileService } = await import('../services/wfmFile.service');
const creditNoteData = await wfmFileService.getCreditNoteDetails(claimDetails.dealerCode, requestNumber, isNonGst);
return ResponseHandler.success(res, creditNoteData, 'Credit note data fetched successfully');
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
logger.error('[DealerClaimController] Error fetching credit note WFM data:', error);
return ResponseHandler.error(res, 'Failed to fetch credit note CSV data', 500, errorMessage);
}
}
} }

View File

@ -107,6 +107,7 @@ router.post('/:requestId/wfm/retrigger', authenticateToken, validateParams(reque
*/ */
router.get('/:requestId/e-invoice/csv', authenticateToken, validateParams(requestIdParamsSchema), asyncHandler(dealerClaimController.downloadInvoiceCsv.bind(dealerClaimController))); router.get('/:requestId/e-invoice/csv', authenticateToken, validateParams(requestIdParamsSchema), asyncHandler(dealerClaimController.downloadInvoiceCsv.bind(dealerClaimController)));
router.post('/:requestId/credit-note', authenticateToken, validateParams(requestIdParamsSchema), upload.single('creditNoteFile'), asyncHandler(malwareScanMiddleware), asyncHandler(dealerClaimController.updateCreditNote.bind(dealerClaimController))); router.post('/:requestId/credit-note', authenticateToken, validateParams(requestIdParamsSchema), upload.single('creditNoteFile'), asyncHandler(malwareScanMiddleware), asyncHandler(dealerClaimController.updateCreditNote.bind(dealerClaimController)));
router.get('/:requestId/credit-note-wfm', authenticateToken, validateParams(requestIdParamsSchema), asyncHandler(dealerClaimController.fetchCreditNoteWfm.bind(dealerClaimController)));
/** /**
* @route POST /api/v1/dealer-claims/:requestId/credit-note/send * @route POST /api/v1/dealer-claims/:requestId/credit-note/send

View File

@ -3596,9 +3596,13 @@ export class DealerClaimService {
if (invoiceItems.length > 0) { if (invoiceItems.length > 0) {
let sapRefNo = ''; let sapRefNo = '';
let isNonGst = false;
if (claimDetails.activityType) { if (claimDetails.activityType) {
const activity = await ActivityType.findOne({ where: { title: claimDetails.activityType } }); const activity = await ActivityType.findOne({ where: { title: claimDetails.activityType } });
sapRefNo = activity?.sapRefNo || ''; sapRefNo = activity?.sapRefNo || '';
const taxationType = activity?.taxationType || (claimDetails.activityType.toLowerCase().includes('non') ? 'Non GST' : 'GST');
isNonGst = taxationType === 'Non GST' || taxationType === 'Non-GST';
} }
const formatDate = (date: any) => { const formatDate = (date: any) => {
@ -3610,10 +3614,8 @@ export class DealerClaimService {
}; };
const csvData = invoiceItems.map((item: any) => { const csvData = invoiceItems.map((item: any) => {
const totalTax = Number(item.igstAmt || 0) + Number(item.cgstAmt || 0) + Number(item.sgstAmt || 0) + Number(item.utgstAmt || 0); const row: any = {
TRNS_UNIQ_NO: isNonGst ? '' : (item.transactionCode || ''),
return {
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,
@ -3621,13 +3623,19 @@ export class DealerClaimService {
CLAIM_DOC_TYP: sapRefNo, CLAIM_DOC_TYP: sapRefNo,
CLAIM_TYPE: claimDetails.activityType, CLAIM_TYPE: claimDetails.activityType,
CLAIM_DATE: formatDate(invoice.invoiceDate || new Date()), CLAIM_DATE: formatDate(invoice.invoiceDate || new Date()),
CLAIM_AMT: item.assAmt, CLAIM_AMT: item.assAmt
GST_AMT: totalTax.toFixed(2),
GST_PERCENTAGE: item.gstRt
}; };
if (!isNonGst) {
const totalTax = Number(item.igstAmt || 0) + Number(item.cgstAmt || 0) + Number(item.sgstAmt || 0) + Number(item.utgstAmt || 0);
row.GST_AMT = totalTax.toFixed(2);
row.GST_PERCENTAGE = item.gstRt;
}
return row;
}); });
await wfmFileService.generateIncomingClaimCSV(csvData, `CN_${claimDetails.dealerCode}_${requestNumber}.csv`); await wfmFileService.generateIncomingClaimCSV(csvData, `CN_${claimDetails.dealerCode}_${requestNumber}.csv`, isNonGst);
await invoice.update({ await invoice.update({
wfmPushStatus: 'SUCCESS', wfmPushStatus: 'SUCCESS',

View File

@ -8,13 +8,17 @@ import logger from '../utils/logger';
*/ */
export class WFMFileService { export class WFMFileService {
private basePath: string; private basePath: string;
private incomingClaimsPath: string; private incomingGstClaimsPath: string;
private outgoingClaimsPath: string; private incomingNonGstClaimsPath: string;
private outgoingGstClaimsPath: string;
private outgoingNonGstClaimsPath: string;
constructor() { constructor() {
this.basePath = process.env.WFM_BASE_PATH || 'C:\\WFM'; this.basePath = process.env.WFM_BASE_PATH || 'C:\\WFM';
this.incomingClaimsPath = process.env.WFM_INCOMING_CLAIMS_PATH || 'WFM-QRE\\INCOMING\\WFM_MAIN\\DLR_INC_CLAIMS'; this.incomingGstClaimsPath = process.env.WFM_INCOMING_GST_CLAIMS_PATH || 'WFM-QRE\\INCOMING\\WFM_MAIN\\DLR_INC_CLAIMS_GST';
this.outgoingClaimsPath = process.env.WFM_OUTGOING_CLAIMS_PATH || 'WFM-QRE\\OUTGOING\\WFM_SAP_MAIN\\DLR_INC_CLAIMS'; this.incomingNonGstClaimsPath = process.env.WFM_INCOMING_NON_GST_CLAIMS_PATH || 'WFM-QRE\\INCOMING\\WFM_MAIN\\DLR_INC_CLAIMS_NON_GST';
this.outgoingGstClaimsPath = process.env.WFM_OUTGOING_GST_CLAIMS_PATH || 'WFM-QRE\\OUTGOING\\WFM_SAP_MAIN\\DLR_INC_CLAIMS_GST';
this.outgoingNonGstClaimsPath = process.env.WFM_OUTGOING_NON_GST_CLAIMS_PATH || 'WFM-QRE\\OUTGOING\\WFM_SAP_MAIN\\DLR_INC_CLAIMS_NON_GST';
} }
/** /**
@ -32,13 +36,14 @@ export class WFMFileService {
* @param data The data to be written to the CSV * @param data The data to be written to the CSV
* @param fileName The name of the file (e.g., CLAIM_12345.csv) * @param fileName The name of the file (e.g., CLAIM_12345.csv)
*/ */
async generateIncomingClaimCSV(data: any[], fileName: string): Promise<string> { async generateIncomingClaimCSV(data: any[], fileName: string, isNonGst: boolean = false): Promise<string> {
const maxRetries = 3; const maxRetries = 3;
let retryCount = 0; let retryCount = 0;
while (retryCount <= maxRetries) { while (retryCount <= maxRetries) {
try { try {
const targetDir = path.join(this.basePath, this.incomingClaimsPath); const targetPath = isNonGst ? this.incomingNonGstClaimsPath : this.incomingGstClaimsPath;
const targetDir = path.join(this.basePath, targetPath);
this.ensureDirectoryExists(targetDir); this.ensureDirectoryExists(targetDir);
const filePath = path.join(targetDir, fileName.endsWith('.csv') ? fileName : `${fileName}.csv`); const filePath = path.join(targetDir, fileName.endsWith('.csv') ? fileName : `${fileName}.csv`);
@ -75,8 +80,42 @@ export class WFMFileService {
/** /**
* Get the absolute path for an outgoing claim file * Get the absolute path for an outgoing claim file
*/ */
getOutgoingPath(fileName: string): string { getOutgoingPath(fileName: string, isNonGst: boolean = false): string {
return path.join(this.basePath, this.outgoingClaimsPath, fileName); const targetPath = isNonGst ? this.outgoingNonGstClaimsPath : this.outgoingGstClaimsPath;
return path.join(this.basePath, targetPath, fileName);
}
/**
* Get credit note details from outgoing CSV
*/
async getCreditNoteDetails(dealerCode: string, requestNumber: string, isNonGst: boolean = false): Promise<any[]> {
const fileName = `CN_${dealerCode}_${requestNumber}.csv`;
const filePath = this.getOutgoingPath(fileName, isNonGst);
try {
if (!fs.existsSync(filePath)) {
return [];
}
const fileContent = fs.readFileSync(filePath, 'utf-8');
const lines = fileContent.split('\n').filter(line => line.trim() !== '');
if (lines.length <= 1) return []; // Only headers or empty
const headers = lines[0].split('|');
const data = lines.slice(1).map(line => {
const values = line.split('|');
const row: any = {};
headers.forEach((header, index) => {
row[header.trim()] = values[index]?.trim() || '';
});
return row;
});
return data;
} catch (error) {
logger.error(`[WFMFileService] Error reading credit note CSV: ${fileName}`, error);
return [];
}
} }
} }