Managing ATP allocations and order splits
This document outlines the end-to-end flow for reserving order items using the ATP (Available to Promise) system, focusing on the processes for both on-hand inventory and backordered items. This includes detailed steps on how the system interacts with the Inventory PBC API to manage inventory efficiently, ensuring optimal customer satisfaction.
Allocating order items with On-Hand inventory
The existing command must be updated to call our Inventory PBC API for the allocate operation, which allocates order items that have on-hand inventory available.
- API Call
-
- URL:
{{host:port/inventory/api/v1/available-inventories/allocate?store=Ruby&processAllOrNone=false&splitFulfillment=true}} - Method:
POST - Request Body:
{ "inventories": [ { "partNumber": "LR-FNTR-0001-0001", "fulfillmentCenterId": "R00B2C", "requestedQuantity": 7 } ] } - **Command
affected:
**com.hcl.commerce.fulfillment.commands.AllocateExistingInventoryCmdImpl
- URL:
- Example
-
-
- Initial Inventory Status
- Consider an example where the on-hand inventory for part number X is five units in inventory location Y.
-
- User Action
- Inventory gets allocated during the addToCart action itself. So, once the user adds seven quantities of item X to the cart from inventory location Y, we call our inventory PBC API for inventory allocation.
-
- Triggering Allocation Command
- The system triggers the command AllocateExistingInventoryCmdImpl, initiating the allocation of the requested quantity from the available on-hand inventory.
-
- OnHand Inventory Allocation Logic
-
- The command checks the available on-hand
inventory:
- Since only five units are available, the command allocates these five units to the order.
- The remaining quantity to allocate is two (seven requested - five allocated).
- The command checks the available on-hand
inventory:
-
POST On-hand inventory allocation
-
- Post-allocation evaluation
-
- After the allocation, the system conducts an evaluation:
- Requested Quantity: Seven
- Allocated Quantity: Five
- Unallocated Quantity: Two
- After the allocation, the system conducts an evaluation:
-
- Eligibility for Split
-
- The system checks the minSplitQty configuration in the
STOREITEM table:
- If two >= minSplitQty, the item is eligible for a split.
- A new orderitemId is created for the unallocated quantity of two, which is then marked as unallocated.
- These two quantities come from expectedInventory to be allocated using our allocate API.
- The system checks the minSplitQty configuration in the
STOREITEM table:
-
- Deallocation (if not eligible for split)
-
- If the unallocated quantity does not meet the minimum split
quantity:
- The command DeallocateExistingInventoryCmdImpl is invoked to deallocate the previously allocated five units.
- The command will call out Inventory PBC API as below.
- URL:
{{host:port/inventory/api/v1/available-inventories/deallocate?store=Ruby&processAllOrNone=false}} - Method:
POST. - Request
Body:
{ "inventories": [ { "partNumber": "LR-FNTR-0001-0001", "fulfillmentCenterId": "R00B2C", "requestedQuantity": 5 } ] - The system updates the order status to reflect that no items have been allocated.
- After deallocating, the whole seven quantities become eligible for allocation from backorder.
- If the unallocated quantity does not meet the minimum split
quantity:
Allocate order items from expected inventory
The system must also be updated to call our Inventory PBC API for the allocation operation to allocate order items for which there is no sufficient on-hand inventory.
- API Call
-
- URL:
{{host:port/inventory/api/v1/expected-inventories/allocate?store=Ruby&processAllOrNone=false}} - Method:
POST.{ "inventories": [ { "partNumber": "LR-FNTR-0001-0001", "fulfillmentCenterId": "R00B2C", "requestedQuantity": 2 } ] } - **Command affected:
**com.hcl.commerce.fulfillment.commands.AllocateExpectedInventoryCmdImpl
- URL:
Let's continue with the previous example
-
- Scenario of Unallocated Items
-
- Following the previous example, two quantities of item X remain unallocated after the initial add-to-cart process due to insufficient on-hand inventory.
- The system now aims to allocate these two quantities from expected inventory.
-
- Executing the Allocation Command
-
- The system calls the command AllocateExpectedInventoryCmdImpl to attempt to allocate the unallocated quantities from the expected inventory.
- This command checks the expected inventory levels for item X.
-
- Backorderable Check
-
- If the items are backorderable:
- The system proceeds with the allocation from the expected inventory.
- The inventory levels are updated accordingly to reflect the new reservations.
- If the items are not backorderable:
- An exception is returned, indicating that the requested items cannot be allocated.
- The user is notified about the inability to fulfill the order due to unavailability.
- If the items are backorderable:
- Example outcome
-
- Successful Allocation
-
- If the system successfully allocates the split order item of two from the expected inventory, it updates the order status to indicate that these items are now assigned.
- The user receives confirmation that the items will be fulfilled as soon as they become available.
- Unsuccessful Allocation
-
- If the allocation fails because the items are back orderable, the user is informed that the items cannot be allocated, and they may need to adjust their order or wait for inventory replenishment.
Place order after allocation
After this allocation happens, we go and place the order. The order status will be code 'B,' indicating backorder status, as we have one order item with quantity two, which is from backorder.
Once the order is placed, there is a scheduler job, ProcessBackordersCmdImpl, that runs periodically to process backorders as described in the following steps:
- Process backorder inventory by ProcessBackorder scheduler job when placed order
-
- Let us see how our order will be processed
- Take the following scenario, in which an order has been placed
with split order items:
- Order Item one: five quantities allocated from on-hand inventory.
- Order Item two: two quantities allocated from backorder.
- ProcessBackorderCmdImpl job execution
- When the ProcessBackordersCmdImpl job runs, it performs
the following steps:
- The Commerce Order System fetches order items with an inventory status of BO (backorder) based on the time placed.
- After selecting the order items, it calls the
AllocateInventoryCmd command, which
performs these actions:
-
- DeAllocate Backorder Inventory
- This command calls DeallocateExpectedInventoryCmdImpl to deallocate the backorder inventory for the backordered items. Here, two quantities will be deallocated to expected inventory.
-
- Allocate from On-Hand inventory
-
The job then calls the AllocateExistingInventoryCmdImpl command, passing splitFulfillment='false' (this will be passed only for backorder items; otherwise, the value will be 'true') to allocate the entire required quantity from a single Inventory Location (IL) for those backordered items.Note: When splitFulfillment='false', if the entire required quantity is available in that inventory location , allocate it, and do not proceed to the next step C, otherwise, do not perform the partial allocation.
-
- Allocate from Expected Inventory
- When processing the backorder inventory, two
scenarios may arise:
-
- Scenario 1: Partial On-Hand inventory available
- If you need two on-hand
quantities but only one has
arrived by the time you process the backorder via
the scheduler, this one
quantity will be allocated and placed into the
QTYALLOBACKORDERED column
instead of the QTYINPROCESS
column (which is the expected behavior when
allocating quantity from on-hand
inventory).Thus, QTYALLOBACKORDER holds allocated on-hand inventory for backorder items when complete inventory is not available. The remaining one will then be allocated from the expected inventory.Note: When this order item is processed again by the backorder scheduler, the deallocatBackOrder API will look like following:
- API Call:
- URL:
{{host:port/inventory/api/v1/expected-inventories/deallocate?store=Ruby&processAllOrNone=false}} - Method:
POST - Request Body:
{ "inventories": [ { "partNumber": "LR-FNTR-0001-0001", "fulfillmentCenterId": "R00B2C", "unitOfMeasure": "C62", "allocatedQuantityOnHand": 1, "allocatedQuantityBackordered": 1, "allocationDetails": [ { "expectedInventoryId": 1, "quantityAllocated": 1 } ] } ] } - allocatedQuantityOnHand is the value in QTYALLOBACKORDER against that order item.
- Command affected:
com.hcl.commerce.fulfillment.commands.DeallocateExpectedInventoryCmdImpl
- URL:
- API Call:
-
- Scenario 2: No On-Hand Inventory Available
- If you need two on-hand quantities but have zero available, the system will allocate the two from the expected inventory. In this case, the order items will revert to backorder status.
-
- Continuous Allocation Process
- This process continues until all backorder items are entirely allocated from on-hand inventory. The scheduler job runs at specified intervals to ensure that any newly available inventory is allocated to fulfill the backorder items, ultimately updating their status to indicate successful allocation and readiness for release.
-
- Release to Fulfillment scheduler job execution
- After updating the order status to
M, the
ReleaseToFulfillment
scheduler job runs. This job performs the
following actions:
- It picks the orders that are in statuses like M or 'C (completed) and calls the HardReserve API to hard reserve inventory of the items.
- API Call:
- URL:
{{host:port/inventory/api/v1/available-inventories/reserve?store=Ruby&processAllOrNone=false}} - Method:
POST - Request Body:
{ "inventories": [ { "partNumber": "LR-FNTR-0001-0001", "fulfillmentCenterId": "R00B2C", "requestedQuantity": 7 } ] }
- URL:
- Command affected:
-
com.ibm.commerce.inventory.commands.DoInventoryActionCmdImpl - Once the reservation is successful, the order status is updated to R (ready), indicating that these orders are prepared for the pick batch and shipment process.
-
-
API list
- Shopper APIs
- The shopper starts by browsing items in a store and checking their availability.
- The shopper interacts with the inventory system to view available products and their locations.
- The shopper adds an item to the cart and proceeds to checkout.
- Get Item Inventories:
GET /inventory/api/v1/item-inventories?store=Ruby, retrieves the list of item inventory details for the given store. This API is used only on the storefront side to display available inventory for shoppers browsing products in the store. - Get Inventory Locations:
GET /inventory/api/v1/inventory-locations?store=Ruby, fetches the inventory details for physical stores. This API is used on the storefront side to display available inventory locations where items are located in different stores for customers to view. - POST to Create or Update Inventory Location:
POST /inventory/api/v1/inventory-locations?store=Ruby, creates or updates inventory locations in the store. This API is used to add new locations or update the details of existing inventory locations within the store.
Checkout APIs
- The checkout process continues if the items are available and the shopper can purchase them.
- Check Available Inventories (Add to Cart):
POST /inventory/api/v1/available-inventories/check?store=Ruby, verifies the availability of items in the cart for the given store. - Checkout Order (API called in sequence from ts-app when
OrderItem inventory status is
NALLC (Not Allocated))
- Inventory Validation:
POST /inventory/api/v1/available-inventories/check?store=Ruby, confirms the availability of items before proceeding with the checkout. - Allocate On-Hand Inventory (No Partial Allocation):
POST /inventory/api/v1/available-inventories/allocate?store=Ruby&splitFulfillment=false, tries to allocate the entire quantity from on-hand inventory at the given inventory location . No partial allocation is allowed. - Allocate On-Hand Inventory (Partial Allocation Allowed):
POST /inventory/api/v1/available-inventories/allocate?store=Ruby&splitFulfillment=true, tries to allocate whole or partial quantity from on-hand inventory at the given inventory location . Partial allocation is allowed. - Allocate Expected Inventory:
POST /inventory/api/v1/expected-inventories/allocate?store=Ruby, tries to allocate the whole from the expected inventory at the inventory location . Partial allocation is not allowed.
- Inventory Validation:
- Submit Order (API called in sequence from ts-app when OrderItem inventory
status is ALLC (Allocated) or BO (Backordered))
- Deallocate On-Hand Inventory:
POST /inventory/api/v1/available-inventories/deallocate?store=Ruby, tries to de-allocate on-hand inventory from the given inventory location . - Deallocate Expected Inventory:
POST /inventory/api/v1/expected-inventories/deallocate?store=Ruby, tries to de-allocate expected inventory from the given inventory location . - Check Available Inventories:
POST /inventory/api/v1/available-inventories/check?store=Ruby, confirms the availability of items before proceeding with the checkout. - Allocate On-Hand Inventory (No Partial Allocation):
POST /inventory/api/v1/available-inventories/allocate?store=Ruby&splitFulfillment=false, tries to allocate the entire quantity from on-hand inventory at the given inventory location . No partial allocation is allowed. - Allocate On-Hand Inventory (Partial Allocation Allowed):
POST /inventory/api/v1/available-inventories/allocate?store=Ruby&splitFulfillment=true, tries to allocate whole or partial quantity from on-hand inventory at the given inventory location . Partial allocation is allowed. - Allocate Expected Inventory:
POST /inventory/api/v1/expected-inventories/allocate?store=Ruby, tries to allocate the whole quantity from the expected inventory at the inventory location . Partial allocation is not allowed.
- Deallocate On-Hand Inventory:
Shopper and Checkout API endpoints
- Shopper APIs
-
GET /inventory/api/v1/item-inventories?store=RubyGET /inventory/api/v1/inventory-locations?store=RubyPOST /inventory/api/v1/inventory-locations?store=Ruby
- Checkout endpoints
-
POST /inventory/api/v1/available-inventories/check?store=RubyPOST /inventory/api/v1/available-inventories/deallocate?store=RubyPOST /inventory/api/v1/expected-inventories/deallocate?store=RubyPOST /inventory/api/v1/available-inventories/allocate?store=Ruby&splitFulfillment=falsePOST /inventory/api/v1/available-inventories/allocate?store=Ruby&splitFulfillment=truePOST /inventory/api/v1/expected-inventories/allocate?store=Ruby