Control Utils
Intended Audience:
Technical User
Authors:
Holger Lierse, Kirill Gaiduk
Changed on:
24 Aug 2026
Overview
`ControlUtils` is the entry point of the Controls Utilities bundle. This page is the API reference for applying controls to a position from a rule.For the underlying concepts (control, control group, bulk vs position-level control) see Controls Utilities Overview. For the order in which the `ControlUtils` resolves and applies controls, and the behavior of the caches, see the Detailed Technical Description on the Controls Utilities package page.Key points
- Specificity-aware: position/product/variant-level controls take precedence over group-level (bulk) controls
- Auditable:
`ControlUtils`records every applied control with a before/after snapshot - Extensible: the position source and the set of control functions are both parameters you can supply
Applying Controls to a Position
`applyControls(context, inventoryCatalogueRef, inventoryPositionRef)`
The convenience overload. Loads the position with the default position supplier and applies the default set of control functions. Use this when the position maps one-to-one to the triggering event.`applyControls(context, positionSupplier, controlFunctions)`
Applies the given control functions to the position produced by `positionSupplier`. Use this to control where the position comes from (for example, an aggregate across locations) and which control functions run.`applyControls(context, positionSupplier, controlFunctions, defaultControls)`
Like the previous overload, but the `ControlUtils` adds `defaultControls` to the loaded controls where a control of that type is not already present. Use this to guarantee a baseline of behavior when no matching control exists.`applyControlsWithDefaultBehavior(context, positionSupplier, controlFunctions)`
A shorthand for the overload above that supplies `ControlTypes.DEFAULT_THRESHOLD_CONTROL_ACTIVE` as the default control, so a position with no matching threshold control defaults to `ACTIVE`.Position Suppliers
A position supplier is a`Supplier<Position>` that tells `applyControls` which position to operate on. `ControlUtils` provides two.`defaultPositionSupplier(context, inventoryCatalogueRef, inventoryPositionRef)`
Loads a single inventory position and enriches it with the standard related product and location information.`aggregatePositionSupplier(...)`
Produces a single position whose `quantity` is the sum of on-hand across multiple locations, for a product. `ControlUtils` provides three variants:`aggregatePositionSupplier(context, inventoryCatalogueRef, productRef, activeStatuses)`
aggregates the positions passed to it, counting only those whose status is in`activeStatuses`.`aggregatePositionSupplier(context, inventoryCatalogueRef, productRef, networkRef, activeStatuses)`
aggregates across every location in the given network.`aggregatePositionSupplier(context, inventoryCatalogueRef, productRef, locationSupplier, activeStatuses)`
aggregates across the locations returned by a custom`locationSupplier`.
`locationsByNetworkSupplier(context, networkRef)`
Returns a `Supplier<List<LocationReference>>` of the locations in a network. Pass it to the `locationSupplier` variant of `aggregatePositionSupplier` when you want to aggregate over a network but supply the locations yourself.Supplying Custom Control Functions
The control functions passed to`applyControls` determine which control types `ControlUtils` recognizes and how each applies. `ControlTypes.buildControlFunctions()` returns the standard set; pass your own list to add or override behavior. The example below assumes you have statically imported the relevant members of `ControlTypes` (`ControlFunction`, `CONTROL_FUNCTION_*`, `appliesToPosition`, `EXCLUSION_TYPE`):The Result: `PositionUpdateResult`
Every overload returns a `PositionUpdateResult`:`getPosition()`- the updated position (`status`and`quantity`after all controls were applied).`getPositionBefore()`- the original position, before any control was applied.`getAudit()`- an ordered list of`PositionUpdate`entries, one per applied control.`getMessage()`- a human-readable summary, for example`"2 controls were applied"`.
`PositionUpdate` in the audit exposes `getBefore()`, `getAfter()` and `getControl()`, giving the position on either side of that single control and the control that applied the change.