feat(buyer-tasks): GET /api/v1/buyer-tasks route
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
05242f09f4
commit
275a47e28f
2 changed files with 92 additions and 0 deletions
63
src/app/api/v1/buyer-tasks/route.test.ts
Normal file
63
src/app/api/v1/buyer-tasks/route.test.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import { describe, it, expect, beforeEach, vi } from "vitest";
|
||||
|
||||
vi.mock("@/lib/server/buyer-tasks-service", () => ({
|
||||
listBuyerTasks: vi.fn(),
|
||||
}));
|
||||
|
||||
import { GET } from "./route";
|
||||
import { listBuyerTasks } from "@/lib/server/buyer-tasks-service";
|
||||
|
||||
function makeRequest(tab: string | null) {
|
||||
const url = tab ? `http://test/api/v1/buyer-tasks?tab=${tab}` : "http://test/api/v1/buyer-tasks";
|
||||
return new Request(url);
|
||||
}
|
||||
|
||||
describe("GET /api/v1/buyer-tasks", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("returns groups for valid tab", async () => {
|
||||
vi.mocked(listBuyerTasks).mockResolvedValue([
|
||||
{
|
||||
groupId: "order-1::sup-1",
|
||||
orderId: "order-1",
|
||||
orderNumber: "ORD-001",
|
||||
supplierId: "sup-1",
|
||||
supplierName: "Steel Co",
|
||||
customerName: "J. Smith",
|
||||
companyName: "Acme",
|
||||
items: [],
|
||||
itemCount: 1,
|
||||
totalCost: 50,
|
||||
purchaseOrderId: null,
|
||||
poStatus: null,
|
||||
step: "needs_po",
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await GET(makeRequest("needs_po") as never);
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
expect(body.groups).toHaveLength(1);
|
||||
expect(body.groups[0].supplierName).toBe("Steel Co");
|
||||
});
|
||||
|
||||
it("returns 400 on invalid tab", async () => {
|
||||
const res = await GET(makeRequest("invalid") as never);
|
||||
expect(res.status).toBe(400);
|
||||
const body = await res.json();
|
||||
expect(body.error).toMatch(/tab/i);
|
||||
});
|
||||
|
||||
it("returns 400 when tab is missing", async () => {
|
||||
const res = await GET(makeRequest(null) as never);
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
|
||||
it("returns 500 on service error", async () => {
|
||||
vi.mocked(listBuyerTasks).mockRejectedValue(new Error("PB down"));
|
||||
const res = await GET(makeRequest("needs_po") as never);
|
||||
expect(res.status).toBe(500);
|
||||
});
|
||||
});
|
||||
29
src/app/api/v1/buyer-tasks/route.ts
Normal file
29
src/app/api/v1/buyer-tasks/route.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { listBuyerTasks, type BuyerTaskTab } from "@/lib/server/buyer-tasks-service";
|
||||
|
||||
const VALID_TABS: BuyerTaskTab[] = ["needs_po", "po_draft", "po_sent"];
|
||||
|
||||
export async function GET(req: NextRequest | Request) {
|
||||
// NextRequest exposes a parsed `nextUrl`; a plain Request (used in
|
||||
// unit tests with `new Request(url)`) doesn't. Fall back to parsing
|
||||
// `req.url` so both shapes work.
|
||||
const tab = (req as NextRequest).nextUrl?.searchParams?.get("tab")
|
||||
?? new URL(req.url).searchParams.get("tab");
|
||||
|
||||
if (!tab || !VALID_TABS.includes(tab as BuyerTaskTab)) {
|
||||
return NextResponse.json(
|
||||
{ error: "Invalid or missing 'tab' parameter" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const groups = await listBuyerTasks(tab as BuyerTaskTab);
|
||||
return NextResponse.json({ groups });
|
||||
} catch (err) {
|
||||
return NextResponse.json(
|
||||
{ error: err instanceof Error ? err.message : "Failed to load buyer tasks" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue