Purchase order approval (screen PO301000, graph POOrderEntry) differs from bill approval in a way that surprises people who build one right after the other: a PO isn't a single-total document for approval purposes nearly as often as a bill is. Requisitioners want approval routed by department, by line-level GL account, or by the requesting employee's manager chain — not just a flat dollar threshold on the order header. This post covers the PO-specific patterns.
Different order types need different workflows
POOrder.OrderType covers Regular, Blanket, Drop-Ship, and a few others, and lumping them into one approval condition is the first mistake I see. A blanket PO might be a $200,000 annual commitment approved once by procurement leadership with individual releases against it needing no further sign-off; a drop-ship PO tied directly to a sales order often should skip discretionary approval entirely since the sale itself already justifies the spend. Scope your transition conditions on OrderType explicitly rather than assuming "PO approval" is one flow:
graph.WithTransitions(transitions => transitions
.AddGroupFrom<POOrder.status.Hold>(g => g
.Add(t => t
.To<POOrder.status.PendingApproval>()
.IsTriggeredOn(a => a.Actions.Release)
.When(POOrder.orderType.IsEqual(POOrderTypeList.RegularOrder)
& POOrder.orderTotal.IsGreaterEqual(2500m)))
.Add(t => t
.To<POOrder.status.Open>()
.IsTriggeredOn(a => a.Actions.Release)
.When(POOrder.orderType.IsEqual(POOrderTypeList.DropShip)
| POOrder.orderTotal.IsLess(2500m)))));
Routing by department or branch, not just amount
The requirement I build most often for POs specifically: route approval to the requesting department's budget owner, not a flat organizational hierarchy. That means the approval map assignment rule needs to resolve dynamically off the PO's own data — usually the BranchID or a custom DepartmentID field carried on the header, joined against an owner-lookup table. On the Assignment and Approval Maps screen (EP503010), the assignment rule type "By condition" lets you reference such a field directly, but for anything beyond a simple lookup (e.g. "the department head, or their delegate if currently on leave") I've had to add a small graph extension that resolves the actual approver into an unbound field the map rule reads, because the stock rule types don't do delegate-chasing.
If a single PO's lines post to different GL accounts or cost centers with different approval owners — common in project-heavy operations — header-level amount conditions can't express that. The honest fix is usually a business rule that requires single-department POs (split multi-department requisitions before they become one PO), because trying to model per-line approval inside a header-scoped workflow status fights the grain of the Workflow engine, which governs document state, not line state.
Interaction with vendor hold status
A PO for a vendor flagged Hold on the Vendors screen (AP303000) should never reach a clean approval state — Acumatica blocks this at the vendor level already, but I still see implementations where the workflow's approval transition fires before the vendor-hold check runs, producing a confusing "approved" PO that then fails at receipt. The fix is ordering: make sure any custom vendor-hold validation happens in the graph's persist pipeline ahead of, or independent from, the workflow transition — the workflow decides routing, it should not be the last line of defense for a data-integrity rule that belongs in a validation exception on Persist.
What "rejected" should actually do
When an approver rejects a PO, the default behavior returns it to Hold or Denied depending on your configuration — but requisitioners consistently expect the rejection reason to be visible without opening the approval history tab. I add a required comment on the reject action (via PXAction with a dialog, wired as an additional transition trigger out of PendingApproval back to Hold) and push it into the PO's Activities feed automatically, since "the PO got rejected and nobody knows why" is the single most common complaint I hear about PO approval once it's live.
Wrapping up
PO approval needs order-type-aware conditions, dynamic department-based assignment rather than static hierarchy, and rejection handling that actually communicates. The line-level GL complication is the one to flag early in requirements gathering — it's the case most likely to force a business-process change rather than a configuration change.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.