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 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<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/radix-vendor-CYvDqP9X.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/redux-vendor-tbZCm13o.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>
<body>

View File

@ -73,6 +73,13 @@ RATE_LIMIT_MAX_REQUESTS=100
MAX_FILE_SIZE_MB=10
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_CHECK_INTERVAL_MINUTES=30
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');
}
const isNonGst = taxationType === 'Non GST' || taxationType === 'Non-GST';
// Construct CSV with pipe separator
const headers = [
'TRNS_UNIQ_NO',
@ -1034,15 +1036,15 @@ export class DealerClaimController {
'CLAIM_DOC_TYP',
'CLAIM_TYPE',
'CLAIM_DATE',
'CLAIM_AMT',
'GST_AMT',
'GST_PERCENTAGE'
'CLAIM_AMT'
];
const rows = items.map(item => {
const isNonGst = taxationType === 'Non GST' || taxationType === 'Non-GST';
if (!isNonGst) {
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 claimNumber = requestNumber;
const invNumber = invoice?.invoiceNumber || '';
@ -1053,11 +1055,7 @@ export class DealerClaimController {
const claimDate = invoice?.createdAt ? new Date(invoice.createdAt).toISOString().split('T')[0] : '';
const claimAmt = item.assAmt;
// Zero out tax for Non-GST
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 [
const rowItems = [
trnsUniqNo,
claimNumber,
invNumber,
@ -1066,10 +1064,15 @@ export class DealerClaimController {
claimDocTyp,
claimType,
claimDate,
claimAmt,
totalTax.toFixed(2),
gstPercentage
].join('|');
claimAmt
];
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');
@ -1112,4 +1115,43 @@ export class DealerClaimController {
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.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

View File

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

View File

@ -8,13 +8,17 @@ import logger from '../utils/logger';
*/
export class WFMFileService {
private basePath: string;
private incomingClaimsPath: string;
private outgoingClaimsPath: string;
private incomingGstClaimsPath: string;
private incomingNonGstClaimsPath: string;
private outgoingGstClaimsPath: string;
private outgoingNonGstClaimsPath: string;
constructor() {
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.outgoingClaimsPath = process.env.WFM_OUTGOING_CLAIMS_PATH || 'WFM-QRE\\OUTGOING\\WFM_SAP_MAIN\\DLR_INC_CLAIMS';
this.incomingGstClaimsPath = process.env.WFM_INCOMING_GST_CLAIMS_PATH || 'WFM-QRE\\INCOMING\\WFM_MAIN\\DLR_INC_CLAIMS_GST';
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 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;
let retryCount = 0;
while (retryCount <= maxRetries) {
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);
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
*/
getOutgoingPath(fileName: string): string {
return path.join(this.basePath, this.outgoingClaimsPath, fileName);
getOutgoingPath(fileName: string, isNonGst: boolean = false): string {
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 [];
}
}
}