HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunitySubmit a ticketLog In

Multi-warehouse implementations

Describes the multiple inventory locations concept in Optimizely Customized Commerce.

You can define multiple inventory locations in the system. These are any place with inventory you want to track, whether a warehouse is used for shipping, individual stores, a factory, or whatever meets your needs. You can even include trucks that are delivering orders.

Currently, only shipping from one central warehouse location is supported. You can still track overall inventory if you have multiple shipping sources but do not want to edit Optimizely Customized Commerce. You must figure out shipment fulfillment logistics from individual shipment locations, outside of Customized Commerce.

In-store pickup from any store location is provided, which can handle any locations defined as places for pickup (but not for fulfillment). In our definitions, these are Fulfillment Centers from which you can ship and Pickup Locations at which a customer can pick up an order. Without customizing, you can have only one Fulfillment Center but any number of Pickup Locations.

These limitations exist because no one knows your business like you. Some business logic to support fulfillment from multiple locations is provided in the sample code. However, each business has its own approach to fulfillment practices, and no logic supports more than a few situations at a time.

Fulfillment technical details

The changes to support multiple locations across infrastructural code are hidden in the assemblies, new services, and the logic visible in the workflows. The infrastructural changes do not matter to most customers, although they may affect existing customized installations. You may implement your needs directly in the workflows or by replacing the services.


The core business logic for inventory and shipping is implemented in the workflows. The key places to look for these are:

  • Cart Workflows
    • GetFulfillmentWarehouseActivity
    • AdjustInventoryActivity
    • ShipmentSplitActivity
  • OrderGroupActivities
    • OrderGroupActivityBase
  • PurchaseOrderActivities
    • AdjustInstoreInventoryActivity
    • CheckInstoreInventoryActivity
    • HandoffActivityBase

There is no implementation for multiple fulfillment centers out of the box. To have multiple fulfillment centers, you need to:

  1. Disable the current lockout (required).
  2. Implement custom warehouse selection logic (required).
  3. Possibly implement custom inventory management logic (optional).

The modifications required for each of these are detailed below.

Disable the lockout

The default installation is designed to raise an exception for certain operations when multiple warehouses are flagged as fulfillment centers. This exception is raised in the OrderGroupActivities\OrderGroupActivityBase workflo in the CheckMultiWarehouse() method. The method is called from multiple locations (for example,  AdjustInventoryActivity.cs, AdjustInstoreInventoryActivity.cs at the time of this writing), so it is easier to clear the contents rather than removing all references. To allow multiple fulfillment warehouses, replace the existing method with the following:

protected virtual void CheckMultiWarehouse(){}

You can also add consistency checks to meet your needs.

Custom warehouse selection

The second part is the major piece of the implementation and cannot be described in depth since the actual logic is dependent on the needs of a particular business. This guide only covers where an implementation must override the default logic.

The main piece of business logic to replace is in the GetFulfillmentWarehouseForLineItem() method in this workflow. In the default implementation, it does little more than find the default warehouse (see line 87). Replace this with custom logic.

As workflow inherits from OrderGroupActivity, you already have an OrderGroup and its data available for all calculations and logic. To determine your list of warehouses and information about their available inventory, access two new service interfaces that were added for release 10. These are the IWarehouseRepository and IInventoryService. These can be instanced in code via the following:


See Warehouse/Inventory Services for details. The current interfaces should be straightforward to use, although you may need to expand their functionality if you need additional information (for example, geolocation) to determine your fulfillment warehouse selection.

ShipmentSplitActivity also has a reference to warehouses that may be of interest. When a new split shipment is created, it is marked as sourcing from the same warehouse as its first line item. This works for a single fulfillment warehouse and in-store pickup but may not function as desired for a more complicated multi-warehouse solution. Determine if the SplitForm() method works for your custom solution. Adjust it if not.

Custom inventory management (optional)

The existing workflows can manage the inventory in your warehouses out of the box as long as your custom warehouse selection logic assigns the correct warehouse for each line item. However, suppose you need to change the processing logic for inventory, such as changing how backorders and preorders are handled or triggering external processes to balance inventories between warehouses as inventories get low. In that case, you need to change the logic in AdjustInventoryActivity to suit your needs. The main method with which to do that is AdjustStockItemQuantity().

The default implementation of the in-store pickup feature handles the store inventories out of the box. You may also want to consider additional inventory handling here, such as resupplying store inventory. The handling for in-store pickup inventories is found in AdjustInstoreInventoryActivity and CheckInstoreInventoryActivity. The former is probably the correct place to modify this for most implementations, but you can consider adjusting the latter instead.



The HandoffActivityBase activity includes support for in-store pickup. It is not necessary to change this, but if you choose to disable all in-store pickup functionality, you should consider removing the code from this also. These include the PickupWarehouseInShipmentProperty dependency and PickupWarehouseInShipment property. These need to be deleted.

Warehouse/inventory services

Many functions for accessing warehouse and inventory data were moved into services, which you can replace in your implementation. However, the default implementations work with the existing Customized Commerce controls and database as-is. This could be useful if you want to encapsulate the current implementation to provide more methods (such as to support geolocation-based fulfillment logic), or if you wish to replace them entirely to manage your inventory with a new or external system.

If you want to implement a custom inventory integration, there are 2 main services to consider:

  • IWarehouseRepository. Methods for accessing the warehouse definitions.
  • IInventoryService. Methods for managing warehouse information and inventory levels of warehouse catalog entries.

You should review the interfaces for the required properties and methods documented in the method signatures. They should be self-explanatory in terms of the expected input and output values. What you need to do depends on the scope of your changes. It needs to be considered on a case-by-case basis.

The recommended model for managing inventory data across separate ERP and Optimizely Customized Commerce systems is to update Commerce regularly and allow Customized Commerce to track inventory internally between updates. Allowing Commerce to manage its own inventory provides the best performance in almost all situations. The main issue from a business standpoint is whether inventory is being sold (or otherwise removed) independently of Customized Commerce. In this case, you need to find a way to reconcile orders, by updating Customized Commerce on-the-fly or by an appropriate backorder process.

You need to consider carefully the pros and cons of the various approaches (for instance, development costs for integrations and whether it is worth incurring the higher latency costs of communicating with your ERP directly to have perfectly accurate numbers at all times). When reviewing these interfaces, remember that some interfaces may be switched to use business objects instead of ID fields.