Item Buying Detail
Item Buying Detail — technical
sku_detail() in app/po.py. Recomputes the full build_workbench_rows() working set and picks the one row matching row_key == sku (accepting either the raw SKU or a N:-prefixed non-inventory key — see the Workbench tech doc's Grouping section). Read-only: this route makes no writes. 404s if the SKU/description currently has neither open demand nor a below-min condition — it is a drill-down from the Workbench grid, not a general item lookup.
Screen key po_sku; the banner reads SKU Detail (base.html's screen_names).
Demand / supply / buy-list drill-down [P2, 2026-09-06]
GET /po/workbench/{sku}/demand, .../supply and .../buylists are the same three JSON endpoints the Workbench grid's row-expand uses, fetched client-side here (Promise.all) rather than server-rendered, and rendered with base.html's shared renderDemandTable() / renderSupplyTable() / renderBuyListsTable() helpers so the inline and full-page drill-downs cannot diverge. wireRushToggles() attaches the per-RO Set Rush / Clear Rush buttons when the demand payload's can_set_rush is true (POST /ro/{order_no}/priority, admin/level1) — the only write reachable from this screen. The supply panel also includes open qb_po_line rows with no matching ro_po_link.
Header stats
row comes straight from build_workbench_rows(), so the header shows SKU, description, UOM, line type, OH, Min/Max, On PO, Qty on Buy Lists, Req Qty and Priority (a RUSH chip plus rush_age when priority == 'R'). The buy-form strip below it is display-only: Qty to Order, unloaded cost, delivery date and extended cost are plain text, and the single vendor <input> is a spelling-check box wired to the vendorList datalist that posts nowhere.
On hand / bin(s)
Known gap, confirmed as-is (Viktor, 2026-09-04): items has only primary_bin / secondary_bin (single text fields), not a per-bin quantity breakdown — no bin-level quantity table exists anywhere in the package. The field is labelled "On hand / bin(s)", showing the item's one qty_on_hand total alongside whichever of primary_bin/secondary_bin are set (row["bins"], built in build_workbench_rows()) — deliberately not framed as a per-bin split, since there's no data to split by. No further build needed unless a bin-quantity table shows up elsewhere.
PO lines received — est. date from sync (last 5)
Known gap, confirmed as-is (Viktor, 2026-09-04): there is no receipts table (purchasing_workbench_spec section 4: "Item Receipts have no API"). This panel proxies it from ro_po_link rows with qty_received > 0 for the SKU, ordered by updated_at (the QB-poll sync timestamp). The heading and the "Est. Received (sync date)" column explicitly label that date as an estimate — a sync timestamp, not a real receipt date — so it can't be misread as authoritative.
Shared table sort (2026-09-07)
Column sorting is one implementation in templates/base.html (Dave, 2026-09-07: "all screens that have tables like this need sorts on the appropriate columns"). A table opts in with class="sorttable"; every thead th becomes sortable except those with class="nosort"/class="toggle", an empty heading, or a checkbox in the heading. Client-side only, over the rows already rendered. Details: tech/table_sorting.md.