feat(collection-confirm): add POST /api/v1/order-items/confirm route
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
fada6f155f
commit
3f228808ea
2 changed files with 99 additions and 0 deletions
72
src/app/api/v1/order-items/confirm/route.test.ts
Normal file
72
src/app/api/v1/order-items/confirm/route.test.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
vi.mock("@/lib/server/collection-confirm-service", () => ({
|
||||
confirmOrderItemsForInvoicing: vi.fn(),
|
||||
}));
|
||||
|
||||
import { POST } from "./route";
|
||||
import { confirmOrderItemsForInvoicing } from "@/lib/server/collection-confirm-service";
|
||||
|
||||
function makePostRequest(body: unknown) {
|
||||
return new NextRequest("http://localhost/api/v1/order-items/confirm", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
describe("POST /api/v1/order-items/confirm", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("calls confirmOrderItemsForInvoicing with the body and returns the updated ids", async () => {
|
||||
const updatedIds = ["row-1", "row-2"];
|
||||
vi.mocked(confirmOrderItemsForInvoicing).mockResolvedValue(updatedIds);
|
||||
|
||||
const requestBody = {
|
||||
itemIds: ["row-1", "row-2"],
|
||||
invoice: { date: "2026-08-03", number: "INV-1" },
|
||||
costOverrides: { "row-1": 50 },
|
||||
actor: { id: "u-1", name: "sj" },
|
||||
};
|
||||
const request = makePostRequest(requestBody);
|
||||
const response = await POST(request);
|
||||
const body = await response.json();
|
||||
|
||||
expect(confirmOrderItemsForInvoicing).toHaveBeenCalledWith(
|
||||
["row-1", "row-2"],
|
||||
{
|
||||
invoice: { date: "2026-08-03", number: "INV-1" },
|
||||
costOverrides: { "row-1": 50 },
|
||||
actor: { id: "u-1", name: "sj" },
|
||||
},
|
||||
);
|
||||
expect(response.status).toBe(200);
|
||||
expect(body).toEqual(updatedIds);
|
||||
});
|
||||
|
||||
it("returns a 500 with a generic error body and logs the original error", async () => {
|
||||
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
vi.mocked(confirmOrderItemsForInvoicing).mockRejectedValue(
|
||||
new Error("PB down"),
|
||||
);
|
||||
|
||||
const request = makePostRequest({
|
||||
itemIds: [],
|
||||
invoice: { date: "2026-08-03", number: "INV-1" },
|
||||
costOverrides: {},
|
||||
actor: { id: "u-1", name: "sj" },
|
||||
});
|
||||
const response = await POST(request);
|
||||
expect(response.status).toBe(500);
|
||||
const body = await response.json();
|
||||
expect(body).toEqual({ error: "internal error" });
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
"[POST /api/v1/order-items/confirm]",
|
||||
expect.any(Error),
|
||||
);
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
27
src/app/api/v1/order-items/confirm/route.ts
Normal file
27
src/app/api/v1/order-items/confirm/route.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { confirmOrderItemsForInvoicing } from "@/lib/server/collection-confirm-service";
|
||||
|
||||
/**
|
||||
* POST /api/v1/order-items/confirm
|
||||
*
|
||||
* Thin wrapper around `confirmOrderItemsForInvoicing(ids, { invoice,
|
||||
* costOverrides, actor })` from the collection-confirm service layer.
|
||||
* The service performs the batched PocketBase update with cost-override
|
||||
* audit notes; 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): Promise<NextResponse> {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { itemIds, invoice, costOverrides, actor } = body;
|
||||
const ids = await confirmOrderItemsForInvoicing(itemIds, {
|
||||
invoice,
|
||||
costOverrides,
|
||||
actor,
|
||||
});
|
||||
return NextResponse.json(ids);
|
||||
} catch (error) {
|
||||
console.error("[POST /api/v1/order-items/confirm]", error);
|
||||
return NextResponse.json({ error: "internal error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue