feat(buyer-tasks): markGroupReady with cross-order check
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
98a0bc4143
commit
05242f09f4
2 changed files with 95 additions and 0 deletions
|
|
@ -308,4 +308,58 @@ describe("generatePoForGroup", () => {
|
|||
const { generatePoForGroup } = await import("./buyer-tasks-service");
|
||||
await expect(generatePoForGroup("order-1", "", [{ id: "item-1", costPrice: 25, quantity: 1 }])).rejects.toThrow(/supplierId/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe("markGroupReady", () => {
|
||||
it("updates all items to ready_delivery", async () => {
|
||||
const getOne = vi.fn().mockResolvedValue({ order: "order-1" });
|
||||
const updateItem = vi.fn().mockResolvedValue({});
|
||||
const admin = {
|
||||
collection: vi.fn().mockReturnValue({ getOne, update: updateItem }),
|
||||
};
|
||||
vi.mocked(getAdminPocketBase).mockResolvedValue(admin as never);
|
||||
|
||||
const { markGroupReady } = await import("./buyer-tasks-service");
|
||||
const result = await markGroupReady("order-1", "sup-1", [
|
||||
{ id: "item-1" },
|
||||
{ id: "item-2" },
|
||||
]);
|
||||
|
||||
expect(result.updated).toBe(2);
|
||||
expect(result.failed).toEqual([]);
|
||||
expect(updateItem).toHaveBeenCalledWith("item-1", { item_status: "ready_delivery" });
|
||||
expect(updateItem).toHaveBeenCalledWith("item-2", { item_status: "ready_delivery" });
|
||||
});
|
||||
|
||||
it("returns 0 when no items provided", async () => {
|
||||
const admin = { collection: vi.fn() };
|
||||
vi.mocked(getAdminPocketBase).mockResolvedValue(admin as never);
|
||||
|
||||
const { markGroupReady } = await import("./buyer-tasks-service");
|
||||
const result = await markGroupReady("order-1", "sup-1", []);
|
||||
|
||||
expect(result.updated).toBe(0);
|
||||
expect(result.failed).toEqual([]);
|
||||
});
|
||||
|
||||
it("collects per-item failures", async () => {
|
||||
const getOne = vi.fn().mockResolvedValue({ order: "order-1" });
|
||||
const updateItem = vi.fn().mockImplementation((id: string) => {
|
||||
if (id === "item-2") throw new Error("PB error");
|
||||
return Promise.resolve({});
|
||||
});
|
||||
const admin = {
|
||||
collection: vi.fn().mockReturnValue({ getOne, update: updateItem }),
|
||||
};
|
||||
vi.mocked(getAdminPocketBase).mockResolvedValue(admin as never);
|
||||
|
||||
const { markGroupReady } = await import("./buyer-tasks-service");
|
||||
const result = await markGroupReady("order-1", "sup-1", [
|
||||
{ id: "item-1" },
|
||||
{ id: "item-2" },
|
||||
]);
|
||||
|
||||
expect(result.updated).toBe(1);
|
||||
expect(result.failed).toEqual([{ id: "item-2", error: "PB error" }]);
|
||||
});
|
||||
});
|
||||
|
|
@ -146,3 +146,44 @@ export async function generatePoForGroup(
|
|||
|
||||
return po.id;
|
||||
}
|
||||
|
||||
export async function markGroupReady(
|
||||
orderId: string,
|
||||
supplierId: string,
|
||||
items: Array<{ id: string }>
|
||||
): Promise<{ updated: number; failed: Array<{ id: string; error: string }> }> {
|
||||
if (!orderId || !supplierId) {
|
||||
throw new Error("orderId and supplierId are required");
|
||||
}
|
||||
if (items.length === 0) return { updated: 0, failed: [] };
|
||||
|
||||
const admin = await getAdminPocketBase();
|
||||
const failed: Array<{ id: string; error: string }> = [];
|
||||
let updated = 0;
|
||||
|
||||
for (const item of items) {
|
||||
// Cross-order check: verify the item belongs to this order before
|
||||
// mutating it. Same pattern as updateOrderItemsPrices.
|
||||
try {
|
||||
const current = await admin.collection("order_items").getOne(item.id);
|
||||
if (current.order !== orderId) {
|
||||
failed.push({
|
||||
id: item.id,
|
||||
error: "Item does not belong to this order",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
await admin.collection("order_items").update(item.id, {
|
||||
item_status: "ready_delivery",
|
||||
});
|
||||
updated += 1;
|
||||
} catch (err) {
|
||||
failed.push({
|
||||
id: item.id,
|
||||
error: err instanceof Error ? err.message : "Unknown error",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { updated, failed };
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue