diff --git a/src/components/collection-confirm/items-table-ai.test.tsx b/src/components/collection-confirm/items-table-ai.test.tsx index 460309e..0458a28 100644 --- a/src/components/collection-confirm/items-table-ai.test.tsx +++ b/src/components/collection-confirm/items-table-ai.test.tsx @@ -28,6 +28,17 @@ describe("ItemsTable AI layer", () => { expect(screen.queryByText(/add to pos/i)).not.toBeInTheDocument(); }); + it("shows only the POS column (no AI column, no AI min-width) when no row has ai_check", () => { + const { container } = render( + , + ); + const headers = screen.getAllByRole("columnheader").map((h) => h.textContent); + expect(headers).toEqual(["SKU", "Description", "Ord", "Coll", "Cost", "Surplus", "POS"]); + expect(container.querySelector("table")?.className).not.toContain("min-w-[860px]"); + expect(container.querySelectorAll("col")).toHaveLength(7); + expect(screen.getByText(/tap the pencil/i).closest("td")).toHaveAttribute("colspan", "7"); + }); + it("adds AI and POS headers when a row has ai_check", () => { render(); const headers = screen.getAllByRole("columnheader").map((h) => h.textContent); diff --git a/src/components/collection-confirm/items-table.tsx b/src/components/collection-confirm/items-table.tsx index 0e9ceed..f0c04e0 100644 --- a/src/components/collection-confirm/items-table.tsx +++ b/src/components/collection-confirm/items-table.tsx @@ -35,9 +35,10 @@ type Props = { /** "Add to POS" click for a line that is not in the POS yet. */ onAddToPos?: (rowId: string) => void; /** - * Force the AI + POS columns on or off. Defaults to on when some row - * carries an `ai_check` or a known `in_pos`, so a table with neither - * renders exactly as before. + * Force the AI + POS columns on or off. By default the AI column shows + * only when some row carries an `ai_check`, and the POS column when some + * row has a known `in_pos`, so a table with neither renders exactly as + * before. */ showAi?: boolean; }; @@ -178,8 +179,9 @@ export function ItemsTable({ onAddToPos, showAi, }: Props) { - const aiColumns = - showAi ?? rows.some((r) => !!r.ai_check || typeof r.in_pos === "boolean"); + const aiColumn = showAi ?? rows.some((r) => !!r.ai_check); + const posColumn = showAi ?? rows.some((r) => typeof r.in_pos === "boolean"); + const columnCount = 6 + (aiColumn ? 1 : 0) + (posColumn ? 1 : 0); const [edit, setEdit] = useState(null); const startCostEdit = (row: ConfirmRow) => { @@ -269,7 +271,9 @@ export function ItemsTable({ return ( {/* Explicit column widths. `table-fixed` honours these, so a cell @@ -291,8 +295,8 @@ export function ItemsTable({ - {aiColumns ? : null} - {aiColumns ? : null} + {aiColumn ? : null} + {posColumn ? : null} @@ -302,8 +306,8 @@ export function ItemsTable({ - {aiColumns ? : null} - {aiColumns ? : null} + {aiColumn ? : null} + {posColumn ? : null} @@ -494,12 +498,12 @@ export function ItemsTable({ - {aiColumns ? ( + {aiColumn ? ( ) : null} - {aiColumns ? ( + {posColumn ? (
Coll Cost SurplusAIPOSAIPOS
{surplus > 0 ? `+${surplus}` : "—"} {row.in_pos ? ( row.pos_stock_item_id ? ( @@ -540,7 +544,7 @@ export function ItemsTable({ */}
Tap the pencil to edit · Enter saves · Esc cancels diff --git a/src/lib/collection-ai-card.test.ts b/src/lib/collection-ai-card.test.ts index afe0763..39b74b5 100644 --- a/src/lib/collection-ai-card.test.ts +++ b/src/lib/collection-ai-card.test.ts @@ -72,21 +72,39 @@ describe("collection-ai-card", () => { expect(cardDocument([makeAiRow({ ai_doc: null })])).toBeNull(); }); - it("derives invoice defaults from the first row with a document number", () => { + it("derives invoice defaults from the card's (newest) tax invoice", () => { const rows = [ - makeAiRow({ id: "1", ai_check: null }), - makeAiRow({ id: "2", ai_check: makeCheck({ document_no: "5028256", doc_date: "2026-10-16" }) }), + makeAiRow({ id: "1", ai_check: null, ai_doc: null }), + makeAiRow({ id: "2", ai_doc: doc("5028256", [], "2026-10-16") }), ]; expect(aiInvoiceDefaults(rows)).toEqual({ number: "5028256", date: "2026-10-16" }); }); + it("uses the same newest document as the chip", () => { + const rows = [ + makeAiRow({ id: "1", ai_doc: doc("OLD-1", [], "2026-10-10") }), + makeAiRow({ id: "2", ai_doc: doc("NEW-2", [], "2026-10-16") }), + ]; + expect(aiInvoiceDefaults(rows)).toEqual({ number: "NEW-2", date: "2026-10-16" }); + }); + + it("never pre-fills from a delivery note", () => { + const dn = { ...doc("DN-7", [], "2026-10-16"), doc_type: "delivery_note" as const }; + const rows = [ + makeAiRow({ id: "1", ai_doc: doc("INV-1", [], "2026-10-10") }), + makeAiRow({ id: "2", ai_doc: dn }), + ]; + // The chip shows the newer delivery note, so nothing is pre-filled. + expect(aiInvoiceDefaults(rows)).toBeUndefined(); + }); + it("returns undefined without any document number", () => { - expect(aiInvoiceDefaults([makeAiRow({ ai_check: null })])).toBeUndefined(); - expect(aiInvoiceDefaults([makeAiRow({ ai_check: makeCheck({ document_no: "" }) })])).toBeUndefined(); + expect(aiInvoiceDefaults([makeAiRow({ ai_check: null, ai_doc: null })])).toBeUndefined(); + expect(aiInvoiceDefaults([makeAiRow({ ai_doc: doc("", []) })])).toBeUndefined(); }); it("omits an invalid date", () => { - const rows = [makeAiRow({ ai_check: makeCheck({ doc_date: "" }) })]; + const rows = [makeAiRow({ ai_doc: doc("5028256", [], "") })]; expect(aiInvoiceDefaults(rows)).toEqual({ number: "5028256" }); }); }); diff --git a/src/lib/collection-ai-card.ts b/src/lib/collection-ai-card.ts index da9a1ac..251a029 100644 --- a/src/lib/collection-ai-card.ts +++ b/src/lib/collection-ai-card.ts @@ -41,17 +41,20 @@ export function cardDocument(rows: ConfirmRow[]): AiDoc | null { return best; } -/** Pre-fill for the confirm dialog from the first row whose check has a document number. */ +/** + * Pre-fill for the confirm dialog: the number and date of the card's + * document (the same newest document the chip shows), only when it is a + * tax invoice — a delivery note's number is not the invoice number. + */ export function aiInvoiceDefaults( rows: ConfirmRow[], ): { number: string; date?: string } | undefined { - for (const row of rows) { - const number = row.ai_check?.document_no?.trim(); - if (!number) continue; - const date = row.ai_check?.doc_date ?? ""; - return /^\d{4}-\d{2}-\d{2}$/.test(date) ? { number, date } : { number }; - } - return undefined; + const doc = cardDocument(rows); + if (!doc || doc.doc_type !== "tax_invoice") return undefined; + const number = (doc.document_no ?? "").trim(); + if (!number) return undefined; + const date = doc.doc_date ?? ""; + return /^\d{4}-\d{2}-\d{2}$/.test(date) ? { number, date } : { number }; } /** Toast for an Add to POS response: plain success, or the counts when any row didn't go in. */