diff --git a/docs/collection-ai-checks.md b/docs/collection-ai-checks.md index 6feeca8..c5ce304 100644 --- a/docs/collection-ai-checks.md +++ b/docs/collection-ai-checks.md @@ -102,11 +102,13 @@ Collection checks, and stored in | Green | The document agrees with our line: our SKU equals the document code after normalising (uppercase, letters and digits only; this is also how a SKU the AI filled goes green), quantity equals what was collected and what was ordered, the AI is sure it is the same item, unit price after any discount within 1 cent | | Amber | Close but worth a look: our SKU differs from the document code; collected quantity matches the document but the ordered quantity differs; the AI thinks it is the same item but is only "likely" sure | | Red | Mismatch or missing: no SKU on our line, quantity differs from the document, price differs or we have no cost, or the line is not on the document or the AI says it is a different product (all four red) | -| Grey | Can't check, per tick: **SKU** when the document line shows no code; **Qty** when it shows no quantity; **Price** on a delivery note or when the document line shows no price; **all four** when the AI couldn't pair the document (see the AI findings box for the reason; **Check with AI** retries) | +| Grey | Can't check, per tick: **SKU** when the document line shows no code; **Qty** when it shows no quantity; **Price** when the document line shows no price (a delivery note that prints prices, like Plumblink's, is compared like an invoice — but the AI only ever corrects a cost from a tax invoice); **all four** when the AI couldn't pair the document (see the AI findings box for the reason; **Check with AI** retries) | For stock purchase lines the SKU tick and robot use the line's own SKU (the one a rep or the AI set on the purchase line), not the catalogue SKU. +The AI findings box also lists the AI's **reading notes** — what it noticed on the photo (a delivery note rather than an invoice, the year missing from the date, a rotated or partly covered page). + Hover a tick for the values compared (ours vs the document). A robot icon marks a SKU the AI filled. Click the document chip on a card to see the extracted lines next to the photo. diff --git a/src/components/collection-confirm/ai-findings.tsx b/src/components/collection-confirm/ai-findings.tsx index f5211b6..a548445 100644 --- a/src/components/collection-confirm/ai-findings.tsx +++ b/src/components/collection-confirm/ai-findings.tsx @@ -7,9 +7,12 @@ import { docPriceLabel, docUnitCost, roundCents } from "@/lib/collection-ai-tick const zar = new Intl.NumberFormat("en-ZA", { style: "currency", currency: "ZAR" }); -/** Box of document-level observations from the AI. Renders nothing when empty. */ -export function AiFindings({ findings }: { findings: string[] }) { - if (findings.length === 0) return null; +/** + * Box of document-level observations from the AI, plus its reading notes + * (what it noticed on the photo). Renders nothing when both are empty. + */ +export function AiFindings({ findings, notes = [] }: { findings: string[]; notes?: string[] }) { + if (findings.length === 0 && notes.length === 0) return null; return (
AI findings

- + {findings.length > 0 ? ( + + ) : null} + {notes.length > 0 ? ( +
+

Reading notes

+ +
+ ) : null}
); } diff --git a/src/components/collection-confirm/po-card-ai.test.tsx b/src/components/collection-confirm/po-card-ai.test.tsx index d802e97..fbf6375 100644 --- a/src/components/collection-confirm/po-card-ai.test.tsx +++ b/src/components/collection-confirm/po-card-ai.test.tsx @@ -100,6 +100,25 @@ describe("PoCard AI layer", () => { expect(screen.getByTestId("ai-findings")).toHaveTextContent("Freight not on PO"); }); + it("shows the AI's reading notes in the findings box even when there are no findings", () => { + const row = makeAiRow({ + ai_doc: { + read_id: "r", + doc_type: "delivery_note", + document_no: "2010/02893666", + doc_date: "2026-10-09", + supplier_name: "Plumblink", + findings: [], + notes: ["Year not printed on the document date"], + lines: [], + }, + }); + render(); + const box = screen.getByTestId("ai-findings"); + expect(box).toHaveTextContent("Reading notes"); + expect(box).toHaveTextContent("Year not printed on the document date"); + }); + it("shows a line's own findings (e.g. a pairing failure) in the findings box", () => { const row = makeAiRow({ ai_check: makeCheck({ diff --git a/src/components/collection-confirm/po-card.tsx b/src/components/collection-confirm/po-card.tsx index 6ad0f3e..fe143cd 100644 --- a/src/components/collection-confirm/po-card.tsx +++ b/src/components/collection-confirm/po-card.tsx @@ -16,6 +16,7 @@ import { import { cardDocument, cardFindings, + cardNotes, documentChipLabel, } from "@/lib/collection-ai-card"; import type { CollectionDocLine } from "@/lib/types"; @@ -204,6 +205,7 @@ export function PoCard({ const [docPanelOpen, setDocPanelOpen] = useState(false); const aiDoc = useMemo(() => cardDocument(rows), [rows]); const aiFindings = useMemo(() => cardFindings(rows), [rows]); + const aiNotes = useMemo(() => cardNotes(rows), [rows]); // Every line the AI read from the chip's document; lines paired with a row // on this card are marked "matched". Falls back to the paired lines alone // when the document's full line list is unavailable. @@ -890,7 +892,7 @@ export function PoCard({ )} - +