/** * Processor for "cmsp-eligibility-history-remaining-check" jobs. * Saves eligibility PDF, service history PDF, and accumulator PDF * to the patient's ELIGIBILITY_STATUS document group. */ import fs from "fs/promises"; import path from "path"; import { storage } from "../../storage"; import { emptyFolderContainingFile } from "../../utils/emptyTempFolder"; import forwardToPatientDataExtractorService from "../../services/patientDataExtractorService"; import { callPythonSync, splitName, createOrUpdatePatientByInsuranceId, } from "./_shared"; export interface CmspEligibilityHistoryRemainingProcessorInput { enrichedPayload: any; userId: number; insuranceId: string; formFirstName?: string; formLastName?: string; formDob?: string; } export interface CmspEligibilityHistoryRemainingProcessorResult { patientUpdateStatus?: string; pdfUploadStatus?: string; pdfFileId?: number | string | null; pdfFilename?: string | null; memberDetailsPdfFileId?: number | string | null; memberDetailsPdfFilename?: string | null; historyPdfFileId?: number | string | null; historyPdfFilename?: string | null; accumulatorPdfFileId?: number | string | null; accumulatorPdfFilename?: string | null; remainingBenefit?: string | null; thirdPartyInsurance?: string | null; } export async function runCmspEligibilityHistoryRemainingProcessor( input: CmspEligibilityHistoryRemainingProcessorInput ): Promise { const { enrichedPayload, userId, insuranceId, formFirstName, formLastName, formDob } = input; const seleniumResult = await callPythonSync("/cmsp-eligibility-history-remaining-check", { data: enrichedPayload, }); const outputResult: CmspEligibilityHistoryRemainingProcessorResult = {}; // Extract patient name const seleniumFirst = seleniumResult.firstName?.trim() || null; const seleniumLast = seleniumResult.lastName?.trim() || null; const seleniumName = seleniumResult.name?.trim() || null; const seleniumInsurance = seleniumResult.insurance?.trim() || null; const extracted: { firstName?: string | null; lastName?: string | null } = {}; if (seleniumFirst || seleniumLast) { extracted.firstName = seleniumFirst; extracted.lastName = seleniumLast; } else if (seleniumName) { const parts = splitName(seleniumName); extracted.firstName = parts.firstName || null; extracted.lastName = parts.lastName || null; } if (!extracted.firstName && !extracted.lastName && seleniumResult?.pdf_path?.endsWith(".pdf")) { try { const pdfBuffer = await fs.readFile(seleniumResult.pdf_path); const extraction = await forwardToPatientDataExtractorService({ buffer: pdfBuffer, originalname: path.basename(seleniumResult.pdf_path), mimetype: "application/pdf", } as any); if (extraction.name) { const parts = splitName(extraction.name); extracted.firstName = parts.firstName || null; extracted.lastName = parts.lastName || null; } } catch (e) { console.error("[cmspProcessor] PDF name extraction failed:", e); } } const preferFirst = extracted.firstName || formFirstName || null; const preferLast = extracted.lastName || formLastName || null; let patient; try { patient = await createOrUpdatePatientByInsuranceId({ insuranceId, firstName: preferFirst, lastName: preferLast, dob: formDob, userId, }); } catch (e: any) { throw new Error(`Failed to create/update patient: ${e.message}`); } if (patient && patient.id !== undefined) { let newStatus = "UNKNOWN"; if (seleniumResult.eligibility === "Y") newStatus = "ACTIVE"; else if (seleniumResult.eligibility === "N") newStatus = "INACTIVE"; const updates: any = { status: newStatus }; if (seleniumInsurance) updates.insuranceProvider = seleniumInsurance; const remainingBenefit = seleniumResult.remaining_amount?.trim() || null; if (remainingBenefit) updates.remainingBenefit = remainingBenefit; // third_party_insurance is present (even as null) whenever the Third Party // Liability table was found — null means the member has no 2nd insurance, // so we still write it to clear any stale value from a prior check. if (Object.prototype.hasOwnProperty.call(seleniumResult, "third_party_insurance")) { updates.thirdPartyInsurance = seleniumResult.third_party_insurance?.trim() || null; } await storage.updatePatient(patient.id, updates); outputResult.patientUpdateStatus = `Patient status updated to ${newStatus}`; outputResult.remainingBenefit = remainingBenefit; outputResult.thirdPartyInsurance = updates.thirdPartyInsurance ?? null; // Helper: save a single PDF to the patient's Cloud Storage Eligibility folder const patientName = `${patient!.firstName ?? ""} ${patient!.lastName ?? ""}`.trim() || `Patient ${patient!.id}`; const saveToGroup = async (pdfPath: string): Promise => { try { const buffer = await fs.readFile(pdfPath); const cloudFile = await storage.savePdfToCloudStorage( userId, patient!.id, patientName, "Eligibility", path.basename(pdfPath), buffer ); return `cloud:${cloudFile.id}`; } catch (e: any) { console.error("[cmspProcessor] saveToGroup failed:", e.message); return null; } }; // Save eligibility PDF if (seleniumResult.pdf_path?.endsWith(".pdf")) { outputResult.pdfFileId = await saveToGroup(seleniumResult.pdf_path); outputResult.pdfFilename = path.basename(seleniumResult.pdf_path); outputResult.pdfUploadStatus = outputResult.pdfFileId ? "Eligibility PDF saved" : "Eligibility PDF upload failed"; } else { outputResult.pdfUploadStatus = "No eligibility PDF returned by Selenium"; } // Save member details PDF if (seleniumResult.member_details_pdf_path?.endsWith(".pdf")) { outputResult.memberDetailsPdfFileId = await saveToGroup(seleniumResult.member_details_pdf_path); outputResult.memberDetailsPdfFilename = path.basename(seleniumResult.member_details_pdf_path); } // Save history PDF if (seleniumResult.history_pdf_path?.endsWith(".pdf")) { outputResult.historyPdfFileId = await saveToGroup(seleniumResult.history_pdf_path); outputResult.historyPdfFilename = path.basename(seleniumResult.history_pdf_path); } // Save accumulator PDF if (seleniumResult.accumulator_pdf_path?.endsWith(".pdf")) { outputResult.accumulatorPdfFileId = await saveToGroup(seleniumResult.accumulator_pdf_path); outputResult.accumulatorPdfFilename = path.basename(seleniumResult.accumulator_pdf_path); } } else { outputResult.patientUpdateStatus = "Patient not found or missing ID; no update performed"; } // Cleanup temp files try { if (seleniumResult.pdf_path) await emptyFolderContainingFile(seleniumResult.pdf_path); } catch (e) { console.error("[cmspProcessor] cleanup failed:", e); } return outputResult; }