diff --git a/package.json b/package.json index 6a77614..51db05a 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "seed:demo-requests": "ts-node -r tsconfig-paths/register src/scripts/seed-demo-requests.ts", "seed:demo-dealers": "ts-node -r tsconfig-paths/register src/scripts/seed-demo-dealers.ts", "cleanup:dealer-claims": "ts-node -r tsconfig-paths/register src/scripts/cleanup-dealer-claims.ts", - "clear:form16-and-demo": "ts-node -r tsconfig-paths/register src/scripts/clear-form16-and-demo-data.ts", - "clear:26as": "ts-node -r tsconfig-paths/register src/scripts/clear-26as-data.ts", + // "clear:form16-and-demo": "ts-node -r tsconfig-paths/register src/scripts/clear-form16-and-demo-data.ts", + // "clear:26as": "ts-node -r tsconfig-paths/register src/scripts/clear-26as-data.ts", "redis:start": "docker run -d --name redis-workflow -p 6379:6379 redis:7-alpine", "redis:stop": "docker rm -f redis-workflow", "test": "jest --passWithNoTests --forceExit", diff --git a/src/services/wfmFile.service.ts b/src/services/wfmFile.service.ts index 8d9fd37..03f45fb 100644 --- a/src/services/wfmFile.service.ts +++ b/src/services/wfmFile.service.ts @@ -7,12 +7,15 @@ const DEFAULT_CLAIMS_INCOMING = path.join('WFM-QRE', 'INCOMING', 'WFM_MAIN', 'DL const DEFAULT_CLAIMS_OUTGOING = path.join('WFM-QRE', 'OUTGOING', 'WFM_SAP_MAIN', 'DLR_INC_CLAIMS'); const DEFAULT_FORM16_CREDIT_INCOMING = path.join('WFM-QRE', 'INCOMING', 'WFM_MAIN', 'FORM16_CRDT'); const DEFAULT_FORM16_DEBIT_INCOMING = path.join('WFM-QRE', 'INCOMING', 'WFM_MAIN', 'FORM16_DEBT'); -const DEFAULT_FORM16_OUTGOING = path.join('WFM-QRE', 'OUTGOING', 'WFM_SAP_MAIN', 'FORM16_CRDT'); +const DEFAULT_FORM16_CREDIT_OUTGOING = path.join('WFM-QRE', 'OUTGOING', 'WFM_SAP_MAIN', 'FORM16_CRDT'); +const DEFAULT_FORM16_DEBIT_OUTGOING = path.join('WFM-QRE', 'OUTGOING', 'WFM_SAP_MAIN', 'FORM16_DBT'); /** * WFM File Service * Handles generation and storage of CSV files in the WFM folder structure. - * Dealer claims use DLR_INC_CLAIMS; Form 16 uses FORM16_CRDT (credit) and FORM16_DEBT (debit) under INCOMING/WFM_MAIN. + * Dealer claims use DLR_INC_CLAIMS; Form 16 uses: + * - FORM16_CRDT (credit) and FORM16_DEBT (debit) under INCOMING/WFM_MAIN + * - FORM16_CRDT (credit) and FORM16_DBT (debit) under OUTGOING/WFM_SAP_MAIN * Paths are cross-platform; set WFM_BASE_PATH (and optional path overrides) in .env for production. */ export class WFMFileService { @@ -25,8 +28,10 @@ export class WFMFileService { private form16IncomingCreditPath: string; /** Form 16 debit notes: INCOMING/WFM_MAIN/FORM16_DEBT */ private form16IncomingDebitPath: string; - /** Form 16: OUTGOING/WFM_SAP_MAIN/FORM16_CRDT (SAP responses) */ - private form16OutgoingPath: string; + /** Form 16 credit responses: OUTGOING/WFM_SAP_MAIN/FORM16_CRDT */ + private form16OutgoingCreditPath: string; + /** Form 16 debit responses: OUTGOING/WFM_SAP_MAIN/FORM16_DBT */ + private form16OutgoingDebitPath: string; constructor() { this.basePath = process.env.WFM_BASE_PATH || 'C:\\WFM'; @@ -42,7 +47,12 @@ export class WFMFileService { this.form16IncomingDebitPath = process.env.WFM_FORM16_DEBIT_INCOMING_PATH || legacyForm16Incoming || DEFAULT_FORM16_DEBIT_INCOMING; - this.form16OutgoingPath = process.env.WFM_FORM16_OUTGOING_PATH || DEFAULT_FORM16_OUTGOING; + // Outgoing: allow specific credit/debit overrides; fall back to legacy single path for credit + const legacyForm16Outgoing = process.env.WFM_FORM16_OUTGOING_PATH; + this.form16OutgoingCreditPath = + process.env.WFM_FORM16_CREDIT_OUTGOING_PATH || legacyForm16Outgoing || DEFAULT_FORM16_CREDIT_OUTGOING; + this.form16OutgoingDebitPath = + process.env.WFM_FORM16_DEBIT_OUTGOING_PATH || DEFAULT_FORM16_DEBIT_OUTGOING; } /** @@ -197,10 +207,51 @@ export class WFMFileService { } /** - * Get the absolute path for a Form 16 outgoing (response) file + * Get the absolute path for a Form 16 outgoing (response) file. + * - Credit: WFM/WFM-QRE/OUTGOING/WFM_SAP_MAIN/FORM16_CRDT + * - Debit: WFM/WFM-QRE/OUTGOING/WFM_SAP_MAIN/FORM16_DBT */ - getForm16OutgoingPath(fileName: string): string { - return path.join(this.basePath, this.form16OutgoingPath, fileName); + getForm16OutgoingPath(fileName: string, type: 'credit' | 'debit' = 'credit'): string { + const targetPath = type === 'debit' ? this.form16OutgoingDebitPath : this.form16OutgoingCreditPath; + return path.join(this.basePath, targetPath, fileName); + } + + /** + * Read a Form 16 outgoing (SAP) response CSV and return rows as objects keyed by header: + * Expected columns (both credit and debit): + * - DMS_UNIQ_NO + * - CLAIM_NUMBER + * - DOC_NO + * - MSG_TYP + * - MESSAGE + */ + async readForm16OutgoingResponse(fileName: string, type: 'credit' | 'debit' = 'credit'): Promise { + const filePath = this.getForm16OutgoingPath(fileName, type); + + 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 Form 16 response CSV (${type}): ${fileName}`, error); + return []; + } } }