← Main Menu All manuals Operator Guide for this screen IM2

Create PO — Technical Spec

Create PO
Technical Spec Ver 1 Updated 2026-10-02 Matches the live screen

1. Files

app/po_create.py (router, /po prefix, mounted in im2.py after po_rel). templates/po_create.html. Screen key po_create is in screen_names and po_tile_screens (base.html). The chip is in _tiles.html po_tiles. The menu card is in its own row under Purchasing in menu.html.

2. Routes (all require action po_create; defaults admin/level1/level2)

MethodPathPurpose
GET/po/createscreen + last 10 rows of po_create_log
POST/po/create/parseJSON {text} → {header, lines, edits, unparsed}
GET/po/create/vendor-search, item-search, item/{sku}, job-search, job-classtypeaheads; job-class = ro_import.class_for_job('QB', id)
POST/po/create/submitvalidate → write one QB PurchaseOrder

3. Speech

Speech recognition runs in the browser (Web Speech API, Chrome/Edge, en-US, continuous). No audio reaches the server.

4. Parser

Deterministic: number words → digits; header keywords (vendor/supplier, date/issue date/dated, job/project/customer, class, memo/note); lines split at "next"/"then"/sentence/", <n>"/" and <n>". Line = qty, optional UOM word, price ("at/@/for $x", "total" ÷ qty), and the remaining text. Matching:

5. Write

Number from po_rel._next_po_number (shared 60000 series). The po_create_log row (ro DB, unique token) is inserted as Pending before the POST, then set to Created or Failed. A Created token returns the existing PO; a Pending token blocks a retry; a Failed token retries under the same number. Payload follows po_rel: APAccount 588, NotBillable, tax NON, ShipAddr from po_ship_to, PrivateNote = memo + tag. INV lines: ItemRef = items.qb_item_id, no ClassRef, CustomerRef only if the job_on_inventory box is ticked. NONINV lines: CustomerRef + ClassRef required. Not gated by allow_auto_po (Dave: straight to QB). QB PO lines reach qb_po_line through the normal PO sync.