- Get Started
- Functionality
- Learning
- Extension
- Dev Tooling
- APIs
- Releases
Authors:
Kirill Gaiduk, Cille Schliebitz
Changed on:
3 Sept 2026
Author:
Kirill Gaiduk
Changed on:
1 Sept 2026
Authors:
Holger Lierse, Kirill Gaiduk
Changed on:
10 Sept 2026
`util-sourcing` library is a comprehensive collection of utility functions designed to minimize the overhead and complexity of writing sourcing logic in your Fluent Commerce rules.`SourcingUtils`): Orchestrates the sourcing process and provides helper methods to load a Sourcing Profile`SourcingContextUtils`): Loads and manages Sourcing Context `OrderUtils`): Performs order-specific operations such as fulfillment creation`LocationUtils`): Provides location-based helpers including distance calculations and caching`FulfilmentOptionsUtils`): Creates fulfillment plans with available quantity tracking and ETA calculation`createSourcingAudit` mutation1// Load the sourcing profile for the current context
2SourcingProfile sourcingProfile = SourcingUtils.loadSourcingProfile(context);1// Create sourcing context with unfulfilled order items
2SourcingContext sourcingContext = SourcingContextUtils.loadSourcingContext(
3 context,
4 SourcingUtils::getUnfulfilledItems
5);1// Enable Sourcing Audit capture for this run
2SourcingAuditRecorder auditRecorder = new DefaultSourcingAuditRecorder();
3
4// Find the best sourcing plan based on strategies
5SourcingPlan plan = SourcingUtils.findPlanBasedOnStrategies(
6 SourcingExecutionParameters.builder()
7 .context(context)
8 .sourcingContext(sourcingContext)
9 .profile(sourcingProfile)
10 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE)) // Consider only ACTIVE positions
11 .inventoryProcessor(this::customInventoryProcessor)
12 .auditRecorder(auditRecorder)
13 .build()
14);1// The system generates a sourcing plan that might look like:
2SourcingPlan optimalPlan = new SourcingPlan();
3optimalPlan.addFulfilment(
4 SourcingUtils.Fulfilment.builder()
5 .location(Location.builder().name("Manhattan Store").build())
6 .items(Arrays.asList(
7 Fulfilment.FulfilmentItem.builder().ref("2x Laptops").build(),
8 Fulfilment.FulfilmentItem.builder().ref("3x Mice").build())
9 )
10 .build()
11);
12optimalPlan.addFulfilment(
13 SourcingUtils.Fulfilment.builder()
14 .location(Location.builder().name("NJ Warehouse").build())
15 .items(Arrays.asList(
16 Fulfilment.FulfilmentItem.builder().ref("3x Mice").build())
17 )
18 .build()
19);1// Set fulfillment types
2OrderUtils.fillFulfilmentType(sourcingContext, fulfilments);
3
4// Create fulfillments from the plan
5List<Fulfilment> fulfilments = OrderUtils.createFulfilments(
6 context,
7 sourcingContext,
8 plan.getFulfilments()
9);1// Record the sourcing decision as a Sourcing Audit and submit it
2SourcingUtils.captureAudit(context, plan, sourcingProfile, auditRecorder, sourcingContext);`createSourcingAudit` for later reviewAuthors:
Holger Lierse, Kirill Gaiduk
Changed on:
10 Sept 2026
`SourcingUtils` class in the `util-sourcing` bundle is the main utility class that orchestrates the entire sourcing process within a rule. It provides core helper methods such as loading a sourcing profile, initializing the sourcing context, and executing the sourcing logic configured in the profile. Each stage supports multiple customization points. It can also capture a Sourcing Audit of the decision and submit it through the `createSourcingAudit` mutation.`getPlanFinder` provides a single entry point for primary and fallback sourcing, generating multiple ranked plans without reloading data`captureAudit``getPlanFinder()``SourcingPlanFinder` that exposes:`nextFullPlan()` for primary-strategy sourcing `nextFallbackPlan()` for fallback-strategy sourcing1SourcingExecutionParameters params = SourcingExecutionParameters.builder()
2 .context(context)
3 .sourcingContext(sourcingContext)
4 .profile(sourcingProfile)
5 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
6 .build();
7
8SourcingPlanFinder finder = SourcingUtils.getPlanFinder(params);
9
10// Primary sourcing: call multiple times to produce alternative
11// plans without reloading sourcing data
12SourcingPlan plan = finder.nextFullPlan();
13
14// Fallback sourcing from the same parameters object
15SourcingPlan fallbackPlan = finder.nextFallbackPlan();`findPlanBasedOnStrategies()``ChunkLoadingPlanFinder` that loads locations in incremental chunks sized proportionally to the order's item count. 1SourcingPlan plan = SourcingUtils.findPlanBasedOnStrategies(
2 SourcingExecutionParameters.builder()
3 .context(context)
4 .sourcingContext(sourcingContext)
5 .profile(profile)
6 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
7 .build()
8);`getBasedOnStrategiesPlanFinder()``SourcingPlanFinder` configured for primary sourcing strategies.`findPlanBasedOnStrategies(SourcingExecutionParameters)` is equivalent to `getBasedOnStrategiesPlanFinder(sourcingExecutionParameters).nextPlan()`.Use this when you need to call `findPlanForAllItems` multiple times without reloading sourcing data from scratch - for example, when generating a ranked list of fulfillment plans.1SourcingPlanFinder planFinder = SourcingUtils.getBasedOnStrategiesPlanFinder(
2 SourcingExecutionParameters.builder()
3 .context(context)
4 .sourcingContext(sourcingContext)
5 .profile(profile)
6 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
7 .build()
8);
9// Call nextPlan() for each attempt without reloading sourcing data
10SourcingPlan plan = planFinder.nextPlan();`findPlanBasedOnFallbackStrategies()`1SourcingPlan plan = SourcingUtils.findPlanBasedOnFallbackStrategies(
2 SourcingExecutionParameters.builder()
3 .context(context)
4 .sourcingContext(sourcingContext)
5 .profile(profile)
6 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
7 .build()
8);`getBasedOnFallbackStrategiesPlanFinder()``SourcingPlanFinder` configured for fallback sourcing strategies.`findPlanBasedOnFallbackStrategies(SourcingExecutionParameters)` is equivalent to `getBasedOnFallbackStrategiesPlanFinder(sourcingExecutionParameters).nextPlan()`.Wrap the returned finder (for example, for multi-attempt location exclusion) before calling `findPartialFulfilmentPlan` in a loop.1SourcingPlanFinder fallbackFinder = SourcingUtils.getBasedOnFallbackStrategiesPlanFinder(
2 SourcingExecutionParameters.builder()
3 .context(context)
4 .sourcingContext(sourcingContext)
5 .profile(profile)
6 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
7 .build()
8);
9// Wrap finder for multi-attempt location exclusion, then call nextPlan()
10SourcingPlan partialPlan = fallbackFinder.nextPlan();`buildRejectedFulfilment()`1// Build system rejected fulfillment for unfulfillable items
2Fulfilment rejectedFulfilment = SourcingUtils.buildRejectedFulfilment(
3 context,
4 sourcingContext,
5 context.getProp(PROP_SYSTEM_REJECTED_LOC_REF)
6);`captureAudit()``createSourcingAudit` mutation.Pass the `sourcingContext` so the audit is recorded against the sourced entity, for example it supplies the Fulfillment Choice id and reference stored on the audit.`DefaultSourcingAuditRecorder` through `SourcingExecutionParameters.auditRecorder(...)`; when no recorder is supplied the call is a no-op.`DefaultSourcingAuditRecorder` captures the decision during plan-finding and posts the audit. Create a new instance per rule invocation; it is stateful, so never share it across rules or store it on a rule field`NoOpSourcingAuditRecorder` is the default when `auditRecorder` is not set. It ignores every capture call, so an un-instrumented sourcing path pays no cost1final SourcingAuditRecorder auditRecorder = new DefaultSourcingAuditRecorder();
2
3SourcingPlan plan = SourcingUtils.getPlanFinder(
4 SourcingExecutionParameters.builder()
5 .context(context)
6 .sourcingContext(sourcingContext)
7 .profile(sourcingProfile)
8 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
9 .auditRecorder(auditRecorder)
10 .build()
11).nextFullPlan();
12
13if (plan.getFulfilments() != null) {
14 OrderUtils.fillFulfilmentType(sourcingContext, plan.getFulfilments());
15 OrderUtils.createFulfilments(context, sourcingContext, plan.getFulfilments());
16}
17
18// Stamps the profile onto the audit and queues the createSourcingAudit mutation
19SourcingUtils.captureAudit(context, plan, sourcingProfile, auditRecorder, sourcingContext);`findPlanForAllItems()``findPlanBasedOnStrategies` method to identify a plan for an order based on the sourcing strategies. It ranks candidate locations using the provided sourcing criteria, and searches for the best combination of locations that can cover the full order within the allowed split limit. Fewer-location plans are always preferred.Before entering permutation search, an early availability check sums available quantities for each required item across all candidate locations. If any item cannot be covered, permutation search is skipped. If no valid combination exists, it returns an empty plan.1String networkRef = SourcingUtils.getNetworkRef(sourcingProfile, strategy);
2String virtualCatalogueRef = SourcingUtils.getVirtualCatalogueRef(sourcingProfile, strategy);
3Integer maxSplit = SourcingUtils.getMaxSplit(sourcingProfile, strategy);
4List<Location> locations = LocationUtils.getLocationsInNetwork(context, networkRef);
5
6SourcingPlan plan = SourcingUtils.findPlanForAllItems(
7 SourcingExecutionParameters.builder()
8 .context(context)
9 .sourcingContext(sourcingContext)
10 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
11 .build(),
12 virtualCatalogueRef,
13 locations,
14 sourcingCriteria,
15 maxSplit
16);`findHighestValuePartialFulfilment()``findPlanBasedOnFallbackStrategies` method to find the highest-value partial fulfillment. It filters out excluded locations, compares each candidate's rating based on the remaining unfulfilled items at that iteration, and checks whether the location can cover at least part of the remaining items. The method returns the best fulfillment found or none if no positive-value option exists.1Set<String> excludedLocations = Set.of("warehouse-001", "store-002");
2Optional<Fulfilment> partialFulfilmentOpt = SourcingUtils.findHighestValuePartialFulfilment(
3 locationAndPositions,
4 unfulfilledItems,
5 excludedLocations
6);
7
8if (partialFulfilmentOpt.isPresent()) {
9 Fulfilment partialFulfilment = partialFulfilmentOpt.get();
10
11 // Calculate remaining items after partial fulfillment
12 List<OrderItem> remainingItems = OrderUtils.itemsMinusFulfilments(
13 unfulfilledItems,
14 Arrays.asList(partialFulfilment)
15 );
16
17 // Create the partial fulfillment
18 OrderUtils.fillFulfilmentType(sourcingContext, Arrays.asList(partialFulfilment));
19 OrderUtils.createFulfilments(context, sourcingContext, Arrays.asList(partialFulfilment));
20
21 context.action().log("Created partial fulfillment with {} items",
22 partialFulfilment.getItems().size());
23}`findPartialFulfilmentPlan()``findHighestValuePartialFulfilment` until the `maxSplit` limit is reached or all unfulfilled items are covered. Location ratings are recalculated after each allocation iteration.Use `getBasedOnFallbackStrategiesPlanFinder` to obtain a pre-loaded `SourcingPlanFinder`, then wrap it (for example, for multi-attempt location exclusion) before calling `findPartialFulfilmentPlan` in a loop.1SourcingPlanFinder fallbackFinder = SourcingUtils.getBasedOnFallbackStrategiesPlanFinder(
2 SourcingExecutionParameters.builder()
3 .context(context)
4 .sourcingContext(sourcingContext)
5 .profile(profile)
6 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
7 .build()
8);
9SourcingPlan partialPlan = SourcingUtils.findPartialFulfilmentPlan(
10 sourcingContext,
11 fallbackStrategy,
12 unfulfilledItems,
13 locationsWithPositions,
14 criteria,
15 locationLimit,
16 maxSplit
17);`loadPositions()``findPlanForAllItems` and `findPlanBasedOnFallbackStrategies`) to load inventory.1List<LocationAndPositions> locationAndPositions = SourcingUtils.loadPositions(
2 SourcingExecutionParameters.builder()
3 .context(context)
4 .sourcingContext(sourcingContext)
5 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
6 .build(),
7 sourcingCriteria,
8 virtualCatalogueRef,
9 locations
10);`loadSourcingProfile()`1SourcingProfile profile = SourcingUtils.loadSourcingProfile(context);
2if (profile != null) {
3 SourcingPlan plan = SourcingUtils.findPlanBasedOnStrategies(
4 SourcingExecutionParameters.builder()
5 .context(context)
6 .sourcingContext(sourcingContext)
7 .profile(profile)
8 .positionStatuses(ImmutableList.of(Constants.Status.ACTIVE))
9 .build()
10 );
11}`getUnfulfilledItems()`1List<OrderItem> unfulfilledItems = SourcingUtils.getUnfulfilledItems(sourcingContext);`getNetworkRef()`1String networkRef = SourcingUtils.getNetworkRef(profile, strategy);`getVirtualCatalogueRef()`1String catalogueRef = SourcingUtils.getVirtualCatalogueRef(profile, strategy);`getMaxSplit()`1Integer maxSplit = SourcingUtils.getMaxSplit(profile, strategy);`getSourcingPlanAudit()``SourcingPlanAudit` attached to a plan. It is always non-null and carries the full decision: the overall status (`FULLY_SOURCED`, `PARTIALLY_SOURCED`, or `NOT_SOURCED`), the sourcing type (`PRIMARY` or `FALLBACK`), the evaluated strategies, the applied Sourcing Profile, the requested Items, and the considered location count.1SourcingPlanAudit audit = plan.getSourcingPlanAudit();
2String status = audit.getStatus(); // FULLY_SOURCED / PARTIALLY_SOURCED / NOT_SOURCED
3String type = audit.getType(); // PRIMARY / FALLBACK
4List<SourcingAuditStrategy> strategies = audit.getStrategies();
5SourcingProfile profile = audit.getSourcingProfile();Authors:
Kirill Gaiduk, Alexey Kaminskiy
Changed on:
10 Sept 2026
`createSourcingAudit` mutation (write) and the `sourcingAudits` query (read) `SOURCINGAUDIT_CREATE` for the mutation, `SOURCINGAUDIT_VIEW` for the query, and `SOURCINGPROFILE_VIEW` to resolve the Sourcing Profile on a returned record`cursor` pagination; the default page size is 10 and each `cursor` is an opaque Base64 pagination token`items` list by 0-based index: `missingItemQuantities` (per Location) and `itemQuantities` (per Fulfillment) each carry one entry per Item`createSourcingAudit` mutation`sourcingAudits` query`ORDER` request, the records for the Order and all its Fulfillment Choices| Entity | Description |
`SourcingAudit` |
|
`SourcingAuditItem` |
|
`SourcingAuditStrategy` | The evaluation detail for one Sourcing Strategy considered during the request:
|
`SourcingAuditStrategyLocation` |
|
`SourcingAuditStrategyFulfilment` | A Fulfillment produced by the successful Strategy:
|
`SourcingAuditConnection` / `SourcingAuditEdge` |
|
| Relationship | Type | Description |
| Connection to Edges | One `SourcingAuditConnection` to many `SourcingAuditEdge` |
|
| Edge to Audit | One `SourcingAuditEdge` to one `SourcingAudit` | Each edge wraps a single `SourcingAudit` in its `node`, with an opaque `cursor` used for pagination |
| Audit to Items | One `SourcingAudit` to many `SourcingAuditItem` |
|
| Audit to Strategies | One `SourcingAudit` to many `SourcingAuditStrategy` | The Strategies considered during evaluation, held in priority (execution) order |
| Audit to Profile | One `SourcingAudit` to one `SourcingProfile` |
|
| Strategy to Locations | One `SourcingAuditStrategy` to many `SourcingAuditStrategyLocation` |
|
| Strategy to Fulfillments | One `SourcingAuditStrategy` to many `SourcingAuditStrategyFulfilment` | The Fulfillments the Strategy produced, each paired with the Location selected for it |
| Fulfillment to selected Location | One `SourcingAuditStrategyFulfilment` to one `SourcingAuditStrategyLocation` |
|
`conditions` and `criteria` fields use the `Json` scalar and hold compact, positional arrays. Their object shapes are:| Field | Shape (one entry per element) | Description |
`conditions` (on `SourcingAuditStrategy`) | `{ "p": boolean, "a": value }` - one entry per Condition, in evaluation order |
|
`criteria` (on `SourcingAuditStrategyLocation`) | `{ "n": number, "a": value }` - one entry per Criterion, aligned to the Criteria on the corresponding Strategy |
|
`createSourcingAudit` mutation and the `sourcingAudits` query - each governed by its own permission. The mutation stores a record; the query returns the stored records for an entity.| Permission | Applies to | Purpose |
`SOURCINGAUDIT_CREATE` | `createSourcingAudit` mutation | Write a Sourcing Audit record |
`SOURCINGAUDIT_VIEW` | `sourcingAudits` query | Read Sourcing Audit records for an entity |
`SOURCINGPROFILE_VIEW` | `sourcingAudits` query |
|
`createSourcingAudit` writes a completed Sourcing Audit record. The Sourcing Rules call it at the end of a Sourcing Request; it is not part of a typical integration flow.`SOURCINGAUDIT_CREATE``CreateSourcingAuditInput!`1mutation createSourcingAudit($input: CreateSourcingAuditInput!) {
2 createSourcingAudit(input: $input) {
3 ref
4 entityType
5 entityId
6 entityRef
7 status
8 createdOn
9 }
10}1{
2 "input": {
3 "ref": "SA-000001",
4 "entityType": "FULFILMENT_CHOICE",
5 "entityId": "789012",
6 "entityRef": "ORD-100123-1",
7 "retailer": { "id": "1" },
8 "type": "FALLBACK",
9 "status": "PARTIALLY_SOURCED",
10 "profile": { "ref": "ANZ_DEFAULT", "version": 3 },
11 "locationCount": 2,
12 "items": [
13 { "orderItemRef": "OI-1", "productRef": "SKU-BEA-1042", "productName": "Hydra-Glow Vitamin C Serum 30ml", "quantity": 5 },
14 { "orderItemRef": "OI-2", "productRef": "SKU-FAS-7781", "productName": "Merino Wool Crew Knit - Charcoal (M)", "quantity": 3 },
15 { "orderItemRef": "OI-3", "productRef": "SKU-PHA-3305", "productName": "Paracetamol 500mg Tablets - 24 Pack", "quantity": 2 }
16 ],
17 "strategies": [
18 {
19 "strategyRef": "b8e7c1a0-4f2d-4c8e-9a1b-2f6d3e5c7a90",
20 "status": "SKIPPED",
21 "evaluatedOn": "2026-08-17T09:30:00Z",
22 "locationCount": 0,
23 "conditions": [ { "p": false, "a": "STANDARD" } ]
24 },
25 {
26 "strategyRef": "c3d9f2b1-5a7e-4b6c-8d0f-1e2a3b4c5d6e",
27 "status": "EVALUATED",
28 "evaluatedOn": "2026-08-17T09:30:00Z",
29 "locationCount": 2,
30 "conditions": [ { "p": true, "a": "NSW" } ],
31 "locations": [
32 { "locationRef": "SYD01", "locationName": "Sydney CBD", "criteria": [ { "n": 1, "a": 2.4 } ], "missingItemQuantities": [ 0, 2, 0 ] },
33 { "locationRef": "MEL01", "locationName": "Melbourne Central", "criteria": [ { "n": 0.61, "a": 713.4 } ], "missingItemQuantities": [ 0, 3, 0 ] }
34 ],
35 "fulfilments": [
36 {
37 "fulfilmentRef": "FUL-1",
38 "selectedLocationPosition": 0,
39 "location": { "locationRef": "SYD01", "locationName": "Sydney CBD", "criteria": [ { "n": 1, "a": 2.4 } ], "missingItemQuantities": [ 0, 2, 0 ] },
40 "itemQuantities": [ 5, 1, 2 ]
41 }
42 ]
43 }
44 ]
45 }
46}1{
2 "data": {
3 "createSourcingAudit": {
4 "ref": "SA-000001",
5 "entityType": "FULFILMENT_CHOICE",
6 "entityId": "789012",
7 "entityRef": "ORD-100123-1",
8 "status": "PARTIALLY_SOURCED",
9 "createdOn": "2026-08-17T09:30:00.000+00:00"
10 }
11 }
12}`sourcingAudits` retrieves the Sourcing Audit records for an Order or Fulfillment Choice. `SOURCINGAUDIT_VIEW` (plus `SOURCINGPROFILE_VIEW` to populate `profile`)`@complexityCost(value: 400)``SourcingAuditConnection`| Argument | Type | Required | Description |
`entityType` | `String!` | ✅ | The audited entity type:
|
`entityId` | `ID!` | ✅ | The audited entity identifier |
`first` | `Int` | ❌ |
|
`after` | `String` | ❌ | Cursor to page forward from |
`last` | `Int` | ❌ | Relay backward pagination - number of records before `before` |
`before` | `String` | ❌ | Cursor to page backward from |
1query sourcingAudits($entityType: String!, $entityId: ID!, $first: Int, $after: String) {
2 sourcingAudits(entityType: $entityType, entityId: $entityId, first: $first, after: $after) {
3 edges {
4 cursor
5 node {
6 ref
7 entityType
8 entityId
9 entityRef
10 type
11 status
12 createdOn
13 locationCount
14 profile { ref version }
15 items { orderItemRef productRef productName quantity }
16 strategies {
17 strategyRef
18 status
19 evaluatedOn
20 locationCount
21 conditions
22 locations { locationRef locationName criteria missingItemQuantities }
23 fulfilments { fulfilmentRef selectedLocationPosition itemQuantities }
24 }
25 }
26 }
27 pageInfo { hasNextPage hasPreviousPage }
28 }
29}1{
2 "entityType": "ORDER",
3 "entityId": "123456",
4 "first": 10
5}1{
2 "data": {
3 "sourcingAudits": {
4 "edges": [
5 {
6 "cursor": "Y3Vyc29yOi0tLTIwMjYtMDgtMTdUMDktMzAtMDEuMDAwWi1mYjAwMDAwMS5neg==",
7 "node": {
8 "ref": "SA-000001",
9 "entityType": "FULFILMENT_CHOICE",
10 "entityId": "789012",
11 "entityRef": "ORD-100123-1",
12 "type": "FALLBACK",
13 "status": "PARTIALLY_SOURCED",
14 "createdOn": "2026-08-17T09:30:01.000+00:00",
15 "locationCount": 2,
16 "profile": { "ref": "ANZ_DEFAULT", "version": 3 },
17 "items": [
18 { "orderItemRef": "OI-1", "productRef": "SKU-BEA-1042", "productName": "Hydra-Glow Vitamin C Serum 30ml", "quantity": 5 },
19 { "orderItemRef": "OI-2", "productRef": "SKU-FAS-7781", "productName": "Merino Wool Crew Knit - Charcoal (M)", "quantity": 3 },
20 { "orderItemRef": "OI-3", "productRef": "SKU-PHA-3305", "productName": "Paracetamol 500mg Tablets - 24 Pack", "quantity": 2 }
21 ],
22 "strategies": [
23 {
24 "strategyRef": "b8e7c1a0-4f2d-4c8e-9a1b-2f6d3e5c7a90",
25 "status": "SKIPPED",
26 "evaluatedOn": "2026-08-17T09:30:01.000+00:00",
27 "locationCount": 0,
28 "conditions": [ { "p": false, "a": "STANDARD" } ],
29 "locations": [],
30 "fulfilments": []
31 },
32 {
33 "strategyRef": "c3d9f2b1-5a7e-4b6c-8d0f-1e2a3b4c5d6e",
34 "status": "EVALUATED",
35 "evaluatedOn": "2026-08-17T09:30:01.000+00:00",
36 "locationCount": 2,
37 "conditions": [ { "p": true, "a": "NSW" } ],
38 "locations": [
39 { "locationRef": "SYD01", "locationName": "Sydney CBD", "criteria": [ { "n": 1, "a": 2.4 } ], "missingItemQuantities": [ 0, 2, 0 ] },
40 { "locationRef": "MEL01", "locationName": "Melbourne Central", "criteria": [ { "n": 0.61, "a": 713.4 } ], "missingItemQuantities": [ 0, 3, 0 ] }
41 ],
42 "fulfilments": [
43 { "fulfilmentRef": "FUL-1", "selectedLocationPosition": 0, "itemQuantities": [ 5, 1, 2 ] }
44 ]
45 }
46 ]
47 }
48 },
49 {
50 "cursor": "Y3Vyc29yOi0tLTIwMjYtMDgtMTdUMDktMzAtMDAuMDAwWi1wcjAwMDAwMC5neg==",
51 "node": {
52 "ref": "SA-000000",
53 "entityType": "FULFILMENT_CHOICE",
54 "entityId": "789012",
55 "entityRef": "ORD-100123-1",
56 "type": "PRIMARY",
57 "status": "NOT_SOURCED",
58 "createdOn": "2026-08-17T09:30:00.000+00:00",
59 "locationCount": 2,
60 "profile": { "ref": "ANZ_DEFAULT", "version": 3 },
61 "items": [
62 { "orderItemRef": "OI-1", "productRef": "SKU-BEA-1042", "productName": "Hydra-Glow Vitamin C Serum 30ml", "quantity": 5 },
63 { "orderItemRef": "OI-2", "productRef": "SKU-FAS-7781", "productName": "Merino Wool Crew Knit - Charcoal (M)", "quantity": 3 },
64 { "orderItemRef": "OI-3", "productRef": "SKU-PHA-3305", "productName": "Paracetamol 500mg Tablets - 24 Pack", "quantity": 2 }
65 ],
66 "strategies": [
67 {
68 "strategyRef": "a1c4f6e2-8d7b-4e39-b0a2-6c9f1d3e5a72",
69 "status": "SKIPPED",
70 "evaluatedOn": "2026-08-17T09:30:00.000+00:00",
71 "locationCount": 0,
72 "conditions": [ { "p": false, "a": "STANDARD" } ],
73 "locations": [],
74 "fulfilments": []
75 },
76 {
77 "strategyRef": "d4b0e9a7-1c62-4f8d-a3b5-7e9c0d2f4a13",
78 "status": "EVALUATED",
79 "evaluatedOn": "2026-08-17T09:30:00.000+00:00",
80 "locationCount": 2,
81 "conditions": [ { "p": true, "a": "NSW" } ],
82 "locations": [],
83 "fulfilments": []
84 }
85 ]
86 }
87 }
88 ],
89 "pageInfo": { "hasNextPage": false, "hasPreviousPage": false }
90 }
91 }
92}Author:
Kirill Gaiduk
Changed on:
3 Sept 2026
`SOURCINGAUDIT_VIEW`. The resolved Sourcing Profile is shown only to users who also hold `SOURCINGPROFILE_VIEW``sourcingAudits` query for the current Order and its Fulfillment Choices
`SOURCINGAUDIT_VIEW` - required to see the Sourcing tab and read Sourcing Audit records`SOURCINGPROFILE_VIEW` - required to see the resolved Sourcing Profile and version on each request`SOURCINGAUDIT_VIEW` do not see the Sourcing tab.| Column | Description |
| Entity Type | The type of entity the request sourced - `ORDER` or `FULFILMENT_CHOICE` |
| Entity Ref | The reference of that entity |
| Requested At | When the Sourcing Request ran |
| Strategy Type | `PRIMARY` or `FALLBACK` |
| Sourcing Profile | The resolved Sourcing Profile and version, shown only with `SOURCINGPROFILE_VIEW` |
| Active Strategy | The Strategy that produced the Fulfillments |
| Items | The number of items the request sourced |
| Fulfillments Allocated | The number of Fulfillments the request produced |
| Status | `FULLY_SOURCED`, `PARTIALLY_SOURCED`, or `NOT_SOURCED` |


| Column | Description |
| Order Item Ref | The order item reference |
| Product Ref | The product reference |
| Product Name | The product name |
| Quantity | The quantity requested |


