From 1477265db9d06e2dc30e5462c03c75d92577a622 Mon Sep 17 00:00:00 2001 From: SJCoetz Date: Thu, 9 Jul 2026 23:18:51 +0200 Subject: [PATCH] feat(po-attachments): add delete route for PO additional attachments --- .../[id]/attachments/[filename]/route.ts | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/app/api/v1/purchase-orders/[id]/attachments/[filename]/route.ts diff --git a/src/app/api/v1/purchase-orders/[id]/attachments/[filename]/route.ts b/src/app/api/v1/purchase-orders/[id]/attachments/[filename]/route.ts new file mode 100644 index 0000000..39d64c8 --- /dev/null +++ b/src/app/api/v1/purchase-orders/[id]/attachments/[filename]/route.ts @@ -0,0 +1,76 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getAdminPocketBase } from "@/lib/server/pocketbase-admin"; + +/** + * DELETE /api/v1/purchase-orders/[id]/attachments/[filename] + * + * Remove a single additional attachment from a PO by token. The + * `filename` segment is the PB-stored token (the same string that + * appears in `additional_attachments[]`), not the operator's + * original filename. + * + * Response: + * 200 — { ok: true, attachments: [remaining tokens] } + * 404 — { error: "Attachment not found" } + * 500 — { error: "PB admin unavailable" | } + * + * Note: PB doesn't have a "delete from a multi-file field" op via + * the SDK, so we read the array, filter out the matching token, and + * write the rest back. The original PB file on disk is not deleted + * (PB doesn't expose a per-file delete from a multi-file field) — + * the token is just removed from the array, so the Send PO modal + * stops showing it. Re-uploading creates a fresh file. + */ + +export const runtime = "nodejs"; +export const dynamic = "force-dynamic"; + +export async function DELETE( + _req: NextRequest, + { params }: { params: Promise<{ id: string; filename: string }> }, +) { + const { id: poId, filename: token } = await params; + + let adminPb; + try { + adminPb = await getAdminPocketBase(); + } catch { + return NextResponse.json( + { error: "PB admin unavailable" }, + { status: 500 }, + ); + } + + try { + const po = await adminPb + .collection("purchase_orders") + .getOne<{ additional_attachments?: string[] | string }>(poId, { + fields: "id,additional_attachments", + }); + + const raw = po?.additional_attachments ?? []; + const arr = Array.isArray(raw) ? raw : raw ? [raw] : []; + + if (!arr.includes(token)) { + return NextResponse.json( + { error: "Attachment not found" }, + { status: 404 }, + ); + } + + const remaining = arr.filter((t) => t !== token); + await adminPb.collection("purchase_orders").update(poId, { + additional_attachments: remaining, + }); + + return NextResponse.json( + { ok: true, attachments: remaining }, + { status: 200 }, + ); + } catch (err) { + return NextResponse.json( + { error: err instanceof Error ? err.message : "Delete failed" }, + { status: 500 }, + ); + } +}