Workflow · Gi

Acumatica GI Mass Update Workflow

Acumatica GI Mass Update Workflow sits at the intersection of three forces: what the user wants to see, what the database can deliver, and what the platform will let you wire up.

John Kihiu12 min read

Generic Inquiries are read-only by design, which surprises people who have used a GI's filterable grid to find exactly the two hundred records they need to update and then go looking for a "mass update" button that does not exist on the GI screen itself. The mass-update workflow that actually works in Acumatica pairs a GI (for finding and scoping the records) with a separate processing mechanism (for changing them).

The read-only boundary is deliberate

A GI's result set is a projection over a BQL query, not a bound DAC view backed by a graph with save logic — there is no cache to persist to, no business logic to run, and critically no place for validation, events, or workflow transitions to fire. Even where the GI Designer lets you add action buttons, those actions invoke a target graph's methods; they are not the GI editing its own rows. Keeping this boundary is what keeps GI results trustworthy as read paths — if GIs could freely write, every report screen would also be a mutation risk surface.

GI to scope, processing screen to execute

The pattern I build for essentially every "select these two hundred and update them" requirement:

  1. Build the GI with whatever filters let the user precisely identify the target record set — this is the hard part, and it is exactly what GIs are good at.
  2. Build a small processing screen (a PXGraph derived from PXGraph<YourGraph, YourFilterDAC> using a processing-style data view, i.e. PXProcessing<TargetDAC>) whose selection query mirrors the GI's filter logic, or — more maintainably — that reuses the same underlying BQL/view definition the GI is built on so the two never drift apart.
  3. The processing screen presents the matching rows in a selectable grid with a real Process/Process All action, running through normal graph logic per row — so validation, events, and workflow transitions all fire exactly as if a user had edited each record by hand.
C# — MINIMAL MASS UPDATE GRAPH
public class MassCustomerCreditHold : PXGraph<MassCustomerCreditHold>
{
    public PXFilter<UpdateFilter> Filter;
    public PXProcessing<Customer> Records;

    protected virtual void Filter_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
    {
        Records.Cache.Clear();
        Records.View.RequestRefresh();
    }

    public IEnumerable records()
    {
        UpdateFilter f = Filter.Current;
        return SelectFrom<Customer>
            .Where<Customer.creditRating.IsEqual<CRCreditRating.poor>
                .And<Customer.statusID.IsNotEqual<CustomerStatus.onHold>>>
            .View.Select(this);
    }

    public PXAction<UpdateFilter> process;
    [PXButton, PXUIField(DisplayName = "Process")]
    protected virtual IEnumerable Process(PXAdapter adapter)
    {
        return Records.ProcessAll(customer =>
        {
            customer.StatusID = CustomerStatus.OnHold;
            Caches[typeof(Customer)].Update(customer);
        });
    }
}

Keeping the GI's filter and the processing screen's selection in sync

The recurring failure mode: a user filters the GI to 200 rows, is happy with the result, but the separately-built processing screen behind the "now update them" button uses a slightly different BQL condition and quietly processes 215 rows, some of which should not have qualified. Where possible, I derive both the GI's WHERE conditions and the processing graph's selection from one documented business rule, and I test them side by side — same filter inputs, compare row counts — before shipping. For anything touching money or status transitions, a mismatch here is not a cosmetic bug.

Always process through business logic, never through direct SQL

It is tempting, for a genuinely large mass update, to reach for a direct SQL UPDATE against the identified key set. Do not — that skips validation, numbering sequences, workflow state transitions, and anything the graph's event handlers would otherwise enforce, and it leaves no record in whatever audit mechanism depends on the graph's save path. Processing screens exist specifically so mass updates go through the same logic a manual edit would.

Wrapping up

GIs stay read-only by design; mass updates belong to a paired processing screen whose selection logic should be built from the same business rule as the GI's filters, not reimplemented separately. Route every mass update through normal graph save logic — never direct SQL — so validation and workflow transitions still apply at scale.

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.