Acumatica · Workflow

Acumatica Workflow — New Vendor Approval

Acumatica Workflow — New Vendor Approval — a complete, field-tested reference by John Kihiu, Acumatica developer in Nairobi.

John Kihiu12 min read

Acumatica Workflow — New Vendor Approval is one of the most common workflow customisations in Acumatica. Every business has a process that does not fit the standard approval map, and the workflow engine is the right place to model it. The trap is that the engine has a lot of moving parts — states, transitions, conditions, handlers, business events, approval groups — and the patterns are not always obvious. This guide walks through the canonical pattern for the scenario, then the variations you will see in the wild.

What the workflow needs to do

The workflow exists to enforce a process. The process has three things: a trigger (something happens), a decision (some condition is checked), and an action (a state change or a notification). The workflow engine implements all three.

Map it on paper first

Before you write any code, draw the state diagram. Each state is a node, each transition is an arrow, each arrow has a label (the condition) and a side effect (the action). If you cannot draw it on a single page, the workflow is too complex and should be split.

The states

For most approval workflows, the states are:

StateCodeMeaning
DraftDCreated but not submitted
Pending ApprovalPWaiting for the approver
ApprovedAApproval received
RejectedRApproval denied
ReleasedEPosted to the sub-ledger

Some workflows add a Held state (waiting for additional information) or split the approval into multiple sequential or parallel groups. The pattern is the same; just add the state and the transitions.

The transitions

Each transition has a source state, a target state, a condition, and a handler. The condition is the gate (who can do this); the handler is the work (what happens).

C# · WORKFLOW TRANSITION
[PXWorkflowDependsOnType(typeof(APInvoice))]
public class APInvoiceEntryWF : PXGraphExtension<APInvoiceEntry>
{
    public sealed class States : PX.Data.PXWorkflowStatusAttribute
    {
        public const string Draft = "D";
        public const string PendingApproval = "P";
        public const string Approved = "A";
        public const string Rejected = "R";
        public const string Released = "E";
    }
    public static class Conditions
    {
        public static bool RequiresManagerApproval(APInvoice doc)
            => doc?.CuryOrderTotal > 10000m;
    }
    public sealed class Handlers
    {
        [PXWorkflowHandler]
        public static IEnumerable<APInvoice> SubmitForApproval(
            PXGraph graph, APInvoice entity)
        {
            entity.Status = States.PendingApproval;
            yield return entity;
        }
    }
}

For the broader workflow patterns, see the workflow engine definitive guide.

Approval groups

For multi-approver scenarios, configure approval groups on the Employee screen first, then reference them in the workflow. The patterns:

PatternWhenConfiguration
Single approverManager signs offOne group, one approver
SequentialManager, then directorTwo groups, ordered
ParallelAll departments must sign offMultiple groups, AND logic
Threshold-basedUnder $5k auto, over $5k managerTwo workflows, condition-gated
Do not mix sequential and parallel

A workflow that goes through a sequential step and then branches into parallel groups is the most common source of "stuck approvals" tickets. Pick one pattern per workflow; do not mix.

For the parallel approval pattern specifically, see the parallel approvals guide.

Email notifications

A workflow that does not notify the next approver stalls. The pattern is Acumatica Business Events: configure the trigger (state change), the filter (only fire for this transition), and the subscriber (email, push, webhook).

CONFIG · BUSINESS EVENT
// Business Event setup
// Screen: APInvoice
// Event:  Status changes to PendingApproval
// Filter: CuryOrderTotal > 10000
// Subscriber: Email to employee with the approver role
}

For the full notification pattern, see the automated actions and emails guide.

Conditional assignment

Static approval maps are fine until your business has more than one rule. Dynamic assignment — "if amount > X, route to the CFO; if customer class is VIP, route to the relationship manager" — is what you actually need.

C# · DYNAMIC APPROVER
protected void _(Events.RowPersisting<APInvoice> e)
{
    var row = e.Row;
    if (row == null) return;
    if (row.CuryOrderTotal > 100000m)
        row.ApproverID = CfoEmployeeID;
    else if (row.CustomerClassID == "VIP")
        row.ApproverID = RelationshipManagerID;
    else
        row.ApproverID = DefaultManagerID;
}

For the full pattern, see the conditional assignment guide.

Testing the workflow

Workflows are deceptively hard to test because they involve time (the approver's response) and human judgment (the rejection reason). The minimum coverage:

  1. Submit a document that meets the condition. Verify it transitions to Pending Approval.
  2. Approve as the assigned approver. Verify it transitions to Approved.
  3. Reject as the assigned approver. Verify it transitions to Rejected and the reason is captured.
  4. Submit a document that does not meet the condition. Verify it auto-approves (or whatever the alternative is).
  5. Verify the email notifications fire.
C# · WORKFLOW TEST
[Test]
public void SubmitForApproval_TriggersTransition()
{
    var graph = PXGraph.CreateInstance<APInvoiceEntry>();
    var doc = new APInvoice { CuryOrderTotal = 50000m };
    graph.Document.Insert(doc);
    graph.Actions.PressSave();
    PXAutomation.GetStep<APInvoice>(graph, doc, "Submit", "PendingApproval").Invoke();
    var refreshed = (APInvoice)graph.Document.Search<APInvoice.refNbr>(doc.RefNbr);
    Assert.AreEqual("P", refreshed.Status);
}

For the full unit testing pattern, see the unit test framework guide.

Common pitfalls

The pitfalls I see most often, in order of frequency:

  1. Forgetting the initial state. A record that enters the workflow without a state gets stuck. Always set the status field to the initial state on insert.
  2. Mixing the condition and the handler. The condition is a one-liner; the handler is the work. If the condition does more than a boolean check, refactor.
  3. Not testing with restricted users. A workflow that exposes "approve" to a user with no approval rights is a leak. Test with restricted users.
  4. Hard-coded approver IDs. Approver IDs are tenant-specific. Use roles, not literal IDs.
  5. Forgetting to publish both the workflow and the graph. The workflow is part of the customisation package. Publish both as a unit.

For the upgrade survival playbook, see the customisation upgrade survival guide.

Wrapping up

The pattern is: state diagram on paper, states in code, transitions with conditions and handlers, approval groups configured, business events wired, tests written, restricted users verified. Do all six and the workflow is solid. Skip any one and you are debugging a stuck-approval ticket six months from now.