Commit graph

8 commits

Author SHA1 Message Date
3eea87ec03 feat(collection-confirm): auto-push purple cards on to invoicing, with a 2-day log
After each AI tick, every Collection Confirm card the page shows purple
(cardAiState verified) is confirmed without a person. Customer lines go
to ready for invoicing with the invoice number and date the AI read; stock
orders go to stock booking once every line is collected. Cards with a
problem flag, a photo for another PO, or no readable invoice number/date
stay for review.

Each push is recorded in ai_settings.collection_auto_push_log and shown at
the top of the page for today and yesterday (PO, supplier, items, value).
Off by default behind a Settings > AI switch; needs the manual live step
npm run pb:migrate:collection-auto-push before it will run.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 11:36:23 +02:00
d3132ab7f6 feat(collection-confirm): collected stock orders go through Collection Confirm
The driver app records the full quantity as received when it collects a
stock pickup, and Collection Confirm only listed stock lines that were
not fully received — so collected stock orders skipped it and sat at
"sent", outside the accountant's booking queue, until someone clicked
Mark received (29 stuck on 2026-10-19).

- STOCK_ON_PAGE_FILTER / stockLineOnPage: a collected stock line stays on
  Collection Confirm until its stock order is received; cancelled orders
  never show. Shared by the list and the AI check (so those lines get
  photos read and ticks too).
- Confirm stock: markStockOrdersReceived flips each stock order to
  "received" once every line is collected/booked (→ booking queue);
  orders with lines still out stay open, reported as stillOpen. The
  route returns { updatedIds, received, stillOpen }; the toast says so.
- Stock photos: `npm run pb:migrate:stock-photos` makes
  stock_purchases.additional_attachments multi-file;
  addStockPurchaseAttachment, Move photo and Delete photo add/remove with
  `+`/`-` instead of replacing the single slot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:03:33 +02:00
e66ea11845 feat(collection-confirm): Delete photo; drop the Run agent scan button
- Delete photo next to "Add supplier invoice" removes the photo open in
  the previewer (wrong upload, or one of several for the same PO) after an
  inline "Delete …? Yes, delete" confirm; the confirm resets when you
  switch photos. Not offered for the PO PDF.
- POST /api/v1/collection-confirm/delete-photo (browser session) →
  deleteCollectionPhoto: takes the file off every order line carrying it
  (or the stock purchase's photo slot) and deletes the AI's reads of it
  plus the checks built on them (shared forgetReads with Move photo).
- Removed the header's blue "Run agent scan" button and its results panel
  (not in use); the /api/v1/agent/scan route stays for the agent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:26:10 +02:00
af4cdc66da feat(collection-confirm): spot a photo on the wrong PO and move it
Drivers photograph invoices per item and can't see which order a photo
lands on. B&R invoice 00282979 (stock order PO26100702STK) ended up on
the thinners line of PO202610017BLY; the AI read "PO26100702STK" off it
but the card only said "not found".

- The card list now carries each read's po_refs and source file, and sets
  ai_doc.other_po when the document names a PO that exists and isn't the
  row's PO (none named, or this card's PO among them: no hint).
- PO card: "Photo may be for <PO>" in the header; when open, "Invoice <no>
  is for <PO>, not this PO" with a Move photo button. Nothing moves on its
  own.
- POST /api/v1/collection-confirm/move-photo (browser session) →
  movePhotoToPo: copies the photo to the target (a collected line of a
  customer PO, or the stock purchase's single photo slot — refused when
  taken), removes it from the source, deletes the AI's read of it and the
  checks built on it so it is re-read where it now belongs.
- normalizePoReference moves to the client-safe src/lib/po-reference.ts
  (re-exported from the matching service).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:08:47 +02:00
802565d2d8 feat(collection-confirm): check printed prices on delivery notes; show AI reading notes
Plumblink hands out delivery notes with prices on them. The Price tick
was always grey on a delivery note, so a card could go purple without
its prices ever being checked, and the AI's reading notes ("delivery
note, not a tax invoice", "year not printed") were never shown.

- Price tick: compare whenever the document line has a price, invoice
  or delivery note; grey only when no price is printed. The AI still
  only corrects a cost from a tax invoice.
- ai_doc now carries the read's notes; cardNotes() unions them per card
  and the AI findings box lists them under "Reading notes" (the box now
  shows when there are notes but no findings).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:50:27 +02:00
d73fb6f0ab feat(collection-ai): read invoice discounts and set the discounted cost
HYCO (I009753) prints full prices on the lines and "Discount 25.00%" in
the totals; Swagelok (622831) has a "Disc %" column on each line. The AI
compared our cost (already the discounted price) with the printed price,
so the Price tick went red on both.

- The read now captures a line's discount_percent and a whole-document
  doc_discount_percent (prompt rule 5b) and stores net_unit_price on each
  line (both discounts stacked).
- The Price tick compares the cost with the price after discount; the
  tooltip and the document-lines panel spell it out
  ("R15.10 less 25% invoice discount = R11.33").
- Owner's call: when a "sure" tax-invoice line has a discount and our
  cost isn't the discounted price, the AI sets the cost to it (customer
  lines through updateOrderItemCost, which adds a cost note; stock lines
  through updateStockPurchaseItem) and records why in ai_check.cost_changed,
  shown in purple under the line. No discount, a delivery note or a
  "likely" match: the cost is never touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:18:21 +02:00
cba2d84549 docs(collection-ai): runbook tick table, audit scope; spec content_hash index is non-unique
F2: tick table (SKU green via the code match incl. AI fills, grey per tick,
pairing failure -> all grey, different product -> red), stock lines use the
line SKU, Add to POS needs a SKU, SKU fills audited for order lines only.
F3: content_hash is a non-unique index (identical uploads share a hash,
skipped PDFs have an empty hash) - matches the migration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 10:21:25 +02:00
8c3cfd45fc feat(collection-ai): settings section, runbook
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 09:55:44 +02:00