import { describe, expect, it } from "vitest"; import type { OrderItemAiFill } from "@/lib/types"; import { orderReviewerFromAuthRecord, withOrderAiReview, } from "./order-assistant-save"; const NOW = new Date("2026-10-24T12:00:00.000Z"); const REVIEWER = { id: "u1", name: "Sam" }; function fill(over: Partial = {}): OrderItemAiFill { return { status: "filled", source: "quote", quote_item_id: "ql1", quote_id: "q1", quote_number: "Q-2026-10-014", cost_price: 18.2, selling_price: 16.64, markup: -8.57, supplier_id: "sup1", sku: "56020510", reason: "same item", doubts: [], model: "m", attempted_at: NOW.toISOString(), ...over, }; } const pending = { ai_fill: fill(), pricing_source: "ai_quote" }; const saved = { cost_price: 18.2, selling_price: 16.64, supplier: "sup1" }; describe("withOrderAiReview", () => { it("keeps ai_quote when the operator saves an AI-filled line unchanged", () => { const out = withOrderAiReview( pending, { cost_price: 18.2, pricing_source: "ai_quote" }, saved, REVIEWER, NOW, ); expect(out.pricing_source).toBe("ai_quote"); expect(out.ai_fill).toMatchObject({ reviewed_at: NOW.toISOString(), reviewed_by: "Sam", accepted_unchanged: true, }); }); it("lets the one-click 'use this cost' copy end the purple state", () => { // The copy sets pricing_source to "quote" — the operator chose the // quote's cost themselves, so the AI's provenance must not survive. const out = withOrderAiReview( pending, { cost_price: 18.2, pricing_source: "quote" }, saved, REVIEWER, NOW, ); expect(out.pricing_source).toBe("quote"); expect(out.ai_fill).toMatchObject({ reviewed_at: NOW.toISOString() }); }); it("marks a manually priced line as manual", () => { const out = withOrderAiReview( { ai_fill: null, pricing_source: "" }, { cost_price: 5, pricing_source: "" }, { cost_price: 5, selling_price: 9, supplier: null }, REVIEWER, NOW, ); expect(out.pricing_source).toBe("manual"); expect(out.ai_fill).toBeUndefined(); }); it("keeps catalogue", () => { const out = withOrderAiReview( { ai_fill: null, pricing_source: "catalogue" }, { cost_price: 5, pricing_source: "catalogue" }, { cost_price: 5, selling_price: 9, supplier: null }, REVIEWER, NOW, ); expect(out.pricing_source).toBe("catalogue"); }); it("never touches a patch with no pricing_source", () => { const out = withOrderAiReview( { ai_fill: null, pricing_source: "" }, { notes: "hello" }, saved, REVIEWER, NOW, ); expect(out).toEqual({ notes: "hello" }); }); it("never mutates the patch it was given", () => { const patch = { cost_price: 18.2, pricing_source: "ai_quote" }; withOrderAiReview(pending, patch, saved, REVIEWER, NOW); expect(patch).toEqual({ cost_price: 18.2, pricing_source: "ai_quote" }); }); it("records a changed price as not accepted unchanged", () => { const out = withOrderAiReview( pending, { cost_price: 20, pricing_source: "ai_quote" }, { cost_price: 20, selling_price: 16.64, supplier: "sup1" }, REVIEWER, NOW, ); expect((out.ai_fill as OrderItemAiFill).accepted_unchanged).toBe(false); }); it("survives a missing line", () => { const out = withOrderAiReview( undefined, { cost_price: 5, pricing_source: "ai_quote" }, saved, REVIEWER, NOW, ); expect(out.pricing_source).toBe("ai_quote"); expect(out.ai_fill).toBeUndefined(); }); }); describe("orderReviewerFromAuthRecord", () => { it("prefers the name, then the email", () => { expect(orderReviewerFromAuthRecord({ id: "u1", name: "Sam", email: "s@x.co" })).toEqual({ id: "u1", name: "Sam", }); expect(orderReviewerFromAuthRecord({ id: "u1", email: "s@x.co" })).toEqual({ id: "u1", name: "s@x.co", }); expect(orderReviewerFromAuthRecord(null)).toEqual({ id: undefined, name: "" }); }); });