fix: cascade-delete stale ClaimFile rows and sync claim attachments
Deleting/replacing an appointment attachment left an orphaned ClaimFile copy behind (auto-linked earlier by autoLinkAppointmentFiles), causing the Selenium claim automation to upload extra files beyond what's currently attached to the appointment. Claim PUT was also append-only for claimFiles, so removing an attachment in the UI never persisted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1403,15 +1403,32 @@ router.put("/:id", async (req: Request, res: Response): Promise<any> => {
|
||||
await syncAppointmentType(existingClaim.appointmentId, updatedCodes);
|
||||
}
|
||||
|
||||
// If new claimFiles are provided, append only ones not already attached to this claim
|
||||
if (Array.isArray(req.body.claimFiles) && req.body.claimFiles.length > 0) {
|
||||
// If claimFiles are provided, sync ClaimFile rows to match the submitted list exactly:
|
||||
// delete rows no longer present (so removing an attachment in the UI actually persists)
|
||||
// and add rows not yet attached. Any AppointmentFile still on the appointment gets
|
||||
// re-linked right after by autoLinkAppointmentFiles, so current attachments aren't lost.
|
||||
if (Array.isArray(req.body.claimFiles)) {
|
||||
const { prisma: db } = await import("@repo/db/client");
|
||||
const existingFiles = await db.claimFile.findMany({
|
||||
where: { claimId },
|
||||
select: { filename: true, filePath: true },
|
||||
select: { id: true, filename: true, filePath: true },
|
||||
});
|
||||
const submittedKeys = new Set(
|
||||
req.body.claimFiles.map(
|
||||
(f: any) => `${String(f.filename || "")}::${String(f.filePath || "")}`
|
||||
)
|
||||
);
|
||||
const staleIds = existingFiles
|
||||
.filter((f: any) => !submittedKeys.has(`${f.filename}::${f.filePath ?? ""}`))
|
||||
.map((f: any) => f.id);
|
||||
if (staleIds.length > 0) {
|
||||
await db.claimFile.deleteMany({ where: { id: { in: staleIds } } });
|
||||
}
|
||||
|
||||
const existingKeys = new Set(
|
||||
existingFiles.map((f: any) => `${f.filename}::${f.filePath ?? ""}`)
|
||||
existingFiles
|
||||
.filter((f: any) => !staleIds.includes(f.id))
|
||||
.map((f: any) => `${f.filename}::${f.filePath ?? ""}`)
|
||||
);
|
||||
const seenKeys = new Set<string>();
|
||||
const newFiles = req.body.claimFiles.filter((f: any) => {
|
||||
|
||||
@@ -237,6 +237,12 @@ export const appointmentProceduresStorage: IAppointmentProceduresStorage = {
|
||||
|
||||
await db.appointmentFile.delete({ where: { id: fileId } });
|
||||
|
||||
// Remove any ClaimFile copies previously auto-linked from this appointment file
|
||||
// so a deleted/replaced attachment doesn't linger on the claim and get re-uploaded.
|
||||
await db.claimFile.deleteMany({
|
||||
where: { filename: file.filename, claim: { appointmentId } },
|
||||
});
|
||||
|
||||
// Best-effort cleanup of the underlying cloud-storage file/disk copy.
|
||||
if (file.filePath) {
|
||||
const cloudFile = await db.cloudFile.findFirst({
|
||||
|
||||
Reference in New Issue
Block a user