feat(stock-quick-draft): PATCH /api/v1/stock-quick-draft/line/[lineId]

Adds a PATCH handler next to the existing DELETE handler. Validates
JSON body, maps service result reasons to HTTP status codes, and uses
admin PB to bypass user-side collection rules.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
SJCoetz 2026-07-31 13:40:06 +02:00
parent da0a689507
commit 811b2dca1c

View file

@ -1,6 +1,10 @@
import { NextRequest, NextResponse } from "next/server";
import { getAdminPocketBase } from "@/lib/server/pocketbase-admin";
import { removeQuickDraftLine } from "@/lib/server/stock-quick-draft-service";
import {
removeQuickDraftLine,
updateQuickDraftLine,
type UpdateQuickDraftLineResult,
} from "@/lib/server/stock-quick-draft-service";
/**
* DELETE /api/v1/stock-quick-draft/line/[lineId]
@ -44,3 +48,74 @@ export async function DELETE(
);
}
}
type FailureReason = Extract<UpdateQuickDraftLineResult, { ok: false }>["reason"];
const STATUS_BY_REASON: Record<FailureReason, number> = {
validation: 400,
line_not_found: 404,
update_failed: 500,
};
/**
* PATCH /api/v1/stock-quick-draft/line/[lineId]
*
* Updates `quantity` and/or `cost_price` on a stock_purchase_items
* row. Backed by `updateQuickDraftLine` in the service module.
*
* Request body: { quantity?: number (>0), costPrice?: number (>=0) }
* At least one of the two fields is required.
*
* Response (success): { ok: true }
* Error mapping (reason → status):
* "validation" → 400
* "line_not_found" → 404
* "update_failed" → 500
*/
export async function PATCH(
req: NextRequest,
ctx: { params: Promise<{ lineId: string }> },
) {
const { lineId } = await ctx.params;
if (!lineId) {
return NextResponse.json(
{ ok: false, reason: "validation", message: "lineId is required" },
{ status: 400 },
);
}
let body: Record<string, unknown>;
try {
body = (await req.json()) as Record<string, unknown>;
} catch {
return NextResponse.json(
{ ok: false, reason: "validation", message: "invalid JSON body" },
{ status: 400 },
);
}
const quantity = typeof body.quantity === "number" ? body.quantity : undefined;
const costPrice = typeof body.costPrice === "number" ? body.costPrice : undefined;
try {
const pb = await getAdminPocketBase();
const result = await updateQuickDraftLine(pb as never, {
lineId,
quantity,
costPrice,
});
if (!result.ok) {
const status = STATUS_BY_REASON[result.reason] ?? 500;
return NextResponse.json(result, { status });
}
return NextResponse.json(result);
} catch (err) {
return NextResponse.json(
{
ok: false,
reason: "update_failed",
message: err instanceof Error ? err.message : "unknown error",
},
{ status: 500 },
);
}
}