diff --git a/src/lib/server/buyer-tasks-service.test.ts b/src/lib/server/buyer-tasks-service.test.ts index ec8dec7..3473e57 100644 --- a/src/lib/server/buyer-tasks-service.test.ts +++ b/src/lib/server/buyer-tasks-service.test.ts @@ -284,6 +284,34 @@ describe("listBuyerTasks", () => { expect(groups[0].supplierEmail).toBe("orders@steelco.example"); }); + it("populates emailError from the related PO when the PO has an email_error", async () => { + const { admin } = makeAdmin([ + baseItem({ + purchase_order: "po-1", + item_status: "po_generated", + expand: { + order: baseOrder, + supplier: baseSupplier, + purchase_order: { + id: "po-1", + status: "draft", + po_number: "PO-26080301", + email_error: "[webhook] Webhook returned HTTP 502", + expand: { + supplier: { id: "sup-1", email: "orders@steelco.example" }, + }, + }, + }, + }), + ]); + vi.mocked(getAdminPocketBase).mockResolvedValue(admin as never); + + const groups = await listBuyerTasks("po_draft"); + + expect(groups).toHaveLength(1); + expect(groups[0].emailError).toBe("[webhook] Webhook returned HTTP 502"); + }); + it("leaves poNumber and supplierEmail null when the PO has no expand", async () => { const { admin } = makeAdmin([ baseItem({ diff --git a/src/lib/server/buyer-tasks-service.ts b/src/lib/server/buyer-tasks-service.ts index 6acaa11..dca786e 100644 --- a/src/lib/server/buyer-tasks-service.ts +++ b/src/lib/server/buyer-tasks-service.ts @@ -27,6 +27,12 @@ export type BuyerTaskGroup = { poStatus: "draft" | "sent" | "sending" | "received" | "mail_failed" | "cancelled" | null; poNumber: string | null; supplierEmail: string | null; + /** Last send-pipeline error. Null on a clean draft or after a successful send. + * Pulled from `purchase_orders.email_error` and truncated to 200 chars at + * the service boundary so a runaway SMTP error doesn't blow up the card + * layout. The full reason remains visible in the order page's send-modal + * banner. */ + emailError: string | null; step: BuyerTaskTab; }; @@ -103,6 +109,13 @@ export async function listBuyerTasks(tab: BuyerTaskTab): Promise