Skip to main content

Scope contents

docs image

Scope contents

What can be used in your orchestration sheet

Scope contents

Once you know what scopes to use in your orchestration sheet, it's time to start getting creative. This page will show you exactly what kind of properties you can use in your sheets. Your first sheets can be tricky, so we'll include lots of examples.

The lines between your scopes are filled with properties, which comprise the bulk of your sheets. These properties are what allows you to finetune the funnel your fulfillment goes through.

Funnel

The guiding principle is that all logic within a sheet is used to narrow down the number of options for fulfillment. To ensure EVA can run your sheets efficiently, we recommend you put all logic that decreases the potential outcomes to the greatest extent in your sheet first.

Three properties to start your sheet with

There are three properties which are always specified at the start of your orchestration sheet. The first two of them, fulfillment and action, are both mandatory.

Fulfillment - unique identifier

Every sheet starts out with a fulfillment property. This property doesn't represent any functionality, it's just a unique identifier for your sheet. However, this property should only be set once and never altered. Altering this property could cause some rerouting issues.

An example
Making a SFS sheet
fulfillment ShipFromStore

Action

The second line after the fulfillment, defines the sheet's action. This property reflects the final action that must be taken when the sheet has the highest score and will thus be used for fulfillment on the order(lines).

These are the possible actions:

  • SHIP_FROM_STORE
  • EXPORT_ORDER
  • CANCEL - to cancel the order
    • This is used as a fallback in case the logic doesn't come up with any possible fulfillment propositions.
  • Export_Return_Order - let order orchestration take care of returns (see also Returns orchestration)
    • Aside from using orchestration to find the best possible return OU, this will let you choose if/how the export should take place.
    • EVA will take care of the return labels based on the Return order documents documentation.
An example
Making a SFS sheet

fulfillment ShipFromStore

action SHIP_FROM_STORE

Option

There are five attributes which are in principle all optional, but which can greatly influence your orchestration flow. We call these options. If you want to, you need to specifically enable these in your sheets.

The first one stands out since even though options are indeed optional, the OrderIntents option is actually always active with a default Sales state. So if you want a non-sales sheet, check out the following breakdown.

1. Setting the OrderIntents - determine a sheet's purpose

By default a sheet is determined as a sales sheet - even if no OrderIntents are specified. You can set the following purposes for a sheet, which you can technically combine if that is preferrable.


Possible OrderIntents

option OrderIntents as 'Sales' // Default state
option OrderIntents as 'Purchase' // For orchestrating purchases
option OrderIntents as 'Returns' // To orchestrate returns to warehouses
option OrderIntents as 'ReturnToSupplier' // Specifically for your RTS flows
option OrderIntents as 'Sales', 'Purchase', 'Returns'


2. Enabling partial fulfillment - spread orders across multiple sheets

The option AllowPartialFulfillment determines whether a specific sheet can be used for partial fulfillment or not.

Setting this to true will allow order lines to be allocated to different OUs in a split shipment. If set to false, the cancellation of any single order line will result in the cancellation of the entire order.


This setting enables orders to split the fulfillment across OUs. You might partially fulfill through Ship from Store and partially through the warehouse, or split the order across multiple stores. Each OU will have its own OrderFulfillmentLine filled with OrderLines - product quantities are not split. If this option is set to false (default), orders can only be fulfilled using one sheet.


Enabling partial fulfillment

option AllowPartialFulfillment as true


3. Enabling line splitting - split quantities across sheets

The second option depends on the first one, since it only applies if AllowPartialFulfillment is set to true. DisableLineSplitting is by default set to false, which means splitting quantities of the products is not allowed. By setting it to true however, you can fine tune what sheets are allowed to split the quantity of these lines and which aren't.


Enabling line splitting
option DisableLineSplitting as true

An example scenario: Partial fulfillment with line splitting

Let's make this clearer with an example.


AllowPartialFulfillmentOrder is set to true and the order requests:

  • 4 shoes
  • 2 sweaters
  • 2 scarfs.

SFS sheet has DisableLineSplitting false
Warehouse sheet DisableLineSplitting true

OU:StoreA has 2 shoes and 1 sweater
OU:StoreB has 2 shoes and 1 sweater
WarehouseA has 2 shoes, 1 sweater and 1 scarf
WarehouseB has 2 shoes, 1 sweater and 1 scarf

Since neither the stores nor the warehouses have enough shoes and sweaters on their own, the fulfillment of those two will be carried out by the sheet that allows line splitting: a combination of stores A and B.


Since only the warehouses carry scarfs however, and both only have a single one while splitting is disabled for the warehouse sheet, the entire OrderLine containing scarfs will be *Cancelled*.

4. Using replacement products in out-of-stock situations

By creating product relations you can define which products serve as a replacement for other products. That means if one product is out of stock, the other can be used instead.


Enabling replacement stock
option UseReplacementProductsForStock as true

5. Setting a maximum number of retries before skipping a supplier/sheet combination

The last available option is MaxRetryCountForDeactivatedLines. This involves order lines with the Deactivated status and indicates the number of deactivated OrderFulfillmentLines that are allowed to exist for a supplier/sheet combination before that combination is ignored again.


Setting a maximum number of retries
option MaxRetryCountForDeactivatedLines as 5 
Rerouting to the same supplier only possible in case of deactivation

The OrderLine can only be rerouted to the same supplier/sheet a second (or more) time if ALL the existing fulfillment lines for the OrderLine have the status Deactivated - which indicates another store had accepted the SFS task already.

If there are any cancelled fulfillments, because the store actively declined the SFS task for example, the OU is ignored in future orchestrations.

Properties in scopes

After stating the fulfillment, action and optionally option properties, you start building the scopes.

This works by specifying the scope first, followed by all the properties you need to create your orchestration logic. All properties in turn work with variables, such as [Supplier.Type] or even [Supplier.DistanceToShippingAddressInKm].

Require

Require allows you to demand certain values on existing variables. It's used amply throughout your sheets.

Two examples
Requiring an OU to be a shop

# We make this sheet negate all possible suppliers that don't have the organization type 'Shop'

scope Supplier

require [Supplier.Type] = 'Shop'

# Make sure it's not a closed shop

require [Supplier.Status] <> 'Closed'

Excluding products with require

scope OrderLine

require Product.CustomID not in [Easter egg hunt]

Logging rejections: with reason

In the previous example, possible suppliers were rejected for a certain reason. It's possible to track these rejections using with reason.

An example
Log every instance where supplier was not a shop

require [Supplier.Type] = 'Shop' with reason 'NotShop'

You can also add a more elaborate description after the reason:

Add a description to the log
require [Supplier.Type] = 'Shop' with reason 'NotShop', 'This organization unit is not a shop'

This example however, should never be used in practice. In this with reason example, every single rejected organization unit will be logged in the database with the reasoning. If your organization is of considerable proportions, this could end up being some pretty heavy logging.


Filter reasons

It is also possible to limit the number of returned reasons, to ensure your logging won't be filled with irrelevant information.

An example

Require shops to be within 10 km of delivery address

# In a ShipFromStore sheet, we only want to work with stores that are within ten kilometers of the customer

require Supplier.DistanceToShippingAddressInKm < 10
with reason 'TooFarAway'

This would result in failure reasons for every store that is not within ten kilometers of the shipping address. This information probably isn't relevant for you, so you want to narrow this down. You can do so using the when statement:

Exclude shops from the log list further than 20 km away
require Supplier.DistanceToShippingAddressInKm < 10
with reason 'TooFarAway' when Supplier.DistanceToShippingAddressInKm < 20

Now you will only get failure reasons for stores that are further away than ten kilometers, but are within twenty kilometers of the customer.

Note

Please note that to use distance calculation in Order Orchestration, you need to set a Google Geocoding API key.


With template string

This is pretty much the same as the detailed description of with reason, the difference being the option to allow for the use of variables.

An example

Log every instance where supplier was not a shop but use actual names

require [Supplier.Type] = 'Shop' with reason 'NotShop', $'Organization unit {[Supplier.Name]} is not a shop'

But continue

In case you want to know the rejection reason for an organization unit at a certain step, but that organization unit is already rejected by some logic that comes first, you can use but continue in that initial line.

This doesn't un-reject the organization units, it simply takes the organization units that are rejected at a specific line into account for following lines, until rejected again. Or, well, rejected2.

An example

Take all rejected OUs along to the next line

require [Supplier.Type] = 'Shop' with reason 'NotShop', 'This organization unit is not a shop' but continue

Data

Depending on the action you set at the start of your sheet, your sheet may benefit from - or even require - a specific set of data lines. It's why we split the available data properties in two sections.

Mandatory data lines

SHIP_FROM_STORE - mandatory lines

When you create a SHIP_FROM_STORE orchestration sheet, EVA needs the following data to create the corresponding SFS task.

Mandatory data lines for SFS sheets

data [TravelDistanceText] as [Supplier.RouteToShippingAddressByBike.DistanceText]\
data [TravelTimeText] as [Supplier.RouteToShippingAddressByBike.TimeText]\
data [TravelTimeInMinutes] as [Supplier.RouteToShippingAddressByBike.TimeInMinutes]\
data [TravelDistanceInKm] as [Supplier.RouteToShippingAddressByBike.DistanceInKm]


EXPORT_ORDER - mandatory lines

If you instead create an *EXPORT_ORDER* sheet, EVA will need the following **data** to know which warehouse to eventually export the order to.
Mandatory data line for EXPORTER sheets

data [ExporterName] as 'WAREHOUSE'


Non-mandatory data lines

By specifying a data called TaskLabels you can influence the labels on the SFS task and distinguish different types of orders. This way you can easily see which order/task is for example a fanout task and which one is an order via another platform. You can then prioritize delivery.

In order to make fanout a label as well, you can enable the setting ShipFromStore:FanoutTaskLabel (defaults to null). When this setting is filled with a string (for example Fanout), then if the fulfillment is part of a fanout, that label is added to the list of labels (if any).

Examples of using labels

In the first example, an order comes in via PushSalesOrder. It has a custom field that specifies the order was made via the Popup channel.


Custom field containing channel

"CustomFields": {
"PickupServicePointID": null,
"Channel": "Popup"
}

Now we give this channel a specific task label.


Simple task label

# Nothing is not included in the list, you can also fallback to e.g. webshop as the default

with PopupLabel as (when Order.CustomFields.Channel = 'Popup' then 'Popup' else then nothing)

data TaskLabels as AmazonLabel

Here's a more expansive example with multiple task labels.


Multiple task labels
fulfillment ShipFromStore

action 'SHIP_FROM_STORE'

scope Order

with Random1Label as (when Order.CustomFields.IsRandom1Order = 'true' then 'Random1' else then 'NotRandom1')
with Random2Label as (when Order.CustomFields.IsRandom2Order = 'true' then 'Random2' else then nothing)

scope OrderLine

with IsLimitedEdition as (when Product.Content.is_limited_edition = 'true' then 'LimitedEdition' else then 'NotLimitedEdition')

data TaskLabels as Random1Label, 'SFS_task', Random2Label, IsLimitedEdition

Score

The score property is used to directly affect the sheet's score by adding or decreasing points based on your variables.

Businesses may prefer proximity over split shipments, and this preference can be influenced by the sheet's score.

An example

Increasing the score for closer OUs

# a shop that's 100 meters away gets 10 added, while one 2 km away gets 0.5

score add 1.0 / [Supplier.RouteToShippingAddressByBike.DistanceInKm]

Scoring on soft elements

Order orchestration also supports scoring based on so called "soft elements". These are variables that are inherently dynamic.

The first two soft variables we've introduced revolve around how well stores perform their SFS tasks. Every time a store is chosen for fulfillment, its score will change based on if/how well it performed.

Store SFS cancellation rate

By introducing Supplier.OrderFulfillmentPerformance.CancellationRate to your supplier scope, you can start keeping track of how often a store cancels (part of) its SFS tasks and in doing so assign a corresponding score per store. This score is calculated based on the ratio between cancelled and completed order lines in a fulfillment.


Example: An OrderFulfillmentLine with 10 OrderLines out of which 1 is cancelled, results in cancellation rate of 0.1.


You can consequently use this to either make a hard statement (like in the following example), completely removing some suppliers from being considered a fulfillment possibility at all, or you can use this as a means of applying scoring. The latter lets you favour well-performing stores while keeping the worst performing ones available as last picks.


Prevent bad-performing OUs from participating

# Prevent any supplier with a cancellation rate higher than 80% from being able to be selected

Supplier.OrderFulfillmentPerformance.CancellationRate != > 0.8

Store SFS completion time

By introducing Supplier.OrderFulfillmentPerformance.AverageCompletionTimeInMinutes to your supplier scope, you can add points for a store based on its SFS task completion time. This is the average number of minutes between the appearance of the SFS task in a store and when the task is completed.


Increasing the score for quick OUs

# Set a score for lower AverageCompletionTimeInMinutes when the value is bigger than zero (when a score is actually available)

score add 100 / [Supplier.OrderFulfillmentPerformance.AverageCompletionTimeInMinutes] when [Supplier.OrderFulfillmentPerformance.AverageCompletionTimeInMinutes] > 0
Opening hours required

Note that this functionality cannot work for OUs which don't have opening hours set, since those are necessary to calculate the moment when a store is able to perform a SFS task. Setting even a basic opening hours template prevents OUs from scoring badly through no fault of their own.


Both the above variables are influenced by the following setting: OrderFulfillment:SupplierPerformanceWindow.

This setting allows you to set a time window. Only the days mentioned here will be taken into account for calculating the stores scores. It takes the following two values:

  • LastSevenDays (default value): The last seven days, if today were the 19th this would cover the performance from the 11th up to and including 18th.
  • LastThirtyDays: The last thirty days, if today were the 19th this would cover the last 30 days up to and including the 18th.

You'll be able to see the score in the Logistics tab of each OU in Admin Suite.


Frequently Asked Questions
  • Where can I check the scores?
    • As mentioned, both average completion time and cancellation rate can be checked in Admin Suite, but you can also call GetOrderFulfillmentSupplierPerformance with an OrganizationUnitID directly to check the OU's scoring values.
  • When are the KPIs updated?
    • The supplier performance is calculated when it's used (either through the service or through an orchestration sheet) and the result is then cached for 1 hour. At the time it's calculated it uses the current time as the cutoff point and then goes back 7 or 30 days (depending on OrderFulfillment:SupplierPerformanceWindow) from that point. Mind that the 1 hour delay does not have significant impact on the actual numbers, since supplier performance is averaged out over a period of 7 or 30 days.
  • Some OUs get updated quicker than others?
    • Supplier performance is calculated on demand and it's calculated per organization. So it's possible that it seems like A gets its new value before B, but that's only because A was requested earlier than B and its cache expired sooner.
  • Why does the cancellation rate for some merchants seem to start at 0 while others start at 1?
    • The cancellation rate is based on the ratio of cancelled fulfillments to total fulfillments. If there are no fulfillments for the supplier, the cancellation rate will always be zero. If it's not zero, then it did have fulfillments at some point in the 7 or 30 day window.

Custom fields

A special mention is warranted for the use of custom fields, since these allow you to create custom logic throughout the entirety of your sheets.

They can be used in the OrderLine scope for example, allowing you to finetune the logic for specific lines of your order only. Or you might use them in the Supplier scope to ensure the use of specific suppliers.

The custom fields can live on OUs, orders, etcetera; you can pinpoint to whichever ones you need to use here.

Examples of custom fields usage

In the following example the order contains a line with a product that needs printing, thus requiring an OU with a printing capability.


Explicitly the example entails that when the order line has a custom field called CustomizationType with the value print, then the supplier is required to be an OU with a custom field called 'PrintingCapable' and the value true.


require Supplier.Customfields.PrintingCapable = true when Orderline.Customfields.CustomizationType = ‘print’

The below example is similar, but a bit more in-depth. It sets the variable CustomizationType with whatever value is passed, or to None when there's no value. It is then used to require the Supplier to be part of the OU set called PrintSuppliers when the custom field called CustomizationType has the value Print.


We even go a bit further by adding the (rejection) reasons, which you'll read about a few chapters down.


with CustomizationType as when [OrderLine.CustomFields.CustomizationType] has value then [OrderLine.CustomFields.CustomizationType] else then 'None' 

require [Supplier.SetNames] in 'PrintSuppliers' when CustomizationType = 'Print'
with reason 'NoPrinting', $'Supplier {[Supplier.Name]} is not part of the set of OUs that print stuff'

Returns orchestration

As you could already see in the OrderIntents, you can also use your orchestration sheets to determine which OUs are suited best for returns.

Ensure order orchestration is enabled for returns

Although we recommend your organization to make use of Unified orders, if you do not make use of it, you will have to set UseOrderOrchestrationForReturnOrders to true specifically before you can use orchestration for returns.

Your OrderIntents need to be set to Returns like so:

option OrderIntents as Returns

The fulfillment method needs to be set to EXPORT_RETURN_ORDER in order to create the return labels/documents and email them. Set the ExporterName of the exporter in the Data field, to determine how the export needs to take place.

The OU that the return order is orchestrated to, is made available on the ReturnForm stencil template and on the ReturnMail stencil template. The stencil model has a ReturnOrganizationUnit property on its root level, for the 99.99% case where the return order is headed to a single warehouse.

However, the fulfillment OU is an OrderLine-level property, so theoretically it’s possible that each order line is headed to a different OU. The root-level property will always be filled in (at least when using order orchestration) and should be sufficient for all uses. The same property is however also present on each OrderLine. The above goes for both the ReturnForm and the ReturnMail stencil template.

Below you can find an example sheet for returns.

Order orchestration returns sheet
fulfillment ReturnOrdersFromReturnPortal

action 'EXPORT_RETURN_ORDER'

option OrderIntents as 'Returns'

scope Order

scope Supplier

require Supplier.Type = 'Warehouse'

data ExporterName as 'TEST_SUITE'

The second example dives into the creation of a return order sheet where EVA disables exports.

Export_Return_Order

fulfillment GreyStoreReturns

option OrderIntents as 'Returns'

action 'EXPORT_RETURN_ORDER'

scope Supplier

require [Supplier.BackendID] = 'Return_Store'

score add 10

with [Data.ExporterName] as 'DEFAULT'

In the last example, we've used [Data.ExporterName] with the DEFAULT value. This value entails that NO export is done to an external system, in other words: EVA does not inform an external system about upcoming return orders.

Even with the action 'EXPORT_RETURN_ORDER', you could still add WAREHOUSE as the [Data.ExporterName], to inform the warehouse as mentioned in the Warehouse order exporter documentation.

EVA return portal

The following is only relevant when using the New Black return portal AND not using the unified orders concept.

The sheet needs to make use of the following OrganizationUnitType, which was added for the purpose of returns especially: ReturnsPortal ().

require Order.SoldFromOrganizationUnit.Type = 'ReturnsPortal'