Files
DentalManagementMH07/apps/Backend/src/routes/appointments-procedures.ts

240 lines
7.3 KiB
TypeScript
Executable File

import { Router, Request, Response } from "express";
import { storage } from "../storage";
import { prisma } from "@repo/db/client";
import {
insertAppointmentProcedureSchema,
updateAppointmentProcedureSchema,
} from "@repo/db/types";
const router = Router();
/**
* GET /api/appointment-procedures/:appointmentId
* Get all procedures for an appointment
*/
router.get("/:appointmentId", async (req: Request, res: Response) => {
try {
const appointmentId = Number(req.params.appointmentId);
if (isNaN(appointmentId)) {
return res.status(400).json({ message: "Invalid appointmentId" });
}
const rows = await storage.getByAppointmentId(appointmentId);
return res.json(rows);
} catch (err: any) {
console.error("GET appointment procedures error", err);
return res.status(500).json({ message: err.message ?? "Server error" });
}
});
router.get(
"/prefill-from-appointment/:appointmentId",
async (req: Request, res: Response) => {
try {
const appointmentId = Number(req.params.appointmentId);
if (!appointmentId || isNaN(appointmentId)) {
return res.status(400).json({ error: "Invalid appointmentId" });
}
const data = await storage.getPrefillDataByAppointmentId(appointmentId);
if (!data) {
return res.status(404).json({ error: "Appointment not found" });
}
return res.json(data);
} catch (err: any) {
console.error("prefill-from-appointment error", err);
return res
.status(500)
.json({ error: err.message ?? "Failed to prefill claim data" });
}
}
);
/**
* PUT /api/appointment-procedures/set-npi-provider/:appointmentId
* Set the npiProviderId on all procedures for an appointment (lightweight update).
*/
router.put("/set-npi-provider/:appointmentId", async (req: Request, res: Response) => {
try {
const appointmentId = Number(req.params.appointmentId);
if (isNaN(appointmentId)) return res.status(400).json({ message: "Invalid appointmentId" });
const npiProviderId = req.body.npiProviderId != null ? Number(req.body.npiProviderId) : null;
await prisma.appointmentProcedure.updateMany({
where: { appointmentId },
data: { npiProviderId: npiProviderId ?? null },
});
return res.json({ success: true });
} catch (err: any) {
console.error("set-npi-provider error", err);
return res.status(500).json({ message: err.message ?? "Server error" });
}
});
/**
* POST /api/appointment-procedures/save-for-appointment
* Replace all procedures for an appointment (clear + insert).
* Body: { appointmentId, patientId, npiProviderId?, procedures: [{procedureCode, fee?, toothNumber?, toothSurface?}] }
*/
router.post("/save-for-appointment", async (req: Request, res: Response) => {
try {
const { appointmentId, patientId, npiProviderId, procedures, attachments } = req.body;
if (!appointmentId || isNaN(Number(appointmentId))) {
return res.status(400).json({ message: "Invalid appointmentId" });
}
if (!patientId || isNaN(Number(patientId))) {
return res.status(400).json({ message: "Invalid patientId" });
}
if (!Array.isArray(procedures)) {
return res.status(400).json({ message: "procedures must be an array" });
}
const filtered = (procedures as any[]).filter(
(p) => String(p.procedureCode ?? "").trim() !== ""
);
const validAttachments = Array.isArray(attachments)
? (attachments as any[]).filter((a) => a?.filename).map((a) => ({
filename: String(a.filename),
mimeType: a.mimeType ?? null,
filePath: a.filePath ?? null,
}))
: undefined;
const count = await storage.saveForAppointment({
appointmentId: Number(appointmentId),
patientId: Number(patientId),
npiProviderId: npiProviderId ? Number(npiProviderId) : null,
procedures: filtered.map((p) => ({
procedureCode: String(p.procedureCode).trim(),
fee: p.fee != null ? Number(p.fee) : null,
toothNumber: p.toothNumber || null,
toothSurface: p.toothSurface || null,
})),
attachments: validAttachments,
});
return res.json({ success: true, count });
} catch (err: any) {
console.error("save-for-appointment error", err);
return res.status(500).json({ message: err.message ?? "Server error" });
}
});
/**
* POST /api/appointment-procedures
* Add single manual procedure
*/
router.post("/", async (req: Request, res: Response) => {
try {
const parsed = insertAppointmentProcedureSchema.parse(req.body);
const created = await storage.createProcedure(parsed);
return res.json(created);
} catch (err: any) {
console.error("POST appointment procedure error", err);
if (err.name === "ZodError") {
return res.status(400).json({ message: err.errors });
}
return res.status(500).json({ message: err.message ?? "Server error" });
}
});
/**
* POST /api/appointment-procedures/bulk
* Add multiple procedures (combos)
*/
router.post("/bulk", async (req: Request, res: Response) => {
try {
const rows = req.body;
if (!Array.isArray(rows) || rows.length === 0) {
return res.status(400).json({ message: "Invalid payload" });
}
const count = await storage.createProceduresBulk(rows);
return res.json({ success: true, count });
} catch (err: any) {
console.error("POST bulk appointment procedures error", err);
return res.status(500).json({ message: err.message ?? "Server error" });
}
});
/**
* PUT /api/appointment-procedures/:id
* Update a procedure
*/
router.put("/:id", async (req: Request, res: Response) => {
try {
const id = Number(req.params.id);
if (isNaN(id)) {
return res.status(400).json({ message: "Invalid id" });
}
const parsed = updateAppointmentProcedureSchema.parse(req.body);
const updated = await storage.updateProcedure(id, parsed);
return res.json(updated);
} catch (err: any) {
console.error("PUT appointment procedure error", err);
if (err.name === "ZodError") {
return res.status(400).json({ message: err.errors });
}
return res.status(500).json({ message: err.message ?? "Server error" });
}
});
/**
* DELETE /api/appointment-procedures/:id
* Delete single procedure
*/
router.delete("/:id", async (req: Request, res: Response) => {
try {
const id = Number(req.params.id);
if (isNaN(id)) {
return res.status(400).json({ message: "Invalid id" });
}
await storage.deleteProcedure(id);
return res.json({ success: true });
} catch (err: any) {
console.error("DELETE appointment procedure error", err);
return res.status(500).json({ message: err.message ?? "Server error" });
}
});
/**
* DELETE /api/appointment-procedures/clear/:appointmentId
* Clear all procedures for appointment
*/
router.delete("/clear/:appointmentId", async (req: Request, res: Response) => {
try {
const appointmentId = Number(req.params.appointmentId);
if (isNaN(appointmentId)) {
return res.status(400).json({ message: "Invalid appointmentId" });
}
await storage.clearByAppointmentId(appointmentId);
return res.json({ success: true });
} catch (err: any) {
console.error("CLEAR appointment procedures error", err);
return res.status(500).json({ message: err.message ?? "Server error" });
}
});
export default router;