Re_Backend/src/services/wfmFile.service.ts

123 lines
5.2 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import logger from '../utils/logger';
/**
* WFM File Service
* Handles generation and storage of CSV files in the WFM folder structure
*/
export class WFMFileService {
private basePath: string;
private incomingGstClaimsPath: string;
private incomingNonGstClaimsPath: string;
private outgoingGstClaimsPath: string;
private outgoingNonGstClaimsPath: string;
constructor() {
this.basePath = process.env.WFM_BASE_PATH || 'C:\\WFM';
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';
}
/**
* Ensure the target directory exists
*/
private ensureDirectoryExists(dirPath: string): void {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
logger.info(`[WFMFileService] Created directory: ${dirPath}`);
}
}
/**
* Generate a CSV file for a credit note/claim and store it in the INCOMING folder
* @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, isNonGst: boolean = false): Promise<string> {
const maxRetries = 3;
let retryCount = 0;
while (retryCount <= maxRetries) {
try {
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`);
// Simple CSV generation logic with pipe separator and no quotes
const headers = Object.keys(data[0] || {}).join('|');
const rows = data.map(item => Object.values(item).map(val => val === null || val === undefined ? '' : String(val)).join('|')).join('\n');
const csvContent = `${headers}\n${rows}`;
fs.writeFileSync(filePath, csvContent);
logger.info(`[WFMFileService] Generated CSV at: ${filePath}`);
return filePath;
} catch (error: any) {
if (error.code === 'EBUSY' && retryCount < maxRetries) {
retryCount++;
const delay = retryCount * 1000;
logger.warn(`[WFMFileService] File busy/locked, retrying in ${delay}ms (Attempt ${retryCount}/${maxRetries}): ${fileName}`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
if (error.code === 'EBUSY') {
throw new Error(`File is locked or open in another program (e.g., Excel). Please close '${fileName}' and try again.`);
}
logger.error('[WFMFileService] Error generating incoming claim CSV:', error);
throw error;
}
}
throw new Error(`Failed to generate CSV after ${maxRetries} retries. Please ensure the file '${fileName}' is not open in any other application.`);
}
/**
* Get the absolute path for an outgoing claim file
*/
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 [];
}
}
}
export const wfmFileService = new WFMFileService();