Fluent Commerce Logo
Docs
Essential knowledge

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.
1// applyControls (convenience)
2ControlUtils.PositionUpdateResult result =
3        ControlUtils.applyControls(context, inventoryCatalogueRef, inventoryPositionRef);
`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.
1// applyControls (custom supplier and functions)
2ControlUtils.PositionUpdateResult result = ControlUtils.applyControls(
3    context,
4    ControlUtils.defaultPositionSupplier(context, inventoryCatalogueRef, inventoryPositionRef),
5    ControlTypes.buildControlFunctions()
6);
`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`.
1// applyControlsWithDefaultBehavior
2ControlUtils.PositionUpdateResult result = ControlUtils.applyControlsWithDefaultBehavior(context,
3        ControlUtils.defaultPositionSupplier(context, inventoryCatalogueRef, inventoryPositionRef),
4        ImmutableList.of(ControlTypes.CONTROL_FUNCTION_THRESHOLD));

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`.
1// applyControls with an aggregate supplier
2ControlUtils.PositionUpdateResult result = ControlUtils.applyControls(context,
3    ControlUtils.aggregatePositionSupplier(
4        context, 
5        inventoryCatalogueRef, 
6        productRef, 
7        ImmutableList.of("ACTIVE")
8    ),
9    ControlTypes.buildControlFunctions()
10);
`locationsByNetworkSupplier(context, networkRef)`
Returns`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`):
1// applyControls with custom control functions
2ControlUtils.applyControls(context,
3    ControlUtils.defaultPositionSupplier(context, inventoryCatalogueRef, inventoryPositionRef),
4    ImmutableList.of(
5            CONTROL_FUNCTION_INCLUSION,
6            // Override the default EXCLUSION control function
7            new ControlFunction(20,
8                    (position, control) -> control.getType().endsWith(EXCLUSION_TYPE) && appliesToPosition(position, control),
9                    (position, control) -> position.update("INACTIVE").update(0)
10            ),
11            CONTROL_FUNCTION_BUFFER
12            // Optionally add more here
13    )
14);

The Result: `PositionUpdateResult`

Every overload returns`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"`.
Each `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.