Purchase Order
Module: purchase_order. The commitment to a vendor, raised from an approved RFQ bid or straight from a requisition, approved through routing, printed on the client's template, and the trigger for expediting and goods receipt.
How this page was verified
Written from master on 2026-09-06 and compared with the big five the same day. No earlier page existed. A map, not a line-by-line trace: 33 files, about 580 database calls.
Where it sits
Requisition (spb_id) / RFQ bid (rfq_id, vendor_prop_quo_id) → Purchase Order
→ Expediting (expedite, milestones) → Goods Received Report (mrr) → invoicesThe data
| Table | Holds |
|---|---|
ts_purchase_order | the header. Identity: po_no, po_title, po_desc, po_date, revision, project_id, category_id. Sources: spb_id, rfq_id, vendor_prop_quo_id, so_id, ref_number, doc_ref. Vendor: vendor_id, vendor_contact_id, vendor_reference, contact, phone. Commercial: currency_id, tax, discount, freight_and_handling, insurance, other_charges, documentation, fob_charges, comission, total, payment_terms_id, invoicing_terms, condition_terms_*. Delivery: delivery_date, delivery_place, delivery_address, delivery_option, deliver_to_id, incoterms_id, mode_transport_id, packing_type_id, shipping_mark, origin_country, ex_factory_date, milestone_list. Contract: contract_id, agreement_type_code, effective_date. Approval: status_save, submit_approval, status_approval, fg_approval, person_prepared_by, person_approved_by, person_for_info. |
ts_purchase_order_item | the line items |
ts_file_reference | uploads and the generated PDF |
ts_procurement_documents, ts_map_procurement_doc_file, ts_procurement_doc_library | where the approved PDF is filed |
The screen
purchase_order.php with purchase_order_browse.htm: grid, a header form split into main, commercial and delivery tabs (each with its own post handler), an items grid, attachments (upload, select, import), a vendor and vendor-contact sub-register, print, export (CSV, matrix), move item up or down, and the routing form. Toolbar: New, Edit, Delete, Cancel, Print, Export, Help.
Numbering: increment_po, increment_po_a, increment_po_t per years, with proc_number_temp before save. A revision is a new header row for the same po_no; findPurchaseOrderByNumberAndRev() in the class resolves the pair.
Approval and what happens after
- Routing form (
purchase_order_handler_routing_form.phpand_routing_post.php, on$pdo): the user picks the vendor, the document reference (requisition or RFQ), the agreement type, attention and cc contacts, the preparer and the document date (theIR20___*fields), then submits. - Routing:
purchase_order_handler_post.phpposts with'rout_group_mod' => 'procurement'and setssubmit_approval = 1,status_approval = 0. The routing is an ordinary Document Routing entry withrouting_procure = 1. - On completion,
RoutingProcurementUccallspurchase_order.class.php, which implementsRoutingProcurementInterface:ProcessProcurement()updates the header;GenerateDocument()renders the PO throughpurchase_order_print_process.phpand the print flavour;StoreDocumentsToProcumentDocs()registers it in Procurement Documents under a per-PO folder;handlerExpediteModule()creates the expediting record and its milestone details frommilestone_list, so the PO appears in Material Expediting;NotificationProcurement()notifies.
Cancel (act=cancelPurchaseOrder, cancelpo) resets submit_approval and status_approval to 0.
Printing
The PO print layout is editable: template_po_updates.php and _json_template_po.php hold the box-and-grid JSON, the same mechanism as so_templates in inweb_config. Which flavour class renders it comes from procure_print_template_code. A discount variant exists in purchase_order_handler_print_browse_discount.inc.php.
What still runs on the legacy helper
Counted on 2026-09-06: 112 calls to iw_mysql_query() against 471 uses of $pdo, and 106 of the 112 are in purchase_order_handler_form_041214.php, a dated backup that is not routed. The live module is on $pdo except the multi-file upload (purchase_order_multiupload_upload.php, 4 legacy calls) and one call in the post handler. Of the four chain modules this is the one that was migrated.
Gotchas
- Two ways in. A PO can reference a requisition directly (
spb_id) or an approved bid (rfq_idplusvendor_prop_quo_id). Reports that count "POs from RFQs" miss the direct ones. - A revision is a new row. Queries by
po_noalone return every revision. - Expediting is created on approval, not on save. A PO that never completes routing never appears in Material Expediting.
- The multi-file upload is dead where the legacy helper throws; use the attachment select path.
Instance differences
Checked on 2026-09-06.
| Instance | Difference |
|---|---|
| JOTRE | Installed. Twelve files differ from master and one is added. The form, print, preview and routing post handlers push approved POs to Accurate (accurate_push_po.php and the sync crons). Carries a purchase_order.inc.php.bak_costcode leftover. |
| Jadestone, Medco, Timas | Not installed in their QA databases. Two or three files differ from master. |
Related
- RFQ and Requisition: the sources.
- Invoice: what should follow a PO, and why it does not run.
- Sign Off: the approval mechanics.