Workflow · Workflow

Acumatica Workflow — Credit Memo Approval

Acumatica Workflow — Credit Memo Approval is one of the most common workflow customisations in Acumatica. Every business has a process that does not fit the standard approval map,.

John Kihiu12 min read

Credit memo approval gets requested for a different reason than bill or PO approval: it's rarely about spend control, it's about revenue leakage control. A credit memo reduces what a customer owes, and unlike a bill or PO, there's no natural upstream check (a three-way match, a budget) keeping it honest — which is why clients almost always want tighter, more paranoid approval logic here than the amount alone would suggest. This post covers the AR-side specifics on screen AR301000, graph ARInvoiceEntry, document type CM.

Scope the condition to document type, always

ARInvoiceEntry handles invoices, credit memos, and debit memos through the same graph, distinguished by ARInvoice.DocType. A workflow extension added carelessly to this graph without a DocType condition will happily apply invoice-approval logic to credit memos and vice versa — I've inherited more than one client instance where "invoice approval" silently also gated credit memos because the original developer conditioned only on amount:

C#
graph.WithTransitions(transitions => transitions
    .AddGroupFrom<ARInvoice.status.Balanced>(g => g
        .Add(t => t
            .To<ARInvoice.status.PendingApproval>()
            .IsTriggeredOn(a => a.Actions.Release)
            .When(ARInvoice.docType.IsEqual(ARDocType.CreditMemo)
                  & ARInvoice.curyOrigDocAmt.IsGreaterEqual(0m)))  // any amount
        .Add(t => t
            .To<ARInvoice.status.Open>()
            .IsTriggeredOn(a => a.Actions.Release)
            .When(ARInvoice.docType.IsNotEqual(ARDocType.CreditMemo)))));

Notice the threshold above is effectively zero — many clients want every unapplied credit memo approved, not just large ones, because the abuse pattern they're worried about (an AR clerk writing off a friend's balance) doesn't correlate with amount the way discretionary spend does.

Linked versus unlinked: different risk profiles

A credit memo generated by a Return Material Authorization or linked to a specific original invoice via ARInvoice.OrigDocType/OrigRefNbr is materially lower risk than a standalone credit memo entered from scratch with no linkage — the former has a paper trail (a return, a documented dispute), the latter is much more discretionary. I split these into separate approval tiers the same way I'd split amount tiers:

C#
.When(ARInvoice.docType.IsEqual(ARDocType.CreditMemo)
      & ARInvoice.origRefNbr.IsNull())        // no linked source doc
      // -> higher scrutiny state, e.g. PendingApprovalUnlinked

Making a reason code mandatory before the transition is even reachable

Rather than relying on the approver to reject memos lacking justification, I make the reason code field required at the point of leaving Hold, before approval routing even triggers — using a standard PXDefault/PXUIField(Required = true) pair on the reason field scoped to DocType == CreditMemo, enforced in the graph rather than the workflow. The workflow's job is routing an already-valid document; validation that a field is populated belongs in the DAC extension or a RowPersisting handler, not smuggled into a .When() condition (which can't produce a user-facing validation message anyway — it can only silently fail to transition).

A blocked transition is not a validation error

If no outbound transition matches, the Release action does nothing and the user sees no error — the screen just doesn't move. Do not use "no matching transition" as your validation mechanism for required fields; users will file it as a bug, not read it as a rejection. Validate with a proper exception before the workflow ever gets a chance to evaluate.

Who actually approves a credit memo

Unlike bill approval (usually AP management) or PO approval (procurement/budget owners), credit memo approval assignment is often tied to whoever owns the customer relationship — the salesperson's manager, or a finance controller independent of sales specifically to avoid the conflict of interest of a rep approving their own customer's write-off. I've set the approval map's assignment rule to explicitly exclude the document's own SalesPersonID from eligible approvers where that conflict-of-interest concern was explicit in requirements — worth asking about directly rather than assuming a generic role-based approver is fine.

Wrapping up

Credit memo approval is a control problem more than a spend problem: scope conditions to DocType explicitly, treat linked and unlinked memos as different risk tiers, enforce reason codes as real validation rather than workflow-condition side effects, and think about approver conflict of interest when configuring the map. The threshold is often "always," which is the opposite instinct from PO or bill approval design.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.