Oracle Retail16 min readBy Priyanshu Pandey

Inventory Positions in Oracle RMS

Master Oracle RMS inventory tracking. Understand the vital difference between Physical Stock on Hand (SOH) and the calculated Inventory Position, driven by ITEM_LOC_SOH columns like STOCK_ON_ORDER, IN_TRANSIT, and TSF_RESERVED.

Phase 5 · Inventory Management · Oracle RMS Series

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.

16 min read📅August 8, 2026✍️Priyanshu Pandey📚Oracle RMS Series

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_HAND that 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_QTY increases 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.

Calculate True Inventory Position
sql
SELECT 
    item,
    loc AS location,
    stock_on_hand,
    -- Step 1: Available Physical
    (stock_on_hand - non_sellable_qty) AS available_physical,
    -- Step 2: Total Inbound
    (in_transit_qty + stock_on_order) AS total_inbound,
    -- Step 3: Total Reserved
    (customer_resv + tsf_reserved_qty + rtv_qty) AS total_reserved,
    
    -- Final Calculation: The Inventory Position
    ((stock_on_hand - non_sellable_qty) 
     + (in_transit_qty + stock_on_order) 
     - (customer_resv + tsf_reserved_qty + rtv_qty)) AS inventory_position
FROM item_loc_soh
WHERE item = '10012345'
  AND loc = 200;

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.

Identify items with negative stock on hand
sql
SELECT 
    item,
    loc AS location,
    stock_on_hand,
    last_update_datetime
FROM item_loc_soh
WHERE stock_on_hand < 0
ORDER BY stock_on_hand ASC;

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_HAND and added to the store's IN_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, their STOCK_ON_HAND will go negative!

  • !

    Zombie On-Order Quantities. If a PO is approved (STOCK_ON_ORDER increments) but the supplier short-ships and the buyer never cancels the remainder of the PO, the STOCK_ON_ORDER will 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 subtract NON_SELLABLE_QTY and CUSTOMER_RESV when exposing ATP (Available to Promise).

8. Official Oracle Resources

For further reading, consult the official Oracle documentation:

RetailCoder
All systems operational
v1.0 Live

RC:OMS

Multi-channel order management with double-entry inventory ledger. Amazon, Flipkart, Shopify, WooCommerce — one source of truth.

Launch demo →
v1.0 Live

RC:Storefront

Self-hosted headless e-commerce. Your server, your data, zero transaction fees. Native RC:OMS inventory sync.

Visit Storefront →
Pipeline

RC:Pulse

AI-powered retail analytics and demand forecasting — built natively on top of your RC:OMS and Storefront data.

Request early access →
Built in India 🇮🇳  ·  Architected by Priyanshu PandeyTalk to an engineer →