From ebbcc730208def74e19dcbe2d67fcc994daeb3a5 Mon Sep 17 00:00:00 2001 From: Dave Date: Thu, 27 Aug 2026 23:52:59 +0200 Subject: [PATCH] fix(boss-dashboard): exclude cancelled orders via order_items.item_status The cancelled check was reading orders.item_status, which doesn't exist on the orders collection in PB. Status lives on order_items, so the check never fired and cancelled orders were counted in orderTotals.total and each rep's ordersPlaced. Mirror the delivered fix: derive a cancelled-order-id set from order_items.item_status in the active window. An order is excluded from total if ANY of its lines carries item_status="cancelled". Co-Authored-By: Claude --- src/lib/server/boss-dashboard-service.test.ts | 74 +++++++++++++++++-- src/lib/server/boss-dashboard-service.ts | 39 +++++----- 2 files changed, 89 insertions(+), 24 deletions(-) diff --git a/src/lib/server/boss-dashboard-service.test.ts b/src/lib/server/boss-dashboard-service.test.ts index 4cffddb..a36e0ed 100644 --- a/src/lib/server/boss-dashboard-service.test.ts +++ b/src/lib/server/boss-dashboard-service.test.ts @@ -149,16 +149,17 @@ beforeEach(() => { describe("getBossDashboardData", () => { it("returns orderTotals: total/delivered/invoiced for the window", async () => { // 3 orders in window: 1 delivered, 1 invoiced, 1 pending. 1 cancelled. - // order_items rows back the delivered count via the order relation. - const orderPending = addRow("orders", { created: "2026-08-27T08:00:00.000Z", rep: "rep-1", invoiced: false, item_status: "pending" }); - const orderDelivered = addRow("orders", { created: "2026-08-27T09:00:00.000Z", rep: "rep-1", invoiced: false, item_status: "delivered" }); - const orderInvoiced = addRow("orders", { created: "2026-08-27T10:00:00.000Z", rep: "rep-2", invoiced: true, item_status: "invoiced" }); - addRow("orders", { created: "2026-08-27T11:00:00.000Z", rep: "rep-2", invoiced: false, item_status: "cancelled" }); + // order_items rows back both delivered AND cancelled via the order relation. + const orderPending = addRow("orders", { created: "2026-08-27T08:00:00.000Z", rep: "rep-1", invoiced: false }); + const orderDelivered = addRow("orders", { created: "2026-08-27T09:00:00.000Z", rep: "rep-1", invoiced: false }); + const orderInvoiced = addRow("orders", { created: "2026-08-27T10:00:00.000Z", rep: "rep-2", invoiced: true }); + const orderCancelled = addRow("orders", { created: "2026-08-27T11:00:00.000Z", rep: "rep-2", invoiced: false }); - // Only the delivered order has an order_item with item_status="delivered". + // order_items carry the actual status (orders.item_status doesn't exist in PB). addRow("order_items", { order: orderPending, item_status: "pending", created: "2026-08-27T08:00:00.000Z" }); addRow("order_items", { order: orderDelivered, item_status: "delivered", created: "2026-08-27T09:00:00.000Z" }); addRow("order_items", { order: orderInvoiced, item_status: "invoiced", created: "2026-08-27T10:00:00.000Z" }); + addRow("order_items", { order: orderCancelled, item_status: "cancelled", created: "2026-08-27T11:00:00.000Z" }); const data = await getBossDashboardData({ window: "today", now: fixedNow }); @@ -190,6 +191,67 @@ describe("getBossDashboardData", () => { expect(data.orderTotals.delivered).toBe(1); }); + it("excludes cancelled orders from total via order_items.item_status", async () => { + // Regression: orders.item_status doesn't exist in PB. The old check + // (o as Record).item_status === "cancelled" therefore + // never fired and cancelled orders were counted in total + ordersPlaced. + // Cancellation lives on order_items.item_status. If ANY item in an order is + // cancelled, the whole order is excluded from total and ordersPlaced. + addRow("users", { id: "rep-1", name: "Gary" }); + addRow("users", { id: "rep-2", name: "Shireen" }); + + // Mixed order: one delivered line + one cancelled line. Per spec, ANY cancelled + // line excludes the order from total — even if other lines are delivered. + const mixedOrder = addRow("orders", { + rep: "rep-1", + invoiced: false, + created: "2026-08-27T08:00:00.000Z", + }); + addRow("order_items", { + order: mixedOrder, + item_status: "delivered", + created: "2026-08-27T08:30:00.000Z", + }); + addRow("order_items", { + order: mixedOrder, + item_status: "cancelled", + created: "2026-08-27T08:45:00.000Z", + }); + + // Fully cancelled order (rep-2). + const cancelledOnly = addRow("orders", { + rep: "rep-2", + invoiced: false, + created: "2026-08-27T09:00:00.000Z", + }); + addRow("order_items", { + order: cancelledOnly, + item_status: "cancelled", + created: "2026-08-27T09:00:00.000Z", + }); + + // Healthy order (rep-1) — should be counted. + const healthyOrder = addRow("orders", { + rep: "rep-1", + invoiced: false, + created: "2026-08-27T10:00:00.000Z", + }); + addRow("order_items", { + order: healthyOrder, + item_status: "pending", + created: "2026-08-27T10:00:00.000Z", + }); + + const data = await getBossDashboardData({ window: "today", now: fixedNow }); + + // Only the healthy order counts. + expect(data.orderTotals.total).toBe(1); + // rep-1's ordersPlaced drops to 1 (only the healthy order); rep-2 is 0. + const byId = Object.fromEntries(data.reps.map((r) => [r.id, r])); + expect(byId["rep-1"].ordersPlaced).toBe(1); + expect(byId["rep-2"].ordersPlaced).toBe(0); + }); + it("groups reps with quotesLoaded/doneFor/doneBy and ordersPlaced", async () => { // Users addRow("users", { id: "rep-1", name: "Gary Ndlovu" }); diff --git a/src/lib/server/boss-dashboard-service.ts b/src/lib/server/boss-dashboard-service.ts index a9707f5..cbd7a95 100644 --- a/src/lib/server/boss-dashboard-service.ts +++ b/src/lib/server/boss-dashboard-service.ts @@ -117,9 +117,9 @@ export async function getBossDashboardData({ }), ]); - // Delivered orders are derived from order_items.item_status (not orders.item_status, - // which doesn't exist in PB). Active window only. - const deliveredItems = await pb.collection("order_items").getFullList({ + // Delivered + cancelled are derived from order_items.item_status (the orders + // collection doesn't carry item_status in PB). Active window only. + const orderItemsInWindow = await pb.collection("order_items").getFullList({ filter: rangeFilter, fields: "order,item_status", }); @@ -137,6 +137,23 @@ export async function getBossDashboardData({ customerRepById.set(c.id, String((c as Record).rep ?? "")); } + // Build sets of order ids that have a delivered item vs a cancelled item. + // Definition: an order is "cancelled" if ANY of its order_items in the active + // window carries item_status="cancelled". This matches the spec: total counts + // orders placed in the window EXCLUDING cancelled ones. (orders.item_status + // doesn't exist in PB — the status lives on order_items.) + const deliveredOrderIds = new Set(); + const cancelledOrderIds = new Set(); + for (const item of orderItemsInWindow) { + const rec = item as Record; + const orderId = String(rec.order ?? "").trim(); + if (!orderId) continue; + const status = String(rec.item_status ?? ""); + if (status === "delivered") deliveredOrderIds.add(orderId); + if (status === "cancelled") cancelledOrderIds.add(orderId); + } + const delivered = deliveredOrderIds.size; + // --- Order totals + per-rep order counts --------------------------------- let total = 0; let invoiced = 0; @@ -144,8 +161,7 @@ export async function getBossDashboardData({ for (const o of orders) { const rec = o as Record; - const itemStatus = String(rec.item_status ?? ""); - const isCancelled = itemStatus === "cancelled"; + const isCancelled = cancelledOrderIds.has(o.id); if (!isCancelled) total += 1; if (rec.invoiced === true) invoiced += 1; @@ -154,19 +170,6 @@ export async function getBossDashboardData({ if (repId) repOrders.set(repId, (repOrders.get(repId) ?? 0) + 1); } - // Delivered: count distinct order ids with at least one item_status="delivered" - // in the active window. (orders.item_status doesn't exist in PB; the status lives - // on order_items.) - const deliveredOrderIds = new Set(); - for (const item of deliveredItems) { - const rec = item as Record; - if (String(rec.item_status ?? "") === "delivered") { - const orderId = String(rec.order ?? "").trim(); - if (orderId) deliveredOrderIds.add(orderId); - } - } - const delivered = deliveredOrderIds.size; - // --- Per-rep quote stats -------------------------------------------------- // quotesLoaded: claimed_by resolves to this rep // quotesDoneFor: the quote's customer belongs to this rep