feat(stock): add POST /api/v1/stock/items/set-pricing
This commit is contained in:
parent
ab639eea6d
commit
6f8c6da0fe
1 changed files with 78 additions and 0 deletions
78
src/app/api/v1/stock/items/set-pricing/route.ts
Normal file
78
src/app/api/v1/stock/items/set-pricing/route.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { updateStockItemsPricing } from "@/lib/server/stock-pricing-service";
|
||||
import { getAdminPocketBase } from "@/lib/server/pocketbase-admin";
|
||||
|
||||
const MAX_UPDATES = 100;
|
||||
|
||||
const PB_ID_RE = /^[a-z0-9]{15}$/;
|
||||
|
||||
type Body = {
|
||||
updates?: Array<{ id?: unknown; costPrice?: unknown; sellingPrice?: unknown; markup?: unknown }>;
|
||||
actor?: { id?: unknown; name?: unknown };
|
||||
};
|
||||
|
||||
export async function POST(req: Request) {
|
||||
let body: Body;
|
||||
try {
|
||||
body = (await req.json()) as Body;
|
||||
} catch {
|
||||
return NextResponse.json(
|
||||
{ code: "invalid_json", message: "Body is not valid JSON" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
if (!Array.isArray(body.updates) || body.updates.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ code: "validation_error", message: "updates must be a non-empty array" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
if (body.updates.length > MAX_UPDATES) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
code: "validation_error",
|
||||
message: `At most ${MAX_UPDATES} updates per call`,
|
||||
},
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
if (!body.actor || typeof body.actor.id !== "string" || !body.actor.id) {
|
||||
return NextResponse.json(
|
||||
{ code: "validation_error", message: "actor.id is required" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const updates = body.updates.map((u, i) => {
|
||||
if (typeof u.id !== "string" || !PB_ID_RE.test(u.id)) {
|
||||
throw new Error(`updates[${i}].id must be a 15-char PB id`);
|
||||
}
|
||||
const out: { id: string; costPrice?: number; sellingPrice?: number; markup?: number } = {
|
||||
id: u.id,
|
||||
};
|
||||
if (u.costPrice !== undefined) out.costPrice = Number(u.costPrice);
|
||||
if (u.sellingPrice !== undefined) out.sellingPrice = Number(u.sellingPrice);
|
||||
if (u.markup !== undefined) out.markup = Number(u.markup);
|
||||
return out;
|
||||
});
|
||||
|
||||
let pb;
|
||||
try {
|
||||
pb = await getAdminPocketBase();
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
return NextResponse.json(
|
||||
{ code: "pb_error", message },
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
const result = await updateStockItemsPricing({
|
||||
pb,
|
||||
updates,
|
||||
actor: { id: body.actor.id, name: String(body.actor.name ?? body.actor.id) },
|
||||
});
|
||||
|
||||
return NextResponse.json(result, { status: 200 });
|
||||
}
|
||||
Loading…
Reference in a new issue