docs(dn): Inbox 3 matching screen design

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DEls 2026-10-26 13:25:54 +02:00
parent ca7d6c94e3
commit 841947a161

View file

@ -0,0 +1,190 @@
# Inbox 3 — delivery-note matching screen
Date: 2026-10-26 · Status: draft for approval
## Why
We need to know, for every purchase order, exactly what was delivered and how much. Today's
matching screen gets in the way:
- Two sources of suggestions disagree. The rule matcher (`match-po-item.ts`, the
`product_matched` check) and the AI allocation preview (`reconciliation_preview`) are both
shown, and they often contradict each other. On slip 0007075669 the AI matched all 7 lines
while the rule check said 6 matched "no PO line".
- The line picker (`ProductDecisions` in `document-detail-view.tsx`) lists every PO line
with no quantities, and lets you pick a PO line but not say how many arrived, in what unit,
or at what price.
- Units that differ between slip and PO (roll vs m, roll vs kg, 5 kg bag) cannot be
resolved on screen. The AI turned "2 rolls" into 60 m and flagged a huge excess.
- A slip stays on the screen as one block until every line is sorted, even when most lines
are plainly right.
## What it is
A new screen, **Inbox 3**, for the office to test on real delivery notes. The site keeps
using the current inbox until we are happy. Then we switch site over.
The capture flow does not change: someone takes a photo of the slip in the app and it comes
in. Inbox 3 changes what happens after that.
## How it behaves
1. **Auto-match first.** When a slip arrives, the system matches every line it is sure of.
Each line that passes all checks goes straight to **Ready to confirm**. Only lines that
still need help stay in Inbox 3.
2. **Slip-first table, one numbered row per slip line** (1, 2, 3…). Columns:
- **On the slip:** the description, plus the slip's own qty × price = amount.
- **Goes to PO line:** a searchable dropdown containing only this PO's lines (type "bail"
to narrow), plus "Not on this PO". It is pre-filled with the single best suggestion.
- **Received:** the quantity, editable.
- **Unit:** a text box with suggestions as you type (each, roll, m, m², m³, kg, 5 kg
bag, ton, length, box, pack). It is never limited to a list. When the unit differs from
the PO line's unit, a box appears: "1 roll = __ m on the PO". When it is filled in,
quantity, value and "left on PO" recalculate.
- **Price:** editable. It starts at the PO rate, with the slip's price shown beside it.
When they differ, the line is flagged and the user picks one or types their own.
- **Value:** received × price, ex VAT.
- **Left on PO:** ordered − (earlier receipts + this line), in PO units.
3. **Money totals** at the bottom: the value of the remaining lines, plus the whole slip ex
VAT against what the PO would charge for the same items.
4. **Slip and PO pictures on the right**: slip above, PO below, with the current line
highlighted where possible. On narrow screens, a switch between Both / Slip / PO.
5. **The assistant** is a text box beside the pictures. You talk to it by line number ("fix
line 5", "lines 3 and 4 are one item, 60 m total, per metre"). It can change anything on a
line: quantity, unit, unit conversion, price, which PO line, and combining several slip
lines into one PO line. It can only choose PO lines that are on this PO. It never posts.
The furthest it goes is Ready to confirm.
6. **Finished lines leave the screen.** When a line is complete (saved by the user, or fixed
by the assistant and passing checks), it moves to Ready to confirm. A banner says how many
lines have gone ("5 lines sent to Ready to confirm · show").
7. **Ready to confirm** groups the ready lines by slip. **Both site and office can confirm**
(David, 2026-10-26):
- In Inbox 3, admin and office users press Confirm.
- The same ready lines also appear in site's normal Ready to post, where the site manager
presses Confirm delivery as today.
Either one posts the ready lines of that slip, never the unresolved ones. Whoever confirms
first wins; the other sees the lines as posted. A slip is complete when all its lines are
posted.
This means the existing inbox's Ready to post and Confirm delivery must handle a slip where
only some lines are ready. They list and post just the ready lines, instead of requiring
the whole document to be ready (`deliveryReady` / `prepareDelivery` today). This is the
second deliberate change to the existing inbox.
## Goals
- One suggestion per line, from one source, with quantity, unit, price and value visible.
- Any slip line can be fixed in place, by hand or by asking the assistant.
- Lines move to Ready to confirm one at a time, as soon as they are right.
- Slip-vs-PO unit and price differences are resolved explicitly and remembered.
## Non-goals
- Redesigning the site's current inbox screen or the photo capture flow. Only two safety and
readiness changes reach it: the supplier guard, and posting only the ready lines.
- Agents (the assistant, Foreman, MCP tools) posting. Only a person presses Confirm: site
manager, admin or office user.
- New OCR or page-grouping work.
## Anti-goals (a failure even if it "works")
- The assistant links a line to anything that is not a line on this PO, or invents an item.
- A price or unit conversion is applied silently. Every change from the PO rate or PO unit
carries a reason and shows on the line.
- A line disappears from Inbox 3 without arriving in Ready to confirm.
- A slip is linked to a PO from a different supplier without being stopped. This happened
live: Chamberlain slips sat on Avidan and Raumix POs.
## Decided by David
- Slip-first layout (mockup A, then v2).
- Numbered lines; quantity, unit and price all editable; a money value on every line.
- Slip and PO pictures on the same screen.
- A searchable PO-line dropdown limited to this PO.
- An assistant with full edit rights on the lines, stopping at Ready to confirm.
- Completed lines move to Ready to confirm individually; only unresolved lines stay.
- Built as a separate Inbox 3, tested by us first, then rolled out to site.
- During the test, both site (from the normal Ready to post) and office (from Inbox 3) can
confirm ready lines.
- The price on each line is editable.
## Claude's calls (check these)
- **Who sees Inbox 3 during testing:** admin and office_user only, not site_user. This
needs a new role check, because financial pages currently let site managers in
(`access.ts`, `path-access.ts`).
- **Price default:** the PO rate. The slip price is shown alongside, and any difference
above R0.50 per unit or 1% flags the line.
- **The unit box** is free text plus suggestions. A "1 X = n PO-units" factor is required
when the unit differs from the PO's. The factor is remembered per supplier + product
(extends `remembered-match.ts`, which today refuses unit overrides).
- **Suggestions come from one source:** the AI allocation. The rule matcher stays as a
guard. If it finds a dimension conflict (e.g. 600 vs 1050 pipe), the AI suggestion is
shown as "check", not ready.
- **Line numbers** in the UI and assistant are 1-based and map to `lineIndex` (0-based).
- **Supplier guard:** a slip whose supplier does not match the PO's supplier is blocked with
a clear message, in Inbox 3 and the existing inbox. This is the one deliberate change to the
existing inbox: it is a safety check, not a screen change. Supplier aliases and merged
suppliers count as a match. The user can override from the line with a reason. The guard
applies whenever a note is re-checked, so existing wrong links show up too.
- **Auto-match ("sure of")** puts a line straight into Ready to confirm only when all of
these hold:
- the AI allocation and the rule guard agree on the PO line;
- `prepareLineBooking` passes;
- the unit equals the PO unit, or is converted by a remembered factor (the factor is shown
on the line);
- the price is within tolerance.
It runs where the AI preview runs today, on arrival. Queued notes are re-run once when
Inbox 3 ships.
- **Partial slips:** these use the existing per-line posting. The first posted line creates
the delivery note, the slip completes when all its lines are posted, and unposted lines
remain visible in both inboxes. Editing or reversing a posted line stays as today (correct
receipt). No new document state is added.
- **Memory:** only unit factors are remembered. Price differences are not; each one is
decided on its line.
- **Combined lines** are one row labelled with all their numbers ("3+4"). They are ready and
posted together, as one `kit`/`converted` allocation. Quantity and price are entered once,
in PO units.
- **Price tolerance:** a line is flagged if it differs from the PO rate by more than R0.50
per PO unit OR more than 1%, compared after unit conversion. Every change away from the PO
rate or PO unit needs a free-text reason. The assistant writes its own reason.
- **Assistant safety:** its edits go through the same validation as manual edits
(`prepareLineBooking`). Chat and changes are logged per note in `dn_review_events`, along
with who asked.
## Built on what exists
- The list model and tabs from `src/lib/inbox-two/model.ts` and `inbox-two-view.tsx`.
- The page viewer (`PageViewer`) and the two-column workspace from
`inbox-document-workspace.tsx`.
- The assistant: route `api/dn-batches/[id]/notes/[noteId]/assistant`, `review.ts`,
`review-schema.ts` and the MiniMax model. The schema already supports qty/unit `edits`,
`purchaseOrderItemId` and `kit` combining. It needs to add **price** (`netAmount` / unit
price, today forced to `usePoRate`) and a **unit factor** on converted lines. The server
must reject any `purchaseOrderItemId` that is not on the note's PO.
- Per-line validation and posting: `prepareLineBooking` (`line-booking.ts`) and
`postLineWithinLease` (`post-line.ts`). These already support per-line posting,
`unitOverride`, `netAmount` and `usePoRate`.
- Readiness: `deliveryReady` is whole-document today. Inbox 3 needs a **per-line ready
state**: a line that passes `prepareLineBooking` is "ready" even while other lines on the
same slip are not.
## Left to the builder
- How per-line ready state is stored (on the allocation or in a separate field), and how
the Ready to confirm view reads it.
- Highlighting the current line on the slip and PO images (best effort; there are no page
coordinates today).
- Whether Inbox 3 is a new route (`/dashboard/financial/delivery-notes/inbox-3`) or a mode
of the inbox-2 document page. A new route is preferred so site never sees it by accident.
- Exact styling, using the existing shadcn components.
## Success
- The 14 notes in today's queue can each be cleared in Inbox 3 without the old screen or
agent tools.
- No line can reach Ready to confirm with a PO line from another PO, an unexplained unit
change, or an unexplained price.
- After a week of office use, David decides whether to switch site over.