feat(collection-confirm): add POST /api/v1/order-items/[id]/cost route
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
e860611980
commit
fada6f155f
2 changed files with 91 additions and 0 deletions
65
src/app/api/v1/order-items/[id]/cost/route.test.ts
Normal file
65
src/app/api/v1/order-items/[id]/cost/route.test.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
vi.mock("@/lib/server/collection-confirm-service", () => ({
|
||||
updateOrderItemCost: vi.fn(),
|
||||
}));
|
||||
|
||||
import { POST } from "./route";
|
||||
import { updateOrderItemCost } from "@/lib/server/collection-confirm-service";
|
||||
|
||||
function makePostRequest(id: string, body: unknown) {
|
||||
return new NextRequest(`http://localhost/api/v1/order-items/${id}/cost`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
describe("POST /api/v1/order-items/[id]/cost", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("calls updateOrderItemCost with the route id and body, returns the updated row", async () => {
|
||||
const updatedRow = { id: "row-1", cost_price: 50 };
|
||||
vi.mocked(updateOrderItemCost).mockResolvedValue(updatedRow as never);
|
||||
|
||||
const request = makePostRequest("row-1", {
|
||||
cost_price: 50,
|
||||
actor: { id: "u-1", name: "sj" },
|
||||
});
|
||||
const response = await POST(request, {
|
||||
params: Promise.resolve({ id: "row-1" }),
|
||||
});
|
||||
const body = await response.json();
|
||||
|
||||
expect(updateOrderItemCost).toHaveBeenCalledWith("row-1", {
|
||||
cost_price: 50,
|
||||
actor: { id: "u-1", name: "sj" },
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
expect(body).toEqual(updatedRow);
|
||||
});
|
||||
|
||||
it("returns a 500 with a generic error body and logs the original error", async () => {
|
||||
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
vi.mocked(updateOrderItemCost).mockRejectedValue(new Error("PB down"));
|
||||
|
||||
const request = makePostRequest("row-1", {
|
||||
cost_price: 50,
|
||||
actor: { id: "u-1", name: "sj" },
|
||||
});
|
||||
const response = await POST(request, {
|
||||
params: Promise.resolve({ id: "row-1" }),
|
||||
});
|
||||
expect(response.status).toBe(500);
|
||||
const body = await response.json();
|
||||
expect(body).toEqual({ error: "internal error" });
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
"[POST /api/v1/order-items/[id]/cost]",
|
||||
expect.any(Error),
|
||||
);
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
26
src/app/api/v1/order-items/[id]/cost/route.ts
Normal file
26
src/app/api/v1/order-items/[id]/cost/route.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { updateOrderItemCost } from "@/lib/server/collection-confirm-service";
|
||||
|
||||
/**
|
||||
* POST /api/v1/order-items/[id]/cost
|
||||
*
|
||||
* Thin wrapper around `updateOrderItemCost(id, { cost_price, actor })`
|
||||
* from the collection-confirm service layer. The service is responsible
|
||||
* for the prev-vs-new cost comparison and the audit-note append; this
|
||||
* route just plumbs the HTTP body through and reports failures with a
|
||||
* generic 500 (the real error is logged server-side).
|
||||
*/
|
||||
export async function POST(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> },
|
||||
): Promise<NextResponse> {
|
||||
try {
|
||||
const { id } = await params;
|
||||
const body = await request.json();
|
||||
const updated = await updateOrderItemCost(id, body);
|
||||
return NextResponse.json(updated);
|
||||
} catch (error) {
|
||||
console.error("[POST /api/v1/order-items/[id]/cost]", error);
|
||||
return NextResponse.json({ error: "internal error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue