Stock on Hand vs Inventory Positions
Knowing how many units are sitting on a shelf is useless if you don't know how many have already been sold online, or how many are currently on a truck. Dive into the ITEM_LOC_SOH table to understand how Oracle RMS calculates the true Inventory Position for replenishment and order promising.
If a store manager looks at a shelf and sees 10 laptops, they believe their inventory is 10. But if an online customer just purchased 3 of them for store pickup, and a truck is arriving tomorrow with 5 more, the physical count is dangerously misleading for supply chain planning.
Oracle Retail Merchandising System (RMS) solves this by maintaining a comprehensive Inventory Position. This calculated metric dictates everything from automated replenishment to ecommerce order promising. This guide breaks down the critical ITEM_LOC_SOH table and how RMS tracks stock moving in and out of the business.
1. The ITEM_LOC_SOH Table
The heartbeat of RMS inventory is the ITEM_LOC_SOH (Item Location Stock on Hand) table. Unlike some ERPs that calculate inventory on the fly by summing millions of transaction logs, RMS maintains an active, rolling total of every inventory state in this table.
When an item is received, STOCK_ON_HAND increments. When it's sold, it decrements. When a PO is approved, STOCK_ON_ORDER increments. This allows systems to query the exact state of inventory in milliseconds without heavy aggregations.
2. Physical Inventory Buckets
These columns represent goods that are physically inside the four walls of the location (store or warehouse).
- STOCK_ON_HAND: The master count. Everything physically in the building that is owned by the retailer.
- NON_SELLABLE_QTY: A subset of
STOCK_ON_HANDthat cannot be sold (e.g., damaged goods, display models, or expired products). These are excluded from replenishment calculations.
The Subset Rule
NON_SELLABLE_QTY is not additive. If you have 10 units of SOH, and 2 are damaged, your STOCK_ON_HAND is 10, and your NON_SELLABLE_QTY is 2. The sellable physical stock is mathematically derived: STOCK_ON_HAND - NON_SELLABLE_QTY.
3. Inbound Inventory Buckets
These columns represent inventory that is owned or committed to the location, but has not yet physically arrived.
- STOCK_ON_ORDER: Inventory tied to Approved Purchase Orders. The supplier has been instructed to ship it, but it has not left their facility (or they haven't sent an ASN).
- IN_TRANSIT_QTY: Inventory that is currently moving on a truck or a boat. This happens when a supplier sends an ASN, or when a warehouse ships a transfer to a store.
4. Outbound & Reserved Buckets
These columns represent inventory that is physically in STOCK_ON_HAND, but you are no longer allowed to sell it because it is promised elsewhere.
- CUSTOMER_RESV: Units reserved for a specific customer (e.g., Buy Online, Pick Up In Store - BOPIS). The customer hasn't collected them yet, so they are physically in the store, but they cannot be sold to a walk-in customer.
- TSF_RESERVED_QTY: Units reserved to be transferred out. For example, Store A is told to transfer 5 units to Store B. Store A's
TSF_RESERVED_QTYincreases by 5 until the truck arrives to pick them up. - RTV_QTY: Units reserved for a Return To Vendor. They are boxed up waiting for the supplier to collect them.
5. Calculating Net Inventory Position
The Inventory Position is the metric used by the RMS Replenishment engine. It asks: "If I look at what I have, what I've promised away, and what is already on its way... do I need to order more?"
The standard formula for Inventory Position is:
Inventory Position = (Sellable Physical Stock) + (Inbound Stock) - (Outbound Reservations)
Expanded into ITEM_LOC_SOH columns, it looks like this:
Inventory Position = (STOCK_ON_HAND - NON_SELLABLE_QTY) + (IN_TRANSIT_QTY + STOCK_ON_ORDER) - (CUSTOMER_RESV + TSF_RESERVED_QTY + RTV_QTY)
If this calculated Inventory Position drops below the item's configured Minimum Stock Level, RMS will automatically generate a Purchase Order or Warehouse Transfer to fill the gap.
6. SQL Deep Dives
Querying the True Inventory Position
This query replicates the internal RMS logic to calculate exactly how many "free and clear" units a location has, taking into account all inbound pipelines and outbound reservations.
Finding Negative Inventory
A major issue in retail is negative inventory, which occurs when a store's POS registers a sale for an item that RMS believes is completely out of stock. This happens due to theft, mis-scans at the register, or unrecorded receipts.
7. Common Gotchas
Important Gotchas
- !
Double-Counting SOH and In-Transit. When a warehouse ships a transfer, the stock is deducted from the warehouse's
STOCK_ON_HANDand added to the store'sIN_TRANSIT_QTY. If the store physically receives the goods but the receiving transaction fails to process in RMS, the store has the physical goods to sell, but RMS still thinks they are in transit. If they sell them, theirSTOCK_ON_HANDwill go negative! - !
Zombie On-Order Quantities. If a PO is approved (
STOCK_ON_ORDERincrements) but the supplier short-ships and the buyer never cancels the remainder of the PO, theSTOCK_ON_ORDERwill stay inflated forever. Replenishment will never re-order the item because it thinks stock is still arriving. - !
Ignoring NON_SELLABLE_QTY. When integrating RMS inventory to an eCommerce storefront, developers often just expose
STOCK_ON_HAND. This results in selling damaged goods or display models to online customers, leading to immediate order cancellations and angry customers. Always subtractNON_SELLABLE_QTYandCUSTOMER_RESVwhen exposing ATP (Available to Promise).
8. Official Oracle Resources
For further reading, consult the official Oracle documentation:


