Wiki · Purchase order · MASTER · R593

Purchase order master (dispatcher)

The vendor side of the transaction. POs originate either from a Sales Order requiring drop ship (Path 1) or from an internal purchasing need (Path 2). Universal ★ automation alert fires to Finance after Item Receipt — receiving is at the dock but billing is Finance-owned.

R593 master 2-path dispatcher ★ Finance alert pending NS automation
What this is

2 paths · universal Finance handoff · PO# threading on Path 1

The Purchase Order is the vendor side of every GFS transaction. POs are used whenever the company buys product, ingredients, packaging, components, finished goods, or drop-ships from a partner vendor. Mike's actual process resolves to two categories:

The universal step is the ★ automation alert → Finance after Item Receipt. Receiving happens at the dock but billing is Finance-owned. Finance reviews PO + Item Receipt + supporting docs (packing slip, vendor invoice) before processing the Vendor Bill and paying per vendor terms.

Diagram: ns-purchase-order-master.html.

When to use it

Trigger conditions

★ Universal handoff

Every PO — on either path — fires the Finance alert after Item Receipt. Same event (events.po.finance_alert_fired). Same review/bill/pay/close pattern. Only the threading on the memo + sidecar customer cycle differ.

Worked example

Two POs in one week

Path 1 · Driscoll SO 1217 (PO# 72622)

Driscoll's SO includes 3 dropship lines via Cardinal Foods (vendor #891). PO-7833 created FROM SO 1217: createdfrom = 1217, memo = "72622", lineFields.links[].tranid = "1217 / 72622". Cardinal ships direct. Item Receipt closes PO line. ★ Finance alert fires. VendBill carries memo = "72622", tranid = "1217 / 72622", initialtranid = "1217 / 72622". Paid per Net 30. Customer-side cycle runs on the SO chain in parallel.

Path 2 · Bongards barrel cheddar replenishment

NJ Heartland inventory of Bongards barrel cheddar drops below 500 cases. PO-7910 entered: entity = 412 (Bongards Creameries), memo = "REQ-04472" (internal req#), createdfrom = NULL, location = NJ Heartland. Truck arrives day 10. Dock unloads, counts, condition-checks. Item Receipt completed. inventory_balance.quantityavailable += received qty at NJ Heartland. ★ Finance alert fires. VendBill entered with memo = "REQ-04472" (no customer PO# thread). Paid per Net 30.

Step-by-step what happens

Trigger → PO entry → transmit → classify → dispatch

  1. 01

    Trigger origin identified

    Either an SO needs drop ship (Path 1) OR an internal purchasing need is identified (Path 2).

  2. 02

    Enter PO in NetSuite

    NS PurchOrd with tranid, entity, memo, lines. Path 1 sets memo = customer_po_number and createdfrom = so.id; Path 2 leaves createdfrom = NULL and memo = internal req# / vendor invoice#.

    D1 mirror 2-min hot tier
  3. 03

    Transmit PO to vendor

    Manual email PDF today; STUB EDI 850 outbound.

  4. 04

    Vendor confirms order, pricing, delivery date

    Captured: order accepted, vendor cost locked, expected ship / delivery date, any subs / shortages flagged.

  5. 05

    Classify origin · dispatch sub-contract

    If createdfrom points at an SO → dispatch po_lifecycle_sales_order_connected_path. Else dispatch po_lifecycle_inventory_or_build_path.

  6. 06

    Sub-contract executes path-specific steps

    See path detail docs for field-level depth.

  7. 07

    Item Receipt (universal when applicable)

    Both paths converge here. Path 1 may skip on direct dropship; Path 2 always credits inventory at location_id.

  8. 08

    ★ Automation alert → Finance

    Universal handoff. Fires events.po.finance_alert_fired. STUB until NS workflow build.

  9. 09

    Finance review · Vendor Bill · pay per terms

    Finance reviews PO + Item Receipt + supporting docs. VendBill entered. Paid per vendor terms.

  10. 10

    Resolve issues · close PO

    Shortages, damages, substitutions, pricing reconciled. PO → 'Closed'. events.po.closed fires.

Outcomes

What's different after the cycle

PO
Closed
received + billed + paid
VendBill
Paid
per vendor terms
Path 1 thread
5 fields
customer PO# end-to-end
Path 2 inventory
Credited
at location
Failure modes

What can go wrong

PO sent, vendor never confirmed

Vendor outreach required; if no reply after window, cancel + alt-source.

Item Receipt missing after expected delivery

PO stalled. Vendor outreach with PO# (Path 1: include "<so.tranid> / <customer_po>" combo); investigate freight delay.

Receipt qty ≠ PO qty

Short ship or over-ship. Flag for Finance reconcile before VendBill processing.

Path 1 PO missing customer PO# thread on memo

Vendor cannot reference the customer order; downstream invoice reconciliation breaks. Patch purchase_orders.memoSO.otherrefnum; resync to NS.

Path 2 PO accidentally has createdfrom pointing at an SO

Misclassified — should be Path 1. Re-dispatch under the correct sub-contract.

Related

Adjacent flows + diagrams

For developers

Code paths + invariants

ConcernWhere
Master contractpurchase_order_lifecycle (risk 2)
Path 1 contractpo_lifecycle_sales_order_connected_path (risk 3)
Path 2 contractpo_lifecycle_inventory_or_build_path (risk 2)
SO ↔ PO link (Path 1)purchase_orders.createdfrom = transactions.id (type=SalesOrd)
VendBill ↔ PO linkvendor_bills.createdfrom = purchase_orders.id
Path 1 threading invariantPO.memo = SO.otherrefnum AND VendBill.memo = PO.memo
Path 2 no-SO-link invariantpurchase_orders.createdfrom IS NULL or parent ≠ SalesOrd
Finance alert eventevents.po.finance_alert_fired (STUB)
EDI 850 outboundSTUB — manual email today
// Master dispatcher: classify and route SELECT p.id, p.createdfrom, t.type FROM purchase_orders p LEFT JOIN transactions t ON p.createdfrom = t.id WHERE p.id = ? // path = (t.type = 'SalesOrd') ? 'sales_order_connected' : 'inventory_or_build'
Changelog

Dated trail

DateRoundChangeTouched by
2026-05-26R593Built PO master + 2 path-details matching SO pattern.Mike + Claude
Schema · data contract

The machine-readable spec

workflow_type · purchase_order_lifecycle · risk_level · 2.

Customer PO# threading (Path 1 only)

NS recordFieldSample value
Sales Order (origin)bodyFields.otherrefnum"72622"
Purchase OrderbodyFields.memo"72622"
Purchase OrderlineFields.links[].tranid"1217 / 72622"
Item Receiptinherits via NS std linkage from POtraces via createdfrom = po.id
Vendor BillbodyFields.memo"72622"
Vendor BillbodyFields.tranid"1217 / 72622"
Vendor BillbodyFields.initialtranid"1217 / 72622"
Path 2 caveat: Path 2 POs do not carry customer PO# threading. memo on PurchOrd + VendBill carries an internal req# or vendor invoice# instead. The threading invariant only applies on Path 1.

D1 tables touched (master + both paths)

TableOperation
purchase_ordersINSERT (header)
purchase_order_linesINSERT (per line)
item_receiptsINSERT (createdfrom = po.id)
inventory_balanceUPDATE (Path 2 credits qty at location)
vendor_billsINSERT (Path 1 carries thread on memo/tranid/initialtranid)
vendor_paymentsINSERT
transactionsUPDATE (status changes)
eventsINSERT (po.created · po.transmitted · po.finance_alert_fired · po.closed)
proposed_actionsINSERT (shortages, damages, subs HITL)
Runbook · when it breaks

It broke at 2am

Scenario · Vendor never confirmed PO

Transmitted but no acknowledgement.

  1. Check PO state: SELECT id, tranid, status, vendor_confirmed, expected_delivery FROM purchase_orders WHERE id=?
  2. Reach out to vendor: use PO tranid; Path 1 include "<so.tranid> / <customer_po>" combo.
  3. If no reply window exceeded: cancel PO; identify alt source; create replacement PO.

Scenario · Item Receipt missing after expected delivery

PO stalled.

  1. Check item receipts: SELECT COUNT(*) FROM item_receipts WHERE po_id=?
  2. Confirm physical arrival: dock team to verify nothing arrived without paperwork.
  3. Vendor outreach with tracking + ETA.
  4. Update purchase_orders.expected_delivery if vendor confirms new ETA; re-fire Finance alert event if needed.

Scenario · Misclassified Path 2 PO has SO link

Path 2 invariant violation.

  1. Verify: SELECT p.id, p.createdfrom, t.type FROM purchase_orders p LEFT JOIN transactions t ON p.createdfrom=t.id WHERE p.id=?
  2. If t.type = 'SalesOrd': this should be Path 1; re-dispatch po_lifecycle_sales_order_connected_path; backfill threading on memo from so.otherrefnum.

Logs to check

Backlog · open questions

What's not done