diff --git a/docs/handover-driver-invoice-photos.md b/docs/handover-driver-invoice-photos.md new file mode 100644 index 0000000..10e142c --- /dev/null +++ b/docs/handover-driver-invoice-photos.md @@ -0,0 +1,130 @@ +# Handover: driver invoice photos that were never collected + +Run every 30 minutes during the working day (06:00–17:00 SAST). + +> **Not scheduled yet.** No cron task runs this — the 5 live crons are the +> MCODe basket, three PocketBase backups and the n8n watchdog. Until one is +> created, someone has to run this by hand. + +## The problem + +Drivers photograph the supplier invoice on a PO in the driver app, but +sometimes never tap **Collect**. The line then stays waiting, so it +never reaches **Collection Confirm** and never gets invoiced. A new app +version (auto invoice match + "Collect these items?" prompt) should stop +this, but until it is proven, check by hand. + +Sometimes the photo is also on the **wrong PO** (e.g. the Metabo invoice +was uploaded on the Mega Lube PO), or is not an invoice at all. + +Two sides to check — they are different collections with different +attachment fields: + +| Side | Line lives in | Waiting statuses | Photo lives in | +|---|---|---|---| +| Customer PO | `order_items` | `collection_pool`, `assigned`, `ready_delivery` | `order_items.order_item_attachements` | +| Stock PO | `stock_purchase_items` | `collection_pool`, `assigned_to_driver` | `stock_purchases.additional_attachments` (**on the parent PO**) | + +All three customer waiting statuses count. The "collection pool" tab group +is `["collection_pool", "assigned", "ready_delivery"]` and +`order_items_confirm_collected` accepts `collection_pool` **or** +`assigned` — a line stuck in any of them never reaches Collection Confirm. + +## The check + +### 1. Find the lines + +Customer lines — `order_items_list` with filter: + +``` +(item_status = "collection_pool" || item_status = "assigned" || item_status = "ready_delivery") && order_item_attachements:length > 0 +``` + +expand `purchase_order,supplier` — the PO number is +`expand.purchase_order.po_number`, it is not a field on the line itself. + +Stock lines — `stock_purchase_items_list` with filter: + +``` +status = "collection_pool" || status = "assigned_to_driver" +``` + +expand `purchase` — the PO number is `expand.purchase.purchase_number` +(looks like `PO26100606STK`, not `PO...MAS`), and the photos are in +`expand.purchase.additional_attachments`. + +### 2. Read every photo + +`order_item_attachements` is a **multi-file** field (up to 10), and stock +POs can have several pages (`..._p1_`, `..._p2_`). Open **each** filename: + +- customer line → `files_fetch`, collection `order_items`, the line id, the filename +- stock line → `files_fetch`, collection `stock_purchases`, the **parent PO** id, the filename + +If a photo cannot be read as an invoice, treat the whole line as +unreadable (below). + +### 3. Compare the invoice with the line + +- the PO number printed on the invoice (reference / customer order no.) + = the line's PO number +- the supplier on the invoice = the line's supplier +- the item matches the line's description +- the quantity on the invoice = the line's `quantity` +- the invoice is dated today or recently + +## What to do + +- **Everything matches** → mark it collected. Do **not** hand-roll this + with `order_items_update` + `order_items_update_status`; use the tool + that exists for it, because it validates eligibility, refuses to + over-collect, stamps the audit note and refuses rows that are already + past the pool: + - customer line → `order_items_confirm_collected` with + `{ item_ids: [...], actor: { id, name }, quantity_collected: { : } }` + - stock line → `stock_purchase_items_mark_collected` with + `{ id: , quantity_collected: }` + - `quantity_collected` is the qty to **add**, not the new total. Omit it + to collect the full remaining quantity. + - `actor.id` is a free-form string — use `mavis` / `Mavis` so the + `notes` feed shows who did it. + - Do every line on that PO that is on the invoice. +- **Invoice shows less than ordered** → do NOT mark it. Report it + (the driver must collect the short quantity on the item card). +- **Photo is for a different PO** → do NOT mark it. Report both PO + numbers so a person can move the photo to the right PO. +- **Photo is not an invoice** → do NOT mark it. Report it. +- **Can't read the photo / not sure** → do NOT mark it. Report it. + +Never cancel, delete, confirm, or change prices. Only ever mark a line +collected, and nothing else. + +## Report + +A short list: what you marked collected (supplier, PO, item, qty, +invoice number) and what needs a person (and why). If nothing was +found, say "nothing new". + +**Do not re-report what is already on the "Waiting on a person" list +below** — those lines stay in the waiting status until somebody moves +them, so every run would otherwise find them again and repeat the same +report 22 times a day. Add anything new to that list. + +## Waiting on a person + +- **NSS M24 × 160 hex bolt ×60, PO202610018MAS** (line + `890919xtp0i8zfp`, driver Joachim): the photo on it is NSS invoice + 5031768 for **PO202610080MAS** (M12 cap screws, already collected and + confirmed on 27 Oct). Wrong photo, so nothing proves the M24 bolts + were collected. Ask Joachim. +- **Mega Lube oil aerosol ×3, PO202610073MAS** (line `ganf24h10lyrzdl`, + driver Joachim): no Mega Lube invoice anywhere — the line has no + attachment at all, so the filter will not find it. Moved to 27 Oct. + Ask Joachim. +- **UPL UNBRAKO 1 1/2 × 7 allen caps ×34, PO202609005CEM** (line + `47it7cxyu27dmd5`): photo is on the line, but an operator bounced it + back to "NOT READY" on 26 Oct, so it is not a forgotten Collect. + Do not mark it. +- **NSS M6 × 30 CSK ×100, PO26100606STK** (stock line + `o9jtrr0wasxxq2g`): the photo on the PO is a picture of a laptop + keyboard, not an invoice. Needs a person to re-shoot it.