feat(claimStatus) - Feature done
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
"node-cron": "^4.2.1",
|
"node-cron": "^4.2.1",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
|
"pdfkit": "^0.17.2",
|
||||||
"ws": "^8.18.0",
|
"ws": "^8.18.0",
|
||||||
"zod": "^3.24.2",
|
"zod": "^3.24.2",
|
||||||
"zod-validation-error": "^3.4.0"
|
"zod-validation-error": "^3.4.0"
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
"@types/node": "20.16.11",
|
"@types/node": "20.16.11",
|
||||||
"@types/passport": "^1.0.16",
|
"@types/passport": "^1.0.16",
|
||||||
"@types/passport-local": "^1.0.38",
|
"@types/passport-local": "^1.0.38",
|
||||||
|
"@types/pdfkit": "^0.17.3",
|
||||||
"@types/ws": "^8.5.13",
|
"@types/ws": "^8.5.13",
|
||||||
"ts-node-dev": "^2.0.0"
|
"ts-node-dev": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,209 +4,284 @@ import { storage } from "../storage";
|
|||||||
import { forwardToSeleniumInsuranceEligibilityAgent } from "../services/seleniumInsuranceEligibilityClient";
|
import { forwardToSeleniumInsuranceEligibilityAgent } from "../services/seleniumInsuranceEligibilityClient";
|
||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import PDFDocument from "pdfkit";
|
||||||
import { forwardToSeleniumInsuranceClaimStatusAgent } from "../services/seleniumInsuranceClaimStatusClient";
|
import { forwardToSeleniumInsuranceClaimStatusAgent } from "../services/seleniumInsuranceClaimStatusClient";
|
||||||
|
import fsSync from "fs";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.post("/eligibility-check", async (req: Request, res: Response): Promise<any> => {
|
router.post(
|
||||||
if (!req.body.data) {
|
"/eligibility-check",
|
||||||
return res
|
async (req: Request, res: Response): Promise<any> => {
|
||||||
.status(400)
|
if (!req.body.data) {
|
||||||
.json({ error: "Missing Insurance Eligibility data for selenium" });
|
return res
|
||||||
}
|
.status(400)
|
||||||
|
.json({ error: "Missing Insurance Eligibility data for selenium" });
|
||||||
if (!req.user || !req.user.id) {
|
|
||||||
return res.status(401).json({ error: "Unauthorized: user info missing" });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const insuranceEligibilityData = JSON.parse(req.body.data);
|
|
||||||
|
|
||||||
const credentials = await storage.getInsuranceCredentialByUserAndSiteKey(
|
|
||||||
req.user.id,
|
|
||||||
insuranceEligibilityData.insuranceSiteKey
|
|
||||||
);
|
|
||||||
if (!credentials) {
|
|
||||||
return res.status(404).json({
|
|
||||||
error:
|
|
||||||
"No insurance credentials found for this provider, Kindly Update this at Settings Page.",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const enrichedData = {
|
if (!req.user || !req.user.id) {
|
||||||
...insuranceEligibilityData,
|
return res.status(401).json({ error: "Unauthorized: user info missing" });
|
||||||
massdhpUsername: credentials.username,
|
}
|
||||||
massdhpPassword: credentials.password,
|
|
||||||
};
|
|
||||||
|
|
||||||
const result =
|
try {
|
||||||
await forwardToSeleniumInsuranceEligibilityAgent(enrichedData);
|
const insuranceEligibilityData = JSON.parse(req.body.data);
|
||||||
|
|
||||||
// ✅ Step 1: Check result and update patient status
|
const credentials = await storage.getInsuranceCredentialByUserAndSiteKey(
|
||||||
const patient = await storage.getPatientByInsuranceId(
|
req.user.id,
|
||||||
insuranceEligibilityData.memberId
|
insuranceEligibilityData.insuranceSiteKey
|
||||||
);
|
);
|
||||||
|
if (!credentials) {
|
||||||
|
return res.status(404).json({
|
||||||
|
error:
|
||||||
|
"No insurance credentials found for this provider, Kindly Update this at Settings Page.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (patient && patient.id !== undefined) {
|
const enrichedData = {
|
||||||
const newStatus = result.eligibility === "Y" ? "active" : "inactive";
|
...insuranceEligibilityData,
|
||||||
await storage.updatePatient(patient.id, { status: newStatus });
|
massdhpUsername: credentials.username,
|
||||||
result.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
massdhpPassword: credentials.password,
|
||||||
|
};
|
||||||
|
|
||||||
// ✅ Step 2: Handle PDF Upload
|
const result =
|
||||||
if (result.pdf_path && result.pdf_path.endsWith(".pdf")) {
|
await forwardToSeleniumInsuranceEligibilityAgent(enrichedData);
|
||||||
const pdfBuffer = await fs.readFile(result.pdf_path);
|
|
||||||
|
|
||||||
const groupTitle = "Insurance Status PDFs";
|
// ✅ Step 1: Check result and update patient status
|
||||||
const groupTitleKey = "INSURANCE_STATUS_PDFs"
|
const patient = await storage.getPatientByInsuranceId(
|
||||||
const groupCategory = "ELIGIBILITY_STATUS";
|
insuranceEligibilityData.memberId
|
||||||
|
);
|
||||||
|
|
||||||
let group = await storage.findPdfGroupByPatientTitleKeyAndCategory(
|
if (patient && patient.id !== undefined) {
|
||||||
patient.id,
|
const newStatus = result.eligibility === "Y" ? "active" : "inactive";
|
||||||
groupTitleKey,
|
await storage.updatePatient(patient.id, { status: newStatus });
|
||||||
groupCategory
|
result.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
||||||
);
|
|
||||||
|
|
||||||
// Step 2b: Create group if it doesn’t exist
|
// ✅ Step 2: Handle PDF Upload
|
||||||
if (!group) {
|
if (result.pdf_path && result.pdf_path.endsWith(".pdf")) {
|
||||||
group = await storage.createPdfGroup(
|
const pdfBuffer = await fs.readFile(result.pdf_path);
|
||||||
|
|
||||||
|
const groupTitle = "Insurance Status PDFs";
|
||||||
|
const groupTitleKey = "INSURANCE_STATUS_PDFs";
|
||||||
|
const groupCategory = "ELIGIBILITY_STATUS";
|
||||||
|
|
||||||
|
let group = await storage.findPdfGroupByPatientTitleKeyAndCategory(
|
||||||
patient.id,
|
patient.id,
|
||||||
groupTitle,
|
|
||||||
groupTitleKey,
|
groupTitleKey,
|
||||||
groupCategory
|
groupCategory
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Step 2b: Create group if it doesn’t exist
|
||||||
|
if (!group) {
|
||||||
|
group = await storage.createPdfGroup(
|
||||||
|
patient.id,
|
||||||
|
groupTitle,
|
||||||
|
groupTitleKey,
|
||||||
|
groupCategory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!group?.id) {
|
||||||
|
throw new Error("PDF group creation failed: missing group ID");
|
||||||
|
}
|
||||||
|
await storage.createPdfFile(
|
||||||
|
group.id,
|
||||||
|
path.basename(result.pdf_path),
|
||||||
|
pdfBuffer
|
||||||
|
);
|
||||||
|
|
||||||
|
await fs.unlink(result.pdf_path);
|
||||||
|
|
||||||
|
result.pdfUploadStatus = `PDF saved to group: ${group.title}`;
|
||||||
|
} else {
|
||||||
|
result.pdfUploadStatus =
|
||||||
|
"No valid PDF path provided by Selenium, Couldn't upload pdf to server.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!group?.id) {
|
|
||||||
throw new Error("PDF group creation failed: missing group ID");
|
|
||||||
}
|
|
||||||
await storage.createPdfFile(
|
|
||||||
group.id,
|
|
||||||
path.basename(result.pdf_path),
|
|
||||||
pdfBuffer
|
|
||||||
);
|
|
||||||
|
|
||||||
await fs.unlink(result.pdf_path);
|
|
||||||
|
|
||||||
result.pdfUploadStatus = `PDF saved to group: ${group.title}`;
|
|
||||||
} else {
|
} else {
|
||||||
result.pdfUploadStatus =
|
result.patientUpdateStatus =
|
||||||
"No valid PDF path provided by Selenium, Couldn't upload pdf to server.";
|
"Patient not found or missing ID; no update performed";
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
result.patientUpdateStatus =
|
|
||||||
"Patient not found or missing ID; no update performed";
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
patientUpdateStatus: result.patientUpdateStatus,
|
patientUpdateStatus: result.patientUpdateStatus,
|
||||||
pdfUploadStatus: result.pdfUploadStatus,
|
pdfUploadStatus: result.pdfUploadStatus,
|
||||||
});
|
});
|
||||||
|
} catch (err: any) {
|
||||||
} catch (err: any) {
|
console.error(err);
|
||||||
console.error(err);
|
return res.status(500).json({
|
||||||
return res.status(500).json({
|
error: err.message || "Failed to forward to selenium agent",
|
||||||
error: err.message || "Failed to forward to selenium agent",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/claim-status-check", async (req: Request, res: Response): Promise<any> => {
|
|
||||||
if (!req.body.data) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.json({ error: "Missing Insurance Status data for selenium" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req.user || !req.user.id) {
|
|
||||||
return res.status(401).json({ error: "Unauthorized: user info missing" });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const insuranceClaimStatusData = JSON.parse(req.body.data);
|
|
||||||
|
|
||||||
const credentials = await storage.getInsuranceCredentialByUserAndSiteKey(
|
|
||||||
req.user.id,
|
|
||||||
insuranceClaimStatusData.insuranceSiteKey
|
|
||||||
);
|
|
||||||
if (!credentials) {
|
|
||||||
return res.status(404).json({
|
|
||||||
error:
|
|
||||||
"No insurance credentials found for this provider, Kindly Update this at Settings Page.",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const enrichedData = {
|
router.post(
|
||||||
...insuranceClaimStatusData,
|
"/claim-status-check",
|
||||||
massdhpUsername: credentials.username,
|
async (req: Request, res: Response): Promise<any> => {
|
||||||
massdhpPassword: credentials.password,
|
if (!req.body.data) {
|
||||||
};
|
return res
|
||||||
|
.status(400)
|
||||||
|
.json({ error: "Missing Insurance Status data for selenium" });
|
||||||
|
}
|
||||||
|
|
||||||
const result =
|
if (!req.user || !req.user.id) {
|
||||||
await forwardToSeleniumInsuranceClaimStatusAgent(enrichedData);
|
return res.status(401).json({ error: "Unauthorized: user info missing" });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function imageToPdfBuffer(imagePath: string): Promise<Buffer> {
|
||||||
|
return new Promise<Buffer>((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const doc = new PDFDocument({ autoFirstPage: false });
|
||||||
|
const chunks: Uint8Array[] = [];
|
||||||
|
|
||||||
// ✅ Step 1: Check result
|
// collect data chunks
|
||||||
const patient = await storage.getPatientByInsuranceId(
|
doc.on("data", (chunk: any) => chunks.push(chunk));
|
||||||
insuranceClaimStatusData.memberId
|
doc.on("end", () => resolve(Buffer.concat(chunks)));
|
||||||
);
|
doc.on("error", (err: any) => reject(err));
|
||||||
|
|
||||||
if (patient && patient.id !== undefined) {
|
const A4_WIDTH = 595.28; // points
|
||||||
// ✅ Step 2: Handle PDF Upload
|
const A4_HEIGHT = 841.89; // points
|
||||||
if (result.pdf_path && result.pdf_path.endsWith(".pdf")) {
|
|
||||||
const pdfBuffer = await fs.readFile(result.pdf_path);
|
|
||||||
|
|
||||||
const groupTitle = "Insurance Status PDFs";
|
doc.addPage({ size: [A4_WIDTH, A4_HEIGHT] });
|
||||||
const groupTitleKey = "INSURANCE_STATUS_PDFs"
|
|
||||||
const groupCategory = "CLAIM_STATUS";
|
|
||||||
|
|
||||||
let group = await storage.findPdfGroupByPatientTitleKeyAndCategory(
|
doc.image(imagePath, 0, 0, {
|
||||||
patient.id,
|
fit: [A4_WIDTH, A4_HEIGHT],
|
||||||
groupTitleKey,
|
align: "center",
|
||||||
groupCategory
|
valign: "center",
|
||||||
);
|
});
|
||||||
|
|
||||||
// Step 2b: Create group if it doesn’t exist
|
doc.end();
|
||||||
if (!group) {
|
} catch (err) {
|
||||||
group = await storage.createPdfGroup(
|
reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const insuranceClaimStatusData = JSON.parse(req.body.data);
|
||||||
|
|
||||||
|
const credentials = await storage.getInsuranceCredentialByUserAndSiteKey(
|
||||||
|
req.user.id,
|
||||||
|
insuranceClaimStatusData.insuranceSiteKey
|
||||||
|
);
|
||||||
|
if (!credentials) {
|
||||||
|
return res.status(404).json({
|
||||||
|
error:
|
||||||
|
"No insurance credentials found for this provider, Kindly Update this at Settings Page.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const enrichedData = {
|
||||||
|
...insuranceClaimStatusData,
|
||||||
|
massdhpUsername: credentials.username,
|
||||||
|
massdhpPassword: credentials.password,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result =
|
||||||
|
await forwardToSeleniumInsuranceClaimStatusAgent(enrichedData);
|
||||||
|
|
||||||
|
// ✅ Step 1: Check result
|
||||||
|
const patient = await storage.getPatientByInsuranceId(
|
||||||
|
insuranceClaimStatusData.memberId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (patient && patient.id !== undefined) {
|
||||||
|
let pdfBuffer: Buffer | null = null;
|
||||||
|
let generatedPdfPath: string | null = null;
|
||||||
|
|
||||||
|
if (
|
||||||
|
result.ss_path &&
|
||||||
|
(result.ss_path.endsWith(".png") ||
|
||||||
|
result.ss_path.endsWith(".jpg") ||
|
||||||
|
result.ss_path.endsWith(".jpeg"))
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Ensure file exists
|
||||||
|
if (!fsSync.existsSync(result.ss_path)) {
|
||||||
|
throw new Error(`Screenshot file not found: ${result.ss_path}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert image to PDF buffer
|
||||||
|
pdfBuffer = await imageToPdfBuffer(result.ss_path);
|
||||||
|
|
||||||
|
// Optionally write generated PDF to temp path (so name is available for createPdfFile)
|
||||||
|
const pdfFileName = `claimStatus_${insuranceClaimStatusData.memberId}_${Date.now()}.pdf`;
|
||||||
|
generatedPdfPath = path.join(
|
||||||
|
path.dirname(result.ss_path),
|
||||||
|
pdfFileName
|
||||||
|
);
|
||||||
|
await fs.writeFile(generatedPdfPath, pdfBuffer);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to convert screenshot to PDF:", err);
|
||||||
|
result.pdfUploadStatus = `Failed to convert screenshot to PDF: ${String(err)}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.pdfUploadStatus =
|
||||||
|
"No valid PDF or screenshot path provided by Selenium; nothing to upload.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdfBuffer && generatedPdfPath) {
|
||||||
|
const groupTitle = "Insurance Status PDFs";
|
||||||
|
const groupTitleKey = "INSURANCE_STATUS_PDFs";
|
||||||
|
const groupCategory = "CLAIM_STATUS";
|
||||||
|
|
||||||
|
let group = await storage.findPdfGroupByPatientTitleKeyAndCategory(
|
||||||
patient.id,
|
patient.id,
|
||||||
groupTitle,
|
|
||||||
groupTitleKey,
|
groupTitleKey,
|
||||||
groupCategory
|
groupCategory
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create group if missing
|
||||||
|
if (!group) {
|
||||||
|
group = await storage.createPdfGroup(
|
||||||
|
patient.id,
|
||||||
|
groupTitle,
|
||||||
|
groupTitleKey,
|
||||||
|
groupCategory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!group?.id) {
|
||||||
|
throw new Error("PDF group creation failed: missing group ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the basename for storage
|
||||||
|
const basename = path.basename(generatedPdfPath);
|
||||||
|
await storage.createPdfFile(group.id, basename, pdfBuffer);
|
||||||
|
|
||||||
|
// Clean up temp files:
|
||||||
|
try {
|
||||||
|
// remove generated PDF file (if it was created during conversion)
|
||||||
|
if (
|
||||||
|
generatedPdfPath &&
|
||||||
|
fsSync.existsSync(generatedPdfPath) &&
|
||||||
|
generatedPdfPath !== result.pdf_path
|
||||||
|
) {
|
||||||
|
await fs.unlink(generatedPdfPath);
|
||||||
|
}
|
||||||
|
// remove screenshot (if provided by Selenium) to avoid lingering temp files
|
||||||
|
if (result.ss_path && fsSync.existsSync(result.ss_path)) {
|
||||||
|
await fs.unlink(result.ss_path);
|
||||||
|
}
|
||||||
|
} catch (cleanupErr) {
|
||||||
|
console.warn("Cleanup error (non-fatal):", cleanupErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.pdfUploadStatus = `PDF saved to group: ${group.title}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!group?.id) {
|
|
||||||
throw new Error("PDF group creation failed: missing group ID");
|
|
||||||
}
|
|
||||||
await storage.createPdfFile(
|
|
||||||
group.id,
|
|
||||||
path.basename(result.pdf_path),
|
|
||||||
pdfBuffer
|
|
||||||
);
|
|
||||||
|
|
||||||
await fs.unlink(result.pdf_path);
|
|
||||||
|
|
||||||
result.pdfUploadStatus = `PDF saved to group: ${group.title}`;
|
|
||||||
} else {
|
} else {
|
||||||
result.pdfUploadStatus =
|
result.patientUpdateStatus =
|
||||||
"No valid PDF path provided by Selenium, Couldn't upload pdf to server.";
|
"Patient not found or missing ID; no update performed";
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
result.patientUpdateStatus =
|
res.json({
|
||||||
"Patient not found or missing ID; no update performed";
|
pdfUploadStatus: result.pdfUploadStatus,
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error(err);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: err.message || "Failed to forward to selenium agent",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({
|
|
||||||
patientUpdateStatus: result.patientUpdateStatus,
|
|
||||||
pdfUploadStatus: result.pdfUploadStatus,
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (err: any) {
|
|
||||||
console.error(err);
|
|
||||||
return res.status(500).json({
|
|
||||||
error: err.message || "Failed to forward to selenium agent",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
Reference in New Issue
Block a user