You can define multiple inventory locations in the system. These are any place that has inventory that you want to track, whether it is a warehouse being 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. If you have multiple shipping sources but do not want to change Customized Commerce, you can still track overall inventory. However, you will need to figure out shipment fulfillment logistics from individual shipment locations on your own.
In-store pickup from any store location is provided, which can handle any number of locations that are 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 Commerce, 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 logic that is 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:
There is no implementation for multiple fulfillment centers out of the box. To have multiple fulfillment centers, you need to:
Disable the current lockout (required).
Implement custom warehouse selection logic (required).
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 workflow, 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:
or add whatever consistency checks 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 the places where an implementation may need to override the default logic.
The main piece of business logic to replace is found in this workflow, in the GetFulfillmentWarehouseForLineItem() method. 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. Currently, 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 Customized Commerce 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, if you need to change the processing logic for inventory, such as changing how backorders and preorders are handled or to trigger external processes to balance inventories between warehouses as inventories get low, 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 (e.g., 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 catalog entries at the warehouses.
You should review the interfaces for the required properties and methods, which are 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 Customized Commerce systems is to update Commerce on a scheduled basis and allow Commerce to track inventory internally between updates. Allowing Customized 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 Commerce. In this case, you need to find a way to reconcile orders, by updating 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 so that you have perfectly accurate numbers at all times). When reviewing these interfaces, keep in mind that some interfaces may be switched to use business objects instead of ID fields in the future.