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 { 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 { 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();