feat(stock-quick-draft): removeQuickDraftLine

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
SJCoetz 2026-07-30 22:04:37 +02:00
parent 0ed89aac10
commit f7de9d44fd
2 changed files with 66 additions and 0 deletions

View file

@ -162,6 +162,7 @@ vi.mock("./pocketbase-admin", () => ({
import {
addQuickDraftLine,
getStockItemSupplierHistory,
removeQuickDraftLine,
searchStockItemsForQuickDraft,
} from "./stock-quick-draft-service";
@ -580,4 +581,41 @@ describe("addQuickDraftLine", () => {
if (result.ok) return;
expect(result.reason).toBe("stock_item_not_found");
});
});
describe("removeQuickDraftLine", () => {
it("deletes the line and returns ok", async () => {
const supplierId = (
await pbMock.collection("suppliers").create({ suppliername: "S" })
).id;
await pbMock.collection("stock_items").create({
id: "item-1",
sku: "STK-CD-115",
name: "115mm Cutting Disc",
});
const purchase = await pbMock.collection("stock_purchases").create({
supplier: supplierId,
status: "draft",
purchase_number: "PO26070101STK",
});
const line = await pbMock.collection("stock_purchase_items").create({
purchase: purchase.id,
stock_item: "item-1",
description: "115mm Cutting Disc",
quantity: 10,
});
const result = await removeQuickDraftLine(pbMock as never, line.id);
expect(result).toEqual({ ok: true });
const remaining = await pbMock.collection("stock_purchase_items").getFullList();
expect(remaining).toEqual([]);
});
it("returns line_not_found when the line id doesn't exist", async () => {
const result = await removeQuickDraftLine(pbMock as never, "does-not-exist");
expect(result.ok).toBe(false);
if (result.ok) return;
expect(result.reason).toBe("line_not_found");
});
});

View file

@ -437,4 +437,32 @@ export async function addQuickDraftLine(
message: err instanceof Error ? err.message : "line create failed",
};
}
}
/* ============================================================================
* removeQuickDraftLine
* ========================================================================== */
/**
* Deletes a `stock_purchase_items` row by id. Used by the modal's
* cards-region "Remove" button so the buyer can clean up mistakes
* without leaving the modal.
*
* Returns `{ ok: true }` on success, or `{ ok: false, reason }` on
* failure. The modal surfaces the message as a toast.
*/
export async function removeQuickDraftLine(
pb: StockQuickDraftPb,
lineId: string,
): Promise<RemoveQuickDraftLineResult> {
try {
await pb.collection(STOCK_PURCHASE_ITEMS).delete(lineId);
return { ok: true };
} catch (err) {
return {
ok: false,
reason: "line_not_found",
message: err instanceof Error ? err.message : "line delete failed",
};
}
}