import { describe, expect, it } from "vitest"; import { deliveryAssignmentState, filterDeliveryPool, groupDeliveryPool, normalizeInvoiceNumber, type DeliveryPoolLine, } from "./delivery-pool"; function line(over: Partial): DeliveryPoolLine { return { id: "l1", description: "M20 nut", quantity: 1, selling_price: 10, customer_invoice_number: "INV100", delivery_note_number: "", invoiced_date: "2026-10-30", delivery_driver: "", delivery_assigned_at: "", order_id: "o1", order_number: "ORD-1", company_id: "c1", company_name: "Acme", invoice_pdf: "", ...over, }; } describe("normalizeInvoiceNumber", () => { it("treats bare digits and the INV prefix as the same invoice", () => { expect(normalizeInvoiceNumber("30352")).toBe("INV30352"); expect(normalizeInvoiceNumber("inv 30352")).toBe("INV30352"); expect(normalizeInvoiceNumber("INV-30352")).toBe("INV30352"); }); it("keeps non-numeric numbers and blanks", () => { expect(normalizeInvoiceNumber("ABC-9")).toBe("ABC-9"); expect(normalizeInvoiceNumber(" ")).toBe(""); expect(normalizeInvoiceNumber(null)).toBe(""); }); }); describe("groupDeliveryPool", () => { it("groups per company, then one card per invoice", () => { const groups = groupDeliveryPool([ line({ id: "a", customer_invoice_number: "30352", quantity: 2, selling_price: 5 }), line({ id: "b", customer_invoice_number: "INV30352", delivery_note_number: "DN1" }), line({ id: "c", customer_invoice_number: "INV1", company_id: "c2", company_name: "Bolt Co" }), ]); expect(groups.map((g) => g.name)).toEqual(["Acme", "Bolt Co"]); expect(groups[0].invoices).toHaveLength(1); const inv = groups[0].invoices[0]; expect(inv.invoiceNumber).toBe("INV30352"); expect(inv.lines.map((l) => l.id)).toEqual(["a", "b"]); expect(inv.total).toBe(20); expect(inv.dnNumbers).toEqual(["DN1"]); expect(groups[0].total).toBe(20); }); it("skips lines without an invoice number and puts unknown companies last", () => { const groups = groupDeliveryPool([ line({ id: "x", customer_invoice_number: "" }), line({ id: "u", customer_invoice_number: "INV9", company_id: "", company_name: "" }), line({ id: "z", customer_invoice_number: "INV8", company_id: "c9", company_name: "Zulu" }), ]); expect(groups.map((g) => g.name)).toEqual(["Zulu", "Unknown company"]); }); it("reports a shared assignment, or mixed when the lines disagree", () => { const same = groupDeliveryPool([ line({ id: "a", delivery_driver: "d1", delivery_assigned_at: "2026-10-31" }), line({ id: "b", delivery_driver: "d1", delivery_assigned_at: "2026-10-31" }), ])[0].invoices[0]; expect(same).toMatchObject({ driverId: "d1", assignedAt: "2026-10-31", mixedAssignment: false }); const mixed = groupDeliveryPool([ line({ id: "a", delivery_driver: "d1", delivery_assigned_at: "2026-10-31" }), line({ id: "b" }), ])[0].invoices[0]; expect(mixed).toMatchObject({ driverId: "", mixedAssignment: true }); }); it("orders invoices newest first and finds the invoice PDF", () => { const [company] = groupDeliveryPool([ line({ id: "a", customer_invoice_number: "INV1", invoiced_date: "2026-10-30" }), line({ id: "b", customer_invoice_number: "INV2", invoiced_date: "2026-10-31", invoice_pdf: "inv2_abc.pdf" }), ]); expect(company.invoices.map((i) => i.invoiceNumber)).toEqual(["INV2", "INV1"]); expect(company.invoices[0].invoicePdf).toEqual({ lineId: "b", filename: "inv2_abc.pdf" }); }); }); describe("deliveryAssignmentState", () => { const today = "2026-10-30"; it("covers every state", () => { expect(deliveryAssignmentState({ driverId: "", assignedAt: "", mixedAssignment: false }, today)).toBe("unassigned"); expect(deliveryAssignmentState({ driverId: "d", assignedAt: today, mixedAssignment: false }, today)).toBe("today"); expect(deliveryAssignmentState({ driverId: "d", assignedAt: "2026-10-29", mixedAssignment: false }, today)).toBe("overdue"); expect(deliveryAssignmentState({ driverId: "d", assignedAt: "2026-11-02", mixedAssignment: false }, today)).toBe("future"); expect(deliveryAssignmentState({ driverId: "", assignedAt: "", mixedAssignment: true }, today)).toBe("mixed"); }); }); describe("filterDeliveryPool", () => { const groups = groupDeliveryPool([ line({ id: "a", customer_invoice_number: "INV1", delivery_driver: "d1", delivery_assigned_at: "2026-10-30" }), line({ id: "b", customer_invoice_number: "INV2", description: "Hex bolt" }), line({ id: "c", customer_invoice_number: "INV3", company_id: "c2", company_name: "Bolt Co" }), ]); it("matches company, invoice and line text", () => { expect(filterDeliveryPool(groups, "hex", "all")[0].invoices.map((i) => i.invoiceNumber)).toEqual(["INV2"]); expect(filterDeliveryPool(groups, "bolt co", "all").map((c) => c.name)).toEqual(["Bolt Co"]); expect(filterDeliveryPool(groups, "inv3", "all")).toHaveLength(1); }); it("filters by driver and drops empty companies", () => { expect(filterDeliveryPool(groups, "", "d1").map((c) => c.invoices.length)).toEqual([1]); const unassigned = filterDeliveryPool(groups, "", "unassigned"); expect(unassigned.flatMap((c) => c.invoices.map((i) => i.invoiceNumber)).sort()).toEqual(["INV2", "INV3"]); }); });