pdf files db, backend route done

This commit is contained in:
2025-07-16 23:54:12 +05:30
parent e25e524308
commit aa913673de
7 changed files with 408 additions and 211 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}
},
};

View File

@@ -23,7 +23,7 @@ endobj
4 0 obj
<</Type /Font
/Subtype /Type0
/BaseFont /GZIEDK+Arial
/BaseFont /MFLEVF+Arial
/Name /F1
/Encoding /Identity-H
/DescendantFonts [5 0 R]
@@ -34,7 +34,7 @@ endobj
5 0 obj
<</Type /Font
/Subtype /CIDFontType2
/BaseFont /GZIEDK+Arial
/BaseFont /MFLEVF+Arial
/CIDSystemInfo 6 0 R
/CIDToGIDMap /Identity
/FontDescriptor 7 0 R
@@ -276,7 +276,7 @@ endobj
7 0 obj
<</Type /FontDescriptor
/FontName /GZIEDK+Arial
/FontName /MFLEVF+Arial
/FontBBox [-664 -324 2000 1039]
/Ascent 905
/Descent -211
@@ -498,8 +498,8 @@ endobj
<EFBFBD>7C<> <20><><EFBFBD><EFBFBD><EFBFBD>I<EFBFBD>t΀r}<7D>rI<72><49>\9<>Q.<2E><>E<EFBFBD><45>S<1B><>ᄲ@8 O
<EFBFBD>
ȁF<EFBFBD>|<7C>WjCr<|K<>Y8<59><38>9qX<71>2<<3C>L<EFBFBD><4C><01>
%^<5E><>\<5C>-'t;<3B>5<EFBFBD><35> <><18> <>(<28>w<EFBFBD>D<16><><EFBFBD><67>τ <0B><>g<EFBFBD><67>f<EFBFBD>F<EFBFBD>6<EFBFBD>a<EFBFBD>&ۿ<05>۷<> c6<19>!<21>y<챾z`~ȃ<><C883><EFBFBD><0E><>;;z<><7A><EFBFBD><EFBFBD><EFBFBD>;3<><33><EFBFBD><EFBFBD>~<7E><>ռ& hJ
g<EFBFBD><a<><61><EFBFBD>_<EFBFBD>
%^<5E><>\<5C>-'t;<3B>5<EFBFBD><35> <><18> <>(<28>w<EFBFBD>D<16><><EFBFBD><67>τ <0B><>g<EFBFBD><67>f<EFBFBD>F<EFBFBD>6<EFBFBD>a<EFBFBD>&ۿ<05>۷<> c6<19>!<21>y<챾z`~ȃ<><C883><EFBFBD><0E><>;;z<><7A><EFBFBD><EFBFBD><EFBFBD>;3<><33><EFBFBD><EFBFBD>~<7E><>ռ& hJ
g<EFBFBD><a<><61><EFBFBD>_<EFBFBD>
{<7B>dy<64><1E>hM<68>/Y<>=<3D><><EFBFBD><EFBFBD>=<3D>RGw<47>Vk<56><6B><EFBFBD><EFBFBD>><1D><0E><>j Ms<73>vq<76>`<60><><DB9A><EFBFBD><EFBFBD>|<7C><>nM<6E>><3E>+<2B>ϙ<EFBFBD>m<EFBFBD><16>y<EFBFBD>ƻn<C6BB>I<EFBFBD>}<7D><>-<2D>գ<EFBFBD>o<EFBFBD><6F>A<EFBFBD><41><EFBFBD>M<EFBFBD>L<EFBFBD><4C><EFBFBD>ҕ<EFBFBD>"<22>[<5B>^<5E>L<><4C>s<EFBFBD><73>o<EFBFBD><6F><EFBFBD><EFBFBD>G<EFBFBD><11><><11>SF<><46><EFBFBD>t<EFBFBD><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD>m>+<2B><>?<3F>r<EFBFBD><0E>{GP'<27>AW<41>5<EFBFBD> 6Z<36><5A><EFBFBD>X/-<2D> <09>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>n@܍<><DC8D><07><>i <0C>g<EFBFBD>/0ȶ<>.<07>F<>qwqZ<71>q=<3D>#h
Mpi<>6<EFBFBD><<3C><><EFBFBD>k/<2F>t`<15><><EFBFBD><EFBFBD>h<EFBFBD>ޛ<EFBFBD><DE9B><EFBFBD>4<EFBFBD><34>U<EFBFBD>zr<1C>Y<EFBFBD>o<EFBFBD><02><> l<15>x<EFBFBD><78><EFBFBD>=<11>:<3A>n<EFBFBD><6E><EFBFBD><EFBFBD><EFBFBD>:<3A><>#<23><><EFBFBD><EFBFBD>m<EFBFBD><6D><EFBFBD>z<EFBFBD>5<EFBFBD>_<EFBFBD>,<2C><>s<08>e <07><04>'<05>X,<2C>LK<4C><4B><EFBFBD>u<EFBFBD>J P<>b*l:<08>,<2C><>2<EFBFBD>ˇ<01>٨<EFBFBD><0E>ZE<>f<EFBFBD>-<2D><> <0B>%x<>q<EFBFBD>s/<2F> ~<7E><>3<EFBFBD><33>v<EFBFBD>΅UǪh<C7AA><68><EFBFBD><02>ʽ<EFBFBD><CABD>A<EFBFBD>Qu<51>ł V<>R-<2D>l !<1F><><EFBFBD>e$<24><><1E><>'<27><01><>vz<07>D<EFBFBD>JC<4A>}Q<>Q<EFBFBD>6z<36><7A><EFBFBD><EFBFBD>5<><19> Z<><5A><EFBFBD>^<5E>w<EFBFBD><77><1C>1<15><><05><>J<EFBFBD>O<EFBFBD>"<22><><EFBFBD>U <20><><EFBFBD>U<EFBFBD><55>C<EFBFBD>Si4<69><34><04>U}_<><5F>"`)<29>:<3A><><13>
<EFBFBD>w<EFBFBD>_G<EFBFBD><EFBFBD>oy< <20>(` <20><><16><><EFBFBD>A<EFBFBD>%<25><><EFBFBD><EFBFBD><EFBFBD>ئވ{q&2<10>!<21>gg<67><67>4<EFBFBD>y<15>|<7C><><EFBFBD><EFBFBD>:<3A>Y<EFBFBD>v=<0E>i\<07><>l<EFBFBD><6C>K<EFBFBD>' ЁV@'<27>}`0<1B><18><02>P6<50>\E<>+x<>yS<79>xC{m<><6D> <09><><EFBFBD>a<EFBFBD><61>Ok̬<6B><CCAC><EFBFBD>rZ<72><5A>i<EFBFBD><69>֜'<27><17>Y<EFBFBD>e<EFBFBD><65>7<EFBFBD>)<29><19>
@@ -608,7 +608,7 @@ trailer
>>
stream
<00><><EFBFBD><EFBFBD>}θ@<><7F>@
endstream
endstream
endobj
11 0 obj

5
dele.txt Normal file
View File

@@ -0,0 +1,5 @@
{
"status": "success",
"eligibility": "Y",
"pdf_path": "C:\\Users\\Potenz\\Desktop\\DentalManager\\apps\\SeleniumService\\seleniumDownloads\\MassDHP_Member_Eligibility_1497211726.pdf"
}

View File

@@ -52,7 +52,10 @@ model Patient {
user User @relation(fields: [userId], references: [id])
appointments Appointment[]
claims Claim[]
pdfs ClaimPdf[]
groups PdfGroup[]
@@index([insuranceId])
@@index([createdAt])
}
model Appointment {
@@ -73,6 +76,9 @@ model Appointment {
user User @relation(fields: [userId], references: [id])
staff Staff? @relation(fields: [staffId], references: [id])
claims Claim[]
@@index([patientId])
@@index([date])
}
model Staff {
@@ -108,7 +114,6 @@ model Claim {
staff Staff? @relation("ClaimStaff", fields: [staffId], references: [id])
serviceLines ServiceLine[]
pdf ClaimPdf[]
}
model ServiceLine {
@@ -136,17 +141,33 @@ model InsuranceCredential {
@@index([userId])
}
model ClaimPdf {
model PdfGroup {
id Int @id @default(autoincrement())
title String // e.g., "June Claim Docs", "Eligibility Set A"
category PdfCategory
createdAt DateTime @default(now())
patientId Int
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
pdfs PdfFile[]
@@index([patientId])
@@index([category])
}
model PdfFile {
id Int @id @default(autoincrement())
patientId Int
claimId Int?
filename String
pdfData Bytes
uploadedAt DateTime @default(now())
groupId Int
group PdfGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
claim Claim? @relation(fields: [claimId], references: [id], onDelete: Cascade)
@@index([groupId])
@@index([patientId])
@@index([claimId])
}
enum PdfCategory {
CLAIM
ELIGIBILITY
OTHER
}

View File

@@ -5,4 +5,6 @@ export * from '../shared/schemas/objects/UserUncheckedCreateInput.schema';
export * from '../shared/schemas/objects/StaffUncheckedCreateInput.schema'
export * from '../shared/schemas/objects/ClaimUncheckedCreateInput.schema'
export * from '../shared/schemas/objects/InsuranceCredentialUncheckedCreateInput.schema'
export * from '../shared/schemas/objects/ClaimPdfUncheckedCreateInput.schema'
export * from '../shared/schemas/objects/PdfFileUncheckedCreateInput.schema'
export * from '../shared/schemas/objects/PdfGroupUncheckedCreateInput.schema'
export * from '../shared/schemas/enums/PdfCategory.schema'