Oracle RMS Item Locations — Ranging, De-ranging & Ranging Rules
An Active item in Oracle RMS is not automatically available everywhere. It must be explicitly ranged to every store and warehouse where it needs to be sold, stocked, or ordered. Ranging creates the ITEM_LOC record that makes an item operationally real at a location — and de-ranging reverses that, with consequences that ripple across replenishment, transfers, and purchasing.
What Is Ranging?
Ranging is the act of formally assigning an item to a location in Oracle RMS. Until a row exists in ITEM_LOC for a specific item-location combination, that item does not exist at that location from the system's perspective. It cannot be ordered to that location, cannot receive stock there, cannot be sold there, and cannot appear on a stock count.
Ranging is the bridge between the item catalog and retail operations. An item may be fully set up in ITEM_MASTER, have a supplier in ITEM_SUPPLIER, and be Active — but none of that makes it available at any particular store or warehouse. Only an ITEM_LOC row does that.
This design is intentional. Different stores carry different ranges. A fashion retailer's flagship store carries the full range including premium lines; a smaller format store carries only core basics. Warehouse ranging is also explicit — an item must be ranged to a warehouse before that warehouse can be used as a replenishment source for stores carrying the item.
When an item is ranged to a location, Oracle RMS creates two records
simultaneously: the ITEM_LOC row (the configuration — retail price,
primary supplier, order multiples) and a companion ITEM_LOC_SOH row
initialised with zero stock on hand. Both must exist for the item to be fully
operational at that location.
The ITEM_LOC Table — Deep Dive
ITEM_LOC is one of the most-referenced tables in Oracle RMS. Its composite primary key of ITEM + LOC + LOC_TYPE is the pairing that almost every inventory and purchasing query joins on. The table carries far more than just a linking record — it holds the operational configuration of the item at that specific location.
| Column | Type | Description |
|---|---|---|
ITEMPKFK | VARCHAR2(25) | FK → ITEM_MASTER.ITEM. Always VARCHAR2 — never cast to NUMBER. |
LOCPK | NUMBER(10) | Location number. Either STORE.STORE or WH.WH depending on LOC_TYPE. |
LOC_TYPEPK | VARCHAR2(1) | 'S' = store · 'W' = warehouse. Always filter on both LOC and LOC_TYPE together. |
STATUS | VARCHAR2(1) | A = Active (fully operational) · I = Inactive (no new orders, may hold stock). |
UNIT_RETAIL | NUMBER(20,4) | Current selling retail price at this location. Can differ by location if price zones apply. |
SELLING_UNIT_RETAIL | NUMBER(20,4) | Retail price per selling unit. Differs from UNIT_RETAIL for catch-weight or variable-measure items. |
PRIMARY_SUPPFK | NUMBER(10) | FK → SUPS.SUPPLIER. Default replenishment supplier for this specific location. Can differ from the global primary on ITEM_SUPPLIER. |
PRIMARY_CNTRY | VARCHAR2(3) | Default country of origin for replenishment at this location. |
STORE_ORD_MULT | NUMBER(12,4) | Minimum and rounding quantity for store replenishment orders. Must be a positive multiple of INNER_PACK_SIZE. |
AUTO_APPR_IND | VARCHAR2(1) | Y = purchase orders for this item at this location are automatically approved. N = manual approval required. |
TAXABLE_IND | VARCHAR2(1) | Y = item is taxable at this location (location-level override of item's default tax status). |
LOCAL_ITEM_DESC | VARCHAR2(250) | Location-specific description override. Used when a store displays the item under a different name. |
TI | NUMBER(12,4) | Tier quantity — units per layer on a pallet. Used in warehouse space planning and full-pallet ordering. |
HI | NUMBER(12,4) | High quantity — number of layers per pallet. Used with TI for full-pallet replenishment calculations. |
MEAS_OF_EACH | NUMBER(12,4) | Average weight or measure per unit for catch-weight items (e.g. average kg per fish). NULL for fixed-unit items. |
CAPTURE_DATE | DATE | Date this item was first ranged to this location. Audit field. |
The Ranging Workflow — What Happens Step by Step
Only Active items can be ranged to locations. A Candidate item cannot be ranged — the RMS application blocks it. Direct SQL inserts to ITEM_LOC for a Candidate item will bypass this check but produce a location record that the application cannot fully process.
The ranging operation targets one or more locations — a single store, a set of stores by district or region, a warehouse, or a combination. The LOC_TYPE is set to 'S' for stores and 'W' for warehouses.
The unit retail price, primary supplier, STORE_ORD_MULT, and AUTO_APPR_IND are set. Most of these default from the item's existing configuration — UNIT_RETAIL from the price zone, PRIMARY_SUPP from ITEM_SUPPLIER, STORE_ORD_MULT from INNER_PACK_SIZE — but can be overridden per location.
The ITEM_LOC row is inserted with STATUS = 'A'. The item is now considered ranged and operational at that location. CAPTURE_DATE is set to SYSDATE.
Oracle RMS automatically creates the companion ITEM_LOC_SOH row with STOCK_ON_HAND = 0 and AV_COST = 0. No manual insert is needed. The item now has a stock position at the location — initially zero, ready to receive stock via purchase order receipts, transfers, or inventory adjustments.
ITEM_LOC Status Values
The STATUS column on ITEM_LOC controls what operations are permitted for an item at that location. It is independent of ITEM_MASTER.STATUS — an Active item can have an Inactive ranging record at a specific location, and that is a perfectly valid configuration.
The item is fully operational at this location. It can be ordered on purchase orders, receive stock, be sold, be transferred, appear on stock counts, and be replenished automatically. The vast majority of ranged items should have STATUS = 'A'. When filtering for items available to sell at a location, always include AND il.status = 'A'.
The item exists at this location and may hold stock, but it cannot receive new purchase orders or be replenished automatically. Existing stock can still be sold and transferred out. Inactive is the transitional status used when a location is being run down on an item before full de-ranging — stock is cleared through sales while new orders are blocked.
Setting STATUS = 'I' is a deliberate holding pattern. It stops new
stock flowing in while allowing existing stock to sell through. Once
STOCK_ON_HAND reaches zero and all open orders are closed, the item
can be de-ranged properly. Leaving items permanently in Inactive status
accumulates "ghost" location records that slow down replenishment batch
processing and confuse location-level reporting.
AUTO_APPR_IND — The Ordering Gate
AUTO_APPR_IND on ITEM_LOC controls whether purchase orders for this item at this location are automatically approved or require manual buyer sign-off.
When AUTO_APPR_IND = 'Y', replenishment-generated purchase orders for this item-location combination are created in Approved status and flow directly through to the supplier. When AUTO_APPR_IND = 'N', the PO is created in Worksheet status and sits in a buyer's approval queue until manually approved.
| Column | Type | Description |
|---|---|---|
AUTO_APPR_IND = 'Y' | Replenishment POs are auto-approved and transmitted to suppliers without buyer intervention. Standard for core range items with stable demand. | |
AUTO_APPR_IND = 'N' | Replenishment POs require manual buyer approval before transmission. Used for high-value items, new suppliers, or items with unpredictable demand. |
Setting AUTO_APPR_IND = 'N' does not prevent the replenishment
engine from generating a purchase order. It still generates the PO and places
it in Worksheet status. If the buyer's queue is not monitored and approved
regularly, orders will pile up unapproved while the store runs out of stock.
This is a common source of unexplained stockouts at go-live.
Ranging Rules — Ranging Multiple Locations at Once
Manually creating individual ITEM_LOC rows for each location is only practical for small ranges. When an item needs to go live across dozens or hundreds of stores simultaneously, Oracle RMS provides ranging rules — configurable criteria that define which locations an item should be ranged to, with what default attributes.
Ranging rules operate on the organisational hierarchy. A buyer defines a rule that says: range this item to all Active stores in District 5 with STORE_ORD_MULT = 6 and AUTO_APPR_IND = 'Y'. The RMS application — or a batch process — then executes the rule and creates the ITEM_LOC rows for every qualifying location.
RMS allows ranging rules to target any level of the organisational hierarchy. The rule cascades downward to all locations beneath the target level that match the active status criteria.
| Column | Type | Description |
|---|---|---|
Chain level | Broadest scope | All active stores in the chain are ranged. Used for national launches of core items. |
Area level | Geographic region | All active stores in the area are ranged. Used for regional launches or zone pricing strategies. |
Region / District level | Operational grouping | Stores managed by a specific district or regional team. Common for test launches before national rollout. |
Individual store / warehouse | Most specific | Targeted ranging to a specific location. Used for flagship exclusives, local-only products, or warehouse-only items. |
When a ranging rule creates ITEM_LOC rows, it needs to populate all the required columns. Most values default from existing item configuration:
| Column | Type | Description |
|---|---|---|
UNIT_RETAIL | From price zone | Derived from the location's price zone assignment and the item's current pricing. Can be overridden per store if differential pricing is configured. |
PRIMARY_SUPP | From ITEM_SUPPLIER | Defaults from the item's PRIMARY_SUPP_IND = 'Y' row on ITEM_SUPPLIER. Can be overridden per location if a different supplier services that region. |
STORE_ORD_MULT | From ITEM_SUPPLIER | Defaults from ITEM_SUPPLIER.INNER_PACK_SIZE for the primary supplier. Must be reviewed — the default is not always appropriate for every store format. |
AUTO_APPR_IND | From system config | Defaults from a system-level setting or the item's configuration. Should be reviewed before activating replenishment for new ranges. |
TI / HI | From item or supplier | Pallet dimensions default from the item or supplier configuration. Important for warehouse locations where pallet-level ordering is used. |
De-ranging — Pre-conditions and Consequences
De-ranging removes an item from a location — it deletes or inactivates the ITEM_LOC row and its companion ITEM_LOC_SOH. Once de-ranged, the item no longer exists at that location from RMS's perspective: no ordering, no receiving, no selling, no stock counts.
De-ranging cannot happen arbitrarily. Oracle RMS enforces pre-conditions that must all be satisfied before a location record can be removed:
| Column | Type | Description |
|---|---|---|
STOCK_ON_HAND = 0 | Hard block | The item must have zero stock on hand at the location. Any positive SOH in ITEM_LOC_SOH prevents de-ranging. The stock must be sold, transferred, or adjusted to zero first. |
No open purchase orders | Hard block | No ORDLOC rows with open status (Worksheet, Submitted, Approved) referencing this item at this location. Open POs must be cancelled or received first. |
No pending transfers | Hard block | No open inbound or outbound transfer lines (TSFDETAIL) for this item at this location. Pending transfers must be completed or cancelled. |
No open stock count | Hard block | No active stock count worksheet (SCOUNT_DETAIL) referencing this item at this location. The count must be completed or cancelled before de-ranging. |
De-ranging removes the ITEM_LOC and ITEM_LOC_SOH records for an item at a location. It does not delete the historical stock ledger entries, historical sales records, or closed purchase order lines that referenced this item at this location. Those historical records remain in the database and are still queryable. This is by design — de-ranging is an operational action, not a data purge.
The recommended sequence before de-ranging is always:
- Set
ITEM_LOC.STATUS = 'I'to stop new orders - Let existing stock sell through to zero
- Cancel or receive any open purchase orders
- Complete or cancel any pending transfers
- Complete any open stock counts
- Confirm
ITEM_LOC_SOH.STOCK_ON_HAND = 0 - Process the de-ranging
ITEM_LOC_SOH — The Companion Record
ITEM_LOC_SOH is automatically created by Oracle RMS when an item is ranged to a location. It is the stock position record for that item at that location and is the primary source for all inventory queries.
| Column | Type | Description |
|---|---|---|
ITEMPKFK | VARCHAR2(25) | FK → ITEM_MASTER.ITEM. Composite PK with LOC and LOC_TYPE. |
LOCPK | NUMBER(10) | Location number — matches ITEM_LOC.LOC. |
LOC_TYPEPK | VARCHAR2(1) | 'S' or 'W'. Must always be filtered alongside LOC. |
STOCK_ON_HAND | NUMBER(12,4) | Current on-hand quantity at this location. Initialised to 0 at ranging. Updated by receipts, sales, adjustments, transfers. |
STOCK_ON_ORDER | NUMBER(12,4) | Quantity on open purchase orders not yet received at this location. Updated when PO lines are created and cleared on receipt. |
IN_TRANSIT_QTY | NUMBER(12,4) | Quantity dispatched from a warehouse but not yet received at the destination store. Cleared on receipt confirmation. |
HELD_QTY | NUMBER(12,4) | Quantity reserved or held — for example, items quarantined pending quality inspection. |
AV_COST | NUMBER(20,4) | Weighted average cost per unit at this location. Recalculated on every receipt using the WAC formula. Initialised to 0 at ranging. |
UNIT_RETAIL | NUMBER(20,4) | Current retail price mirrored from ITEM_LOC. Kept in sync for performance — avoids joining to ITEM_LOC in every SOH query. |
RC:OMS applies the same item-to-channel ranging logic as Oracle RMS to modern multi-channel selling. Every item ranged to every channel with real-time stock sync — no overselling, no ghost listings. Built for Indian multi-channel retailers.
Launch RC:OMS Demo →Key Tables — Quick Reference
Practical SQL Examples
1. Full ranging status for an item across all locations
-- Complete ranging snapshot for one item — all stores and warehouses
SELECT il.loc,
il.loc_type,
CASE il.loc_type
WHEN 'S' THEN s.store_name
WHEN 'W' THEN w.wh_name
END loc_name,
il.status ranging_status,
il.unit_retail,
il.primary_supp,
il.store_ord_mult,
il.auto_appr_ind,
ils.stock_on_hand,
ils.stock_on_order,
ils.in_transit_qty,
ils.av_cost,
il.capture_date
FROM item_loc il
LEFT JOIN store s ON s.store = il.loc AND il.loc_type = 'S'
LEFT JOIN wh w ON w.wh = il.loc AND il.loc_type = 'W'
LEFT JOIN item_loc_soh ils ON ils.item = il.item
AND ils.loc = il.loc
AND ils.loc_type = il.loc_type
WHERE il.item = :v_item
ORDER BY il.loc_type, loc_name;2. Items ranged to a store but with zero SOH and no open orders — de-ranging candidates
-- Items safe to de-range from a specific location
-- Zero SOH, no open PO lines, no pending transfers
SELECT il.item,
im.item_desc,
il.status,
ils.stock_on_hand,
ils.stock_on_order,
ils.in_transit_qty,
il.capture_date
FROM item_loc il
JOIN item_master im ON im.item = il.item
JOIN item_loc_soh ils ON ils.item = il.item
AND ils.loc = il.loc
AND ils.loc_type = il.loc_type
WHERE il.loc = :v_loc
AND il.loc_type = :v_loc_type
AND il.status = 'I' -- already set to Inactive
AND ils.stock_on_hand = 0
AND ils.stock_on_order = 0
AND ils.in_transit_qty = 0
AND NOT EXISTS ( -- no open transfer lines
SELECT 1 FROM tsfdetail td
JOIN tsfhead th ON th.tsf_no = td.tsf_no
WHERE (td.from_loc = il.loc OR td.to_loc = il.loc)
AND td.item = il.item
AND th.status NOT IN ('C', 'R') -- not Closed or Received
)
ORDER BY im.item_desc;3. Unranged Active items — items with no location records at all
-- Active transaction-level items that have never been ranged anywhere
-- Common data quality issue after bulk item creation without a ranging step
SELECT im.item,
im.item_desc,
im.dept,
dp.dept_name,
im.status,
im.item_level,
im.tran_level
FROM item_master im
JOIN deps dp ON dp.dept = im.dept
WHERE im.status = 'A'
AND im.item_level = im.tran_level -- transaction items only
AND NOT EXISTS (
SELECT 1 FROM item_loc il
WHERE il.item = im.item
)
ORDER BY dp.dept_name, im.item_desc;4. Active items ranged to stores but missing from the supplying warehouse
-- Items ranged to stores but not ranged to their store's DEFAULT_WH
-- These items cannot be replenished because the warehouse has no ranging record
SELECT il.item,
im.item_desc,
il.loc store_no,
s.store_name,
s.default_wh,
w.wh_name default_wh_name
FROM item_loc il
JOIN item_master im ON im.item = il.item
JOIN store s ON s.store = il.loc
JOIN wh w ON w.wh = s.default_wh
WHERE il.loc_type = 'S'
AND il.status = 'A'
AND im.status = 'A'
AND s.default_wh IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM item_loc il_wh
WHERE il_wh.item = il.item
AND il_wh.loc = s.default_wh
AND il_wh.loc_type = 'W'
)
ORDER BY il.item, s.store_name;5. PL/SQL — validate de-ranging pre-conditions for an item at a location
-- Returns 'OK' or a description of the blocking condition
-- Run before any programmatic de-ranging to avoid partial failures
FUNCTION can_derange (
p_item IN item_loc.item%TYPE,
p_loc IN item_loc.loc%TYPE,
p_loc_type IN item_loc.loc_type%TYPE
) RETURN VARCHAR2 IS
l_soh NUMBER;
l_on_order NUMBER;
l_in_transit NUMBER;
l_open_tsf PLS_INTEGER;
l_open_count PLS_INTEGER;
BEGIN
-- 1. Check SOH, on-order, and in-transit quantities
SELECT NVL(stock_on_hand, 0),
NVL(stock_on_order, 0),
NVL(in_transit_qty, 0)
INTO l_soh, l_on_order, l_in_transit
FROM item_loc_soh
WHERE item = p_item
AND loc = p_loc
AND loc_type = p_loc_type;
IF l_soh > 0 THEN
RETURN 'BLOCKED: STOCK_ON_HAND = ' || l_soh || ' — must be zero';
END IF;
IF l_on_order > 0 THEN
RETURN 'BLOCKED: STOCK_ON_ORDER = ' || l_on_order
|| ' — close or receive open POs first';
END IF;
IF l_in_transit > 0 THEN
RETURN 'BLOCKED: IN_TRANSIT_QTY = ' || l_in_transit
|| ' — receive pending transfers first';
END IF;
-- 2. No open transfer lines
SELECT COUNT(1) INTO l_open_tsf
FROM tsfdetail td
JOIN tsfhead th ON th.tsf_no = td.tsf_no
WHERE td.item = p_item
AND (td.from_loc = p_loc OR td.to_loc = p_loc)
AND th.status NOT IN ('C', 'R');
IF l_open_tsf > 0 THEN
RETURN 'BLOCKED: ' || l_open_tsf
|| ' open transfer line(s) — complete or cancel first';
END IF;
-- 3. No active stock count
SELECT COUNT(1) INTO l_open_count
FROM scount_detail sc
JOIN scount_head sh ON sh.count_id = sc.count_id
WHERE sc.item = p_item
AND sc.loc = p_loc
AND sc.loc_type = p_loc_type
AND sh.status NOT IN ('C');
IF l_open_count > 0 THEN
RETURN 'BLOCKED: open stock count — complete or cancel first';
END IF;
RETURN 'OK';
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'NOT_RANGED: no ITEM_LOC_SOH record found for this location';
WHEN OTHERS THEN
RETURN 'ERROR: ' || SQLERRM;
END can_derange;
Common Gotchas for Developers
- !
Ranging an item to a store but not to its DEFAULT_WH. When a store has a
DEFAULT_WHconfigured on theSTOREtable, replenishment orders for items at that store are raised to that warehouse. If the item is not also ranged to the warehouse (noITEM_LOCrow withLOC_TYPE = 'W'), the replenishment batch cannot create anORDLOCline for the warehouse leg. The store will never receive replenishment stock even if its SOH drops below the reorder point. Always range to both store and supplying warehouse simultaneously. - !
Setting STORE_ORD_MULT to zero or NULL. The
STORE_ORD_MULTcolumn defines the minimum order quantity for replenishment. A zero or NULL value causes the replenishment batch to either skip the item entirely or generate a zero-quantity order — both of which look like silent success but result in no stock being ordered. Default it to at leastITEM_SUPPLIER.INNER_PACK_SIZEfor every ranged location. - !
Querying ITEM_LOC without LOC_TYPE and getting double results.
Store number 1000 and Warehouse number 1000 are different locations that share the same
LOCvalue. QueryingWHERE item = :x AND loc = 1000withoutAND loc_type = 'S'returns rows for both. This is the most common silent data bug in RMS reporting queries — it inflates item counts, SOH totals, and order quantities by appearing to add a duplicate location. - !
Assuming ITEM_LOC_SOH always exists when ITEM_LOC does. In a standard RMS instance, creating an
ITEM_LOCrow triggers the automatic creation of the companionITEM_LOC_SOHrow. However, in some direct SQL migration scenarios or older implementations, the SOH row may be missing. Any query that does an INNER JOIN betweenITEM_LOCandITEM_LOC_SOHwill silently drop those locations from results. Use LEFT JOIN and check for NULL SOH values in reporting logic. - !
De-ranging without first setting STATUS = 'I' to drain stock. Attempting to de-range an item that still has open orders or positive SOH will fail. The correct sequence is always: Inactive → run down stock → clear orders → de-range. Skipping directly to de-range on an Active item with stock produces a hard error in the UI and, in direct SQL scenarios, a constraint violation or partial delete that leaves orphaned
ITEM_LOC_SOHrecords without their parentITEM_LOCrow. - !
Ranging to a Virtual Warehouse and then wondering why replenishment fails.
Virtual Warehouses (
WH_TYPE = 'VA') are logical subdivisions of a Physical Warehouse. In most RMS configurations, purchase orders are raised against Physical Warehouses. Ranging an item exclusively to a Virtual WH and setting the store'sDEFAULT_WHto that Virtual WH means replenishment order generation will fail — or succeed but create PO lines that the supplier's EDI system cannot process against a logical warehouse that does not physically exist. - !
Using LOCAL_ITEM_DESC for all locations instead of ITEM_DESC.
ITEM_LOC.LOCAL_ITEM_DESCis intended for location-specific description overrides — a different product name used by a particular store. Some integrations incorrectly populate this field for every location as a shortcut to avoid theITEM_DESCtable join. This creates maintenance overhead: whenever the master description changes inITEM_DESC, theLOCAL_ITEM_DESCoverrides across hundreds of location records must also be updated manually.
Key Takeaways
- ✓Ranging creates the ITEM_LOC record that makes an item operational at a location. Without it, an Active item cannot be ordered, stocked, sold, or replenished at that location regardless of its ITEM_MASTER status.
- ✓Ranging always creates two records simultaneously: ITEM_LOC (configuration) and ITEM_LOC_SOH (stock position, initialised to zero). Both must exist for the item to be fully functional at the location.
- ✓Always filter on both LOC and LOC_TYPE together. Store 1000 and Warehouse 1000 share the same LOC value — LOC_TYPE = 'S' vs 'W' is the only discriminator.
- ✓Range items to both the store and the store's DEFAULT_WH simultaneously. A store-ranged item without a warehouse ranging record cannot be replenished from that warehouse.
- ✓STORE_ORD_MULT must be a positive non-zero value. A zero or NULL STORE_ORD_MULT causes replenishment to skip the item silently.
- ✓De-ranging requires: zero STOCK_ON_HAND, zero STOCK_ON_ORDER, zero IN_TRANSIT_QTY, no open transfer lines, no active stock counts. The correct sequence is Inactive → drain stock → clear orders → de-range.
- ✓Ranging rules allow bulk ranging across hierarchy levels (chain, area, region, district). Default attribute values on ITEM_LOC are inherited from price zones, ITEM_SUPPLIER, and system configuration — always review STORE_ORD_MULT and AUTO_APPR_IND after bulk ranging.
