pdf files db, backend route done
This commit is contained in:
@@ -7,107 +7,217 @@ const upload = multer({ storage: multer.memoryStorage() });
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post("/claim-pdf/upload", upload.single("file"), async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const { patientId, claimId } = req.body;
|
||||
const file = req.file;
|
||||
// ----------- PDF GROUPS ------------------
|
||||
router.post(
|
||||
"/pdf-groups",
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const { title, category, patientId } = req.body;
|
||||
if (!title || !category || !patientId) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "Missing title, category, or patientId" });
|
||||
}
|
||||
|
||||
if (!patientId || !claimId) {
|
||||
return res.status(400).json({ error: "Missing patientId, or claimId" });
|
||||
const group = await storage.createPdfGroup(
|
||||
parseInt(patientId),
|
||||
title,
|
||||
category
|
||||
);
|
||||
|
||||
res.json(group);
|
||||
} catch (err) {
|
||||
console.error("Error creating PDF group:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
|
||||
if (!file){
|
||||
return res.status(400).json({ error: "Missing file" });
|
||||
}
|
||||
|
||||
const created = await storage.createClaimPdf(
|
||||
parseInt(patientId),
|
||||
parseInt(claimId),
|
||||
file.originalname,
|
||||
file.buffer
|
||||
);
|
||||
|
||||
res.json(created);
|
||||
} catch (err) {
|
||||
console.error("Error uploading claim PDF:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/claim-pdf/recent", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const limit = parseInt(req.query.limit as string) || 5;
|
||||
const offset = parseInt(req.query.offset as string) || 0;
|
||||
|
||||
const recent = await storage.getRecentClaimPdfs(limit, offset);
|
||||
res.json(recent);
|
||||
} catch (err) {
|
||||
console.error("Error fetching recent PDFs:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/claim-pdf/:id", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) return res.status(400).json({ error: "Missing ID" });
|
||||
|
||||
const id = parseInt(idParam);
|
||||
const pdf = await storage.getClaimPdfById(id);
|
||||
|
||||
if (!pdf || !pdf.pdfData) return res.status(404).json({ error: "PDF not found" });
|
||||
|
||||
// Fix bad objectified Buffer
|
||||
if (!Buffer.isBuffer(pdf.pdfData)) {
|
||||
pdf.pdfData = Buffer.from(Object.values(pdf.pdfData));
|
||||
}
|
||||
res.setHeader("Content-Type", "application/pdf");
|
||||
res.setHeader(
|
||||
"Content-Disposition",
|
||||
`attachment; filename="${pdf.filename}"; filename*=UTF-8''${encodeURIComponent(pdf.filename)}`
|
||||
);
|
||||
res.send(pdf.pdfData);
|
||||
} catch (err) {
|
||||
console.error("Error fetching PDF by ID:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.delete("/claim-pdf/:id", async (req: Request, res: Response): Promise<any> => {
|
||||
router.get(
|
||||
"/pdf-groups/:id",
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) {
|
||||
return res.status(400).json({ error: "Missing ID" });
|
||||
}
|
||||
const id = parseInt(idParam);
|
||||
const group = await storage.getPdfGroupById(id);
|
||||
if (!group) return res.status(404).json({ error: "Group not found" });
|
||||
res.json(group);
|
||||
} catch (err) {
|
||||
console.error("Error fetching PDF group:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.get("/pdf-groups", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) return res.status(400).json({ error: "Missing ID" });
|
||||
|
||||
const id = parseInt(idParam);
|
||||
const success = await storage.deleteClaimPdf(id);
|
||||
|
||||
res.json({ success });
|
||||
const groups = await storage.getAllPdfGroups();
|
||||
res.json(groups);
|
||||
} catch (err) {
|
||||
console.error("Error deleting PDF:", err);
|
||||
console.error("Error listing PDF groups:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.put("/claim-pdf/:id", upload.single("file"), async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) return res.status(400).json({ error: "Missing ID" });
|
||||
|
||||
const id = parseInt(idParam);
|
||||
const file = req.file;
|
||||
|
||||
const updated = await storage.updateClaimPdf(id, {
|
||||
filename: file?.originalname,
|
||||
pdfData: file?.buffer,
|
||||
});
|
||||
|
||||
if (!updated) return res.status(404).json({ error: "PDF not found or update failed" });
|
||||
|
||||
res.json(updated);
|
||||
} catch (err) {
|
||||
console.error("Error updating PDF:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
router.put(
|
||||
"/pdf-groups/:id",
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) {
|
||||
return res.status(400).json({ error: "Missing ID" });
|
||||
}
|
||||
const id = parseInt(idParam);
|
||||
const { title, category } = req.body;
|
||||
const updated = await storage.updatePdfGroup(id, { title, category });
|
||||
if (!updated) return res.status(404).json({ error: "Group not found" });
|
||||
res.json(updated);
|
||||
} catch (err) {
|
||||
console.error("Error updating PDF group:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/pdf-groups/:id",
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) {
|
||||
return res.status(400).json({ error: "Missing ID" });
|
||||
}
|
||||
const id = parseInt(idParam);
|
||||
const success = await storage.deletePdfGroup(id);
|
||||
res.json({ success });
|
||||
} catch (err) {
|
||||
console.error("Error deleting PDF group:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ----------- PDF FILES ------------------
|
||||
router.post(
|
||||
"/pdf-files",
|
||||
upload.single("file"),
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const { groupId } = req.body;
|
||||
const file = req.file;
|
||||
if (!groupId || !file) {
|
||||
return res.status(400).json({ error: "Missing groupId or file" });
|
||||
}
|
||||
|
||||
const pdf = await storage.createPdfFile(
|
||||
parseInt(groupId),
|
||||
file.originalname,
|
||||
file.buffer
|
||||
);
|
||||
|
||||
res.json(pdf);
|
||||
} catch (err) {
|
||||
console.error("Error uploading PDF file:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/pdf-files/:id",
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) {
|
||||
return res.status(400).json({ error: "Missing ID" });
|
||||
}
|
||||
const id = parseInt(idParam);
|
||||
const pdf = await storage.getPdfFileById(id);
|
||||
if (!pdf || !pdf.pdfData)
|
||||
return res.status(404).json({ error: "PDF not found" });
|
||||
|
||||
if (!Buffer.isBuffer(pdf.pdfData)) {
|
||||
pdf.pdfData = Buffer.from(Object.values(pdf.pdfData));
|
||||
}
|
||||
|
||||
res.setHeader("Content-Type", "application/pdf");
|
||||
res.setHeader(
|
||||
"Content-Disposition",
|
||||
`attachment; filename="${pdf.filename}"; filename*=UTF-8''${encodeURIComponent(pdf.filename)}`
|
||||
);
|
||||
res.send(pdf.pdfData);
|
||||
} catch (err) {
|
||||
console.error("Error downloading PDF file:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/pdf-files/recent",
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const limit = parseInt(req.query.limit as string) || 5;
|
||||
const offset = parseInt(req.query.offset as string) || 0;
|
||||
const files = await storage.getRecentPdfFiles(limit, offset);
|
||||
res.json(files);
|
||||
} catch (err) {
|
||||
console.error("Error getting recent PDF files:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.put(
|
||||
"/pdf-files/:id",
|
||||
upload.single("file"),
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) {
|
||||
return res.status(400).json({ error: "Missing ID" });
|
||||
}
|
||||
const id = parseInt(idParam);
|
||||
const file = req.file;
|
||||
|
||||
const updated = await storage.updatePdfFile(id, {
|
||||
filename: file?.originalname,
|
||||
pdfData: file?.buffer,
|
||||
});
|
||||
|
||||
if (!updated)
|
||||
return res
|
||||
.status(404)
|
||||
.json({ error: "PDF not found or update failed" });
|
||||
|
||||
res.json(updated);
|
||||
} catch (err) {
|
||||
console.error("Error updating PDF file:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/pdf-files/:id",
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) {
|
||||
return res.status(400).json({ error: "Missing ID" });
|
||||
}
|
||||
const id = parseInt(idParam);
|
||||
|
||||
const success = await storage.deletePdfFile(id);
|
||||
res.json({ success });
|
||||
} catch (err) {
|
||||
console.error("Error deleting PDF file:", err);
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -5,50 +5,64 @@ import { forwardToSeleniumInsuranceEligibilityAgent } from "../services/selenium
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
"/check",
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
if (!req.body.data) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "Missing Insurance Eligibility data for selenium" });
|
||||
}
|
||||
router.post("/check", async (req: Request, res: Response): Promise<any> => {
|
||||
if (!req.body.data) {
|
||||
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" });
|
||||
}
|
||||
if (!req.user || !req.user.id) {
|
||||
return res.status(401).json({ error: "Unauthorized: user info missing" });
|
||||
}
|
||||
|
||||
try {
|
||||
const insuranceEligibilityData = JSON.parse(req.body.data);
|
||||
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 = {
|
||||
...insuranceEligibilityData,
|
||||
massdhpUsername: credentials.username,
|
||||
massdhpPassword: credentials.password,
|
||||
};
|
||||
|
||||
const result =
|
||||
await forwardToSeleniumInsuranceEligibilityAgent(enrichedData);
|
||||
|
||||
res.json(result);
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
return res.status(500).json({
|
||||
error: err.message || "Failed to forward to selenium agent",
|
||||
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 = {
|
||||
...insuranceEligibilityData,
|
||||
massdhpUsername: credentials.username,
|
||||
massdhpPassword: credentials.password,
|
||||
};
|
||||
|
||||
const result =
|
||||
await forwardToSeleniumInsuranceEligibilityAgent(enrichedData);
|
||||
|
||||
// ✅ Step 1: Check result and update patient status
|
||||
const patient = await storage.getPatientByInsuranceId(
|
||||
insuranceEligibilityData.memberId
|
||||
);
|
||||
|
||||
if (patient && patient.id !== undefined) {
|
||||
const newStatus = result.eligibility === "Y" ? "active" : "inactive";
|
||||
await storage.updatePatient(patient.id, { status: newStatus });
|
||||
result.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
||||
} else {
|
||||
console.warn(
|
||||
`No patient found with insuranceId: ${insuranceEligibilityData.memberId}`
|
||||
);
|
||||
result.patientUpdateStatus =
|
||||
"Patient not found or missing ID; no update performed";
|
||||
}
|
||||
|
||||
res.json(result);
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
return res.status(500).json({
|
||||
error: err.message || "Failed to forward to selenium agent",
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -6,7 +6,9 @@ import {
|
||||
StaffUncheckedCreateInputObjectSchema,
|
||||
ClaimUncheckedCreateInputObjectSchema,
|
||||
InsuranceCredentialUncheckedCreateInputObjectSchema,
|
||||
ClaimPdfUncheckedCreateInputObjectSchema,
|
||||
PdfFileUncheckedCreateInputObjectSchema,
|
||||
PdfGroupUncheckedCreateInputObjectSchema,
|
||||
PdfCategorySchema,
|
||||
} from "@repo/db/usedSchemas";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -146,8 +148,10 @@ type ClaimWithServiceLines = Claim & {
|
||||
}[];
|
||||
};
|
||||
|
||||
// claim types:
|
||||
type ClaimPdf = z.infer<typeof ClaimPdfUncheckedCreateInputObjectSchema>;
|
||||
// Pdf types:
|
||||
type PdfGroup = z.infer<typeof PdfGroupUncheckedCreateInputObjectSchema>;
|
||||
type PdfFile = z.infer<typeof PdfFileUncheckedCreateInputObjectSchema>;
|
||||
type PdfCategory = z.infer<typeof PdfCategorySchema>;
|
||||
|
||||
export interface ClaimPdfMetadata {
|
||||
id: number;
|
||||
@@ -245,29 +249,36 @@ export interface IStorage {
|
||||
siteKey: string
|
||||
): Promise<InsuranceCredential | null>;
|
||||
|
||||
// Claim PDF Methods
|
||||
createClaimPdf(
|
||||
patientId: number,
|
||||
claimId: number,
|
||||
// General PDF Methods
|
||||
createPdfFile(
|
||||
groupId: number,
|
||||
filename: string,
|
||||
pdfData: Buffer
|
||||
): Promise<ClaimPdf>;
|
||||
|
||||
getClaimPdfById(id: number): Promise<ClaimPdf | undefined>;
|
||||
|
||||
getAllClaimPdfs(): Promise<ClaimPdfMetadata[]>;
|
||||
|
||||
getRecentClaimPdfs(
|
||||
limit: number,
|
||||
offset: number
|
||||
): Promise<ClaimPdfMetadata[]>;
|
||||
|
||||
deleteClaimPdf(id: number): Promise<boolean>;
|
||||
|
||||
updateClaimPdf(
|
||||
): Promise<PdfFile>;
|
||||
getPdfFileById(id: number): Promise<PdfFile | undefined>;
|
||||
getPdfFilesByGroupId(groupId: number): Promise<PdfFile[]>;
|
||||
getRecentPdfFiles(limit: number, offset: number): Promise<PdfFile[]>;
|
||||
deletePdfFile(id: number): Promise<boolean>;
|
||||
updatePdfFile(
|
||||
id: number,
|
||||
updates: Partial<Pick<ClaimPdf, "filename" | "pdfData">>
|
||||
): Promise<ClaimPdf | undefined>;
|
||||
updates: Partial<Pick<PdfFile, "filename" | "pdfData">>
|
||||
): Promise<PdfFile | undefined>;
|
||||
|
||||
// Group management
|
||||
createPdfGroup(
|
||||
patientId: number,
|
||||
title: string,
|
||||
category: PdfCategory
|
||||
): Promise<PdfGroup>;
|
||||
|
||||
getAllPdfGroups(): Promise<PdfGroup[]>;
|
||||
getPdfGroupById(id: number): Promise<PdfGroup | undefined>;
|
||||
getPdfGroupsByPatientId(patientId: number): Promise<PdfGroup[]>;
|
||||
updatePdfGroup(
|
||||
id: number,
|
||||
updates: Partial<Pick<PdfGroup, "title" | "category">>
|
||||
): Promise<PdfGroup | undefined>;
|
||||
deletePdfGroup(id: number): Promise<boolean>;
|
||||
}
|
||||
|
||||
export const storage: IStorage = {
|
||||
@@ -610,73 +621,107 @@ export const storage: IStorage = {
|
||||
});
|
||||
},
|
||||
|
||||
// pdf claims
|
||||
async createClaimPdf(
|
||||
patientId,
|
||||
claimId,
|
||||
filename,
|
||||
pdfData
|
||||
): Promise<ClaimPdf> {
|
||||
return db.claimPdf.create({
|
||||
// PDF Files
|
||||
async createPdfFile(groupId, filename, pdfData) {
|
||||
return db.pdfFile.create({
|
||||
data: {
|
||||
patientId,
|
||||
claimId,
|
||||
groupId,
|
||||
filename,
|
||||
pdfData,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async getClaimPdfById(id: number): Promise<ClaimPdf | undefined> {
|
||||
const pdf = await db.claimPdf.findUnique({ where: { id } });
|
||||
return pdf ?? undefined;
|
||||
},
|
||||
|
||||
async getAllClaimPdfs(): Promise<ClaimPdfMetadata[]> {
|
||||
return db.claimPdf.findMany({
|
||||
select: { id: true, filename: true, uploadedAt: true },
|
||||
orderBy: { uploadedAt: "desc" },
|
||||
});
|
||||
},
|
||||
|
||||
async getRecentClaimPdfs(
|
||||
limit: number,
|
||||
offset: number
|
||||
): Promise<ClaimPdfMetadata[]> {
|
||||
return db.claimPdf.findMany({
|
||||
skip: offset,
|
||||
take: limit,
|
||||
orderBy: { uploadedAt: "desc" },
|
||||
select: {
|
||||
id: true,
|
||||
filename: true,
|
||||
uploadedAt: true,
|
||||
patient: true,
|
||||
async getAllPdfGroups(): Promise<PdfGroup[]> {
|
||||
return db.pdfGroup.findMany({
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async deleteClaimPdf(id: number): Promise<boolean> {
|
||||
async getPdfFileById(id) {
|
||||
return (await db.pdfFile.findUnique({ where: { id } })) ?? undefined;
|
||||
},
|
||||
|
||||
async getPdfFilesByGroupId(groupId) {
|
||||
return db.pdfFile.findMany({
|
||||
where: { groupId },
|
||||
orderBy: { uploadedAt: "desc" },
|
||||
});
|
||||
},
|
||||
|
||||
async getRecentPdfFiles(limit: number, offset: number): Promise<PdfFile[]> {
|
||||
return db.pdfFile.findMany({
|
||||
skip: offset,
|
||||
take: limit,
|
||||
orderBy: { uploadedAt: "desc" },
|
||||
include: { group: true },
|
||||
});
|
||||
},
|
||||
|
||||
async updatePdfFile(id, updates) {
|
||||
try {
|
||||
await db.claimPdf.delete({ where: { id } });
|
||||
return await db.pdfFile.update({
|
||||
where: { id },
|
||||
data: updates,
|
||||
});
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
async deletePdfFile(id) {
|
||||
try {
|
||||
await db.pdfFile.delete({ where: { id } });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
async updateClaimPdf(
|
||||
id: number,
|
||||
updates: Partial<Pick<ClaimPdf, "filename" | "pdfData">>
|
||||
): Promise<ClaimPdf | undefined> {
|
||||
// ----------------------
|
||||
// PdfGroup CRUD
|
||||
// ----------------------
|
||||
|
||||
async createPdfGroup(patientId, title, category) {
|
||||
return db.pdfGroup.create({
|
||||
data: {
|
||||
patientId,
|
||||
title,
|
||||
category,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async getPdfGroupById(id) {
|
||||
return (await db.pdfGroup.findUnique({ where: { id } })) ?? undefined;
|
||||
},
|
||||
|
||||
async getPdfGroupsByPatientId(patientId) {
|
||||
return db.pdfGroup.findMany({
|
||||
where: { patientId },
|
||||
orderBy: { createdAt: "desc" },
|
||||
});
|
||||
},
|
||||
|
||||
async updatePdfGroup(id, updates) {
|
||||
try {
|
||||
const updated = await db.claimPdf.update({
|
||||
return await db.pdfGroup.update({
|
||||
where: { id },
|
||||
data: updates,
|
||||
});
|
||||
return updated;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
async deletePdfGroup(id) {
|
||||
try {
|
||||
await db.pdfGroup.delete({ where: { id } });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user