Oracle RMS Transformable Items
Some items in retail do not arrive in the same form they are sold. A whole fish becomes fillets. A fabric roll becomes cut panels. A bulk bin of mixed sweets becomes individual bags of sorted varieties. Oracle RMS models this reality through item transformations — a formal mechanism for converting input items into output items with defined ratios, cost allocation, and full stock ledger accountability.
What Are Transformable Items?
In Oracle RMS, most items are static — they are received in the same unit they are stocked and sold. A shirt arrives as a shirt, is stocked as a shirt, and is sold as a shirt. The item number never changes from receiving dock to point of sale.
Some items do not work this way. In food retail, a whole salmon is purchased from a supplier but never sold as a whole fish — it is processed into salmon fillets, salmon steaks, and salmon skin-on portions, each with its own item number, its own price, and its own stock position. In textiles, a fabric roll is ordered by the metre and transformed into cut pattern pieces for garment assembly. In confectionery, a bulk sack of mixed sweets is received and repacked into individual 100g bags of sorted varieties.
Oracle RMS handles all of these scenarios through item transformations. A transformation is a formally defined rule that says: consuming a certain quantity of this input item produces certain quantities of these output items, with the input item's cost distributed across the outputs in a specified proportion.
Pack breakdown (covered in the previous article) handles the splitting of a
pre-defined pack into its known components — the structure is fixed in
PACKSKU. Item transformation is a more powerful mechanism: it handles
arbitrary conversion ratios, yield losses (the input quantity consumed may not
equal the total output quantities), and full cost reallocation across outputs.
The two features overlap in some use cases but are architecturally distinct.
See the comparison section at the end of this article.
ITEM_XFORM_IND — The Transformation Flag
The entry point into the transformation system is a single column on ITEM_MASTER: ITEM_XFORM_IND. Setting this to 'Y' on an item marks it as a participant in at least one transformation rule — either as an input item, an output item, or both.
| Column | Type | Description |
|---|---|---|
ITEM_XFORM_IND | VARCHAR2(1) | Y = this item participates in at least one transformation rule. N = standard item, no transformation logic applies. The flag must be 'Y' on both input and output items. |
Both the item being consumed (the input) and every item being produced (the
outputs) must have ITEM_XFORM_IND = 'Y' on their respective
ITEM_MASTER rows. If the flag is missing on any participant, the
transformation rule cannot be saved and any attempt to process a
transformation transaction against that item will fail at validation.
Input Items vs Output Items
Every transformation rule has exactly one input item and one or more output items. These roles are defined in the ITEM_TRANSFORM table, not on ITEM_MASTER — a single item can be an input in one transformation and an output in another.
Since output items are produced internally from the input item, they should
generally have ORDERABLE_IND = 'N' on ITEM_MASTER. This
prevents replenishment batches from raising purchase orders for items that are
never bought directly from a supplier. The only way stock of an output item
increases is through a transformation transaction consuming the corresponding
input item.
The ITEM_TRANSFORM Table Structure
Transformation rules are stored across two related tables in Oracle RMS: ITEM_TRANSFORM_HEAD (the header record for the rule) and ITEM_TRANSFORM_DETAIL (one row per output item in the rule). Some RMS versions also use the simpler ITEM_TRANSFORM table structure — check your instance version, as the schema can vary between RMS 13.x, 14.x, and 16.x.
The header record defines the transformation rule itself — which item is consumed, at what base input quantity, and in which location context the rule applies.
| Column | Type | Description |
|---|---|---|
XFORM_IDPK | NUMBER(10) | System-generated primary key for the transformation rule. |
FROM_ITEMFK | VARCHAR2(25) | The input item — FK → ITEM_MASTER.ITEM. Must have ITEM_XFORM_IND = 'Y'. |
FROM_QTY | NUMBER(12,4) | The base quantity of the input item consumed per transformation run. The ratio base. |
FROM_UOM | VARCHAR2(4) | Unit of measure for FROM_QTY — must match or be convertible to the input item's UOM. |
LOC | NUMBER(10) | Location where this transformation rule applies. NULL = applies at all locations. |
LOC_TYPE | VARCHAR2(1) | 'S' or 'W' — store or warehouse. Required when LOC is populated. |
EFFECTIVE_DATE | DATE | Date from which this transformation rule is active. |
END_DATE | DATE | Date after which this transformation rule is no longer active. NULL = no end date. |
One row per output item produced by the transformation rule. The ratio here defines how many units of this output item are produced per FROM_QTY units of the input item consumed.
| Column | Type | Description |
|---|---|---|
XFORM_IDPKFK | NUMBER(10) | FK → ITEM_TRANSFORM_HEAD.XFORM_ID. |
TO_ITEMPKFK | VARCHAR2(25) | The output item — FK → ITEM_MASTER.ITEM. Must have ITEM_XFORM_IND = 'Y'. |
TO_QTY | NUMBER(12,4) | Quantity of this output item produced per FROM_QTY units of the input consumed. |
TO_UOM | VARCHAR2(4) | Unit of measure for TO_QTY — must match or be convertible to the output item's UOM. |
COST_ALLOC_PCT | NUMBER(12,4) | Percentage of the input item's total cost allocated to this output item. All output rows for a rule must sum to 100. |
Transformation Ratios and Yield
The ratio between FROM_QTY and TO_QTY captures the yield of the transformation — how much output you get from a given input quantity. In ideal transformations the input quantity equals the sum of output quantities. In reality, most physical transformations have waste or yield loss, so the sum of all TO_QTY values will be less than FROM_QTY.
Transformation rule: 1 kg of Whole Salmon (input) produces:
| Output Item | TO_QTY | TO_UOM | COST_ALLOC_PCT | |---|---|---|---| | Salmon Fillet | 0.45 | KG | 60% | | Salmon Steak | 0.25 | KG | 30% | | Salmon Skin-on Portion | 0.15 | KG | 10% |
Total output: 0.85 kg from 1 kg input — 0.15 kg is yield loss (bones, skin, trim).
The yield loss is implicit — the TO_QTY values in ITEM_TRANSFORM_DETAIL simply do not add up to the FROM_QTY. Oracle RMS does not require them to. The cost allocated to the yield loss is absorbed by the cost allocation percentages across the outputs — there is no separate "waste item" entry unless the retailer explicitly models waste as an output item with a zero or near-zero cost allocation.
The COST_ALLOC_PCT values across all ITEM_TRANSFORM_DETAIL
rows for a given XFORM_ID must sum to exactly 100. Oracle RMS
validates this when the transformation rule is saved via the UI. Integration
scripts that insert directly to the table must enforce this constraint
themselves — the database does not always have a check constraint to catch
rounding errors like 99.99 or 100.01.
Cost Allocation Across Output Items
When a transformation is processed, the cost of the input item consumed is distributed to the output items according to the COST_ALLOC_PCT values. This is how Oracle RMS maintains correct cost-of-goods accounting when one purchase becomes multiple sellable products.
The calculation is straightforward:
Cost allocated to output item X = (Input quantity consumed × Input item AV_COST) × (COST_ALLOC_PCT for output X ÷ 100)
This allocated cost becomes the new average cost for each output item at that location, blended into the existing ITEM_LOC_SOH.AV_COST using the standard weighted average cost formula.
Suppose 10 kg of Whole Salmon is transformed. The input item's average cost is ₹400/kg.
- Total input cost consumed: 10 kg × ₹400 = ₹4,000
| Output Item | COST_ALLOC_PCT | Cost Allocated | Units Produced | Implied Cost/Unit | |---|---|---|---|---| | Salmon Fillet (4.5 kg) | 60% | ₹2,400 | 4.5 kg | ₹533.33/kg | | Salmon Steak (2.5 kg) | 30% | ₹1,200 | 2.5 kg | ₹480.00/kg | | Salmon Skin-on (1.5 kg) | 10% | ₹400 | 1.5 kg | ₹266.67/kg |
The allocated costs are then used to update the AV_COST in ITEM_LOC_SOH for each output item at the location where the transformation occurred. If the output items already had existing stock at an existing average cost, the WAC formula blends the new units with the existing position.
The cost allocation percentages are the most business-critical configuration in a transformation rule. If the percentages do not reflect the true commercial value split between output items, the average costs assigned to each output will be wrong. A salmon fillet should carry a higher cost than a skin-on portion because it commands a higher retail price and represents a more valuable yield. Retailers who set equal cost allocation across all outputs will see systematically incorrect margins on every output item for as long as those transformations run.
The Transformation Transaction Workflow
A transformation transaction is the operational event that triggers the actual SOH and cost changes. It can be initiated from the RMS back-office or from a store/warehouse system. The workflow is the same regardless of where it originates.
The operator selects the input item and the applicable transformation rule. RMS validates that the rule is effective (within EFFECTIVE_DATE and END_DATE) and that the input item is ranged at the location with sufficient SOH to support the transformation quantity.
The operator enters the quantity of the input item to be transformed. This must be a positive multiple of FROM_QTY — or FROM_QTY itself for a single run. RMS validates that the input item's SOH at the location is ≥ the specified quantity.
RMS calculates the output quantities automatically from the TO_QTY ratios in ITEM_TRANSFORM_DETAIL. If transforming 5× the base quantity, all output quantities are multiplied by 5. Output quantities are rounded to the output item's precision if they are not whole numbers.
Input item SOH is reduced by the transformation quantity. Each output item's SOH is increased by its calculated output quantity. Both adjustments post to ITEM_LOC_SOH simultaneously in the same transaction.
The input item's cost contribution is calculated and distributed to output items per COST_ALLOC_PCT. Each output item's AV_COST in ITEM_LOC_SOH is recalculated using WAC. Stock ledger entries are created for both the input reduction and each output increase.
Stock Ledger Impact
Every transformation transaction writes to the Oracle RMS stock ledger (STKLEDGR), creating a full audit trail of what was consumed and what was produced. This is essential for inventory accounting, shrinkage analysis, and reconciliation.
For a single transformation transaction, Oracle RMS creates the following stock ledger entries:
| Column | Type | Description |
|---|---|---|
Input item reduction | TRAN_CODE = 'XF' | One ledger entry reducing the input item's SOH and crediting its cost contribution to the transformation. Reason code identifies it as a transformation-out event. |
Output item increases | TRAN_CODE = 'XF' | One ledger entry per output item increasing SOH and debiting the allocated cost. Together these entries balance the transformation financially. |
Net cost movement | Zero net impact | The total cost credited for the input reduction equals the total cost debited across all output increases (COST_ALLOC_PCT sums to 100). The transformation is cost-neutral to the stock ledger overall. |
Because COST_ALLOC_PCT values must sum to 100%, the total cost
removed from the input item's position exactly equals the total cost added to
all output items' positions. A transformation never creates or destroys
financial value in the stock ledger — it only redistributes cost from one
item to others. This makes the stock ledger reconciliation straightforward:
transformation entries should always net to zero across all participants.
Transformation vs Pack Breakdown — Key Differences
Both transformations and pack breakdowns convert one item's stock into another item's stock. Developers new to Oracle RMS often ask when to use each. The distinction is architectural and commercial:
Whether you are processing raw materials into finished goods or selling pre-assembled bundles across Amazon, Flipkart, and your own store, RC:OMS tracks every inventory movement with double-entry accuracy. Every transformation, every channel, one source of truth.
Launch RC:OMS Demo →Key Tables — Quick Reference
Practical SQL Examples
1. All transformation rules for an input item
-- All transformation rules where a given item is the input
-- Shows what outputs are produced and in what ratio
SELECT h.xform_id,
h.from_item,
im_from.item_desc input_desc,
h.from_qty,
h.from_uom,
h.loc,
h.loc_type,
h.effective_date,
h.end_date,
d.to_item,
im_to.item_desc output_desc,
d.to_qty,
d.to_uom,
d.cost_alloc_pct,
-- Implied yield ratio for this output
ROUND(d.to_qty / h.from_qty, 4) yield_ratio
FROM item_transform_head h
JOIN item_transform_detail d ON d.xform_id = h.xform_id
JOIN item_master im_from ON im_from.item = h.from_item
JOIN item_master im_to ON im_to.item = d.to_item
WHERE h.from_item = :v_input_item
AND (h.end_date IS NULL OR h.end_date > SYSDATE)
ORDER BY h.xform_id, d.to_item;2. Transformation rules where an item appears as an output
-- Find which transformation rules produce a given output item
-- Critical check before discontinuing — must handle upstream input items too
SELECT h.xform_id,
h.from_item,
im_from.item_desc input_desc,
im_from.status input_status,
h.from_qty,
d.to_qty,
d.cost_alloc_pct,
h.effective_date,
h.end_date
FROM item_transform_detail d
JOIN item_transform_head h ON h.xform_id = d.xform_id
JOIN item_master im_from ON im_from.item = h.from_item
WHERE d.to_item = :v_output_item
AND (h.end_date IS NULL OR h.end_date > SYSDATE)
ORDER BY h.from_item;3. Validate cost allocation percentages sum to 100 for all active rules
-- Data integrity check — transformation rules where COST_ALLOC_PCT != 100
-- A rule that does not sum to 100 will misallocate cost on every transaction
SELECT h.xform_id,
h.from_item,
im.item_desc input_desc,
SUM(d.cost_alloc_pct) total_alloc_pct,
COUNT(d.to_item) output_count,
CASE
WHEN ABS(SUM(d.cost_alloc_pct) - 100) < 0.01 THEN 'OK'
ELSE 'INVALID — does not sum to 100'
END alloc_status
FROM item_transform_head h
JOIN item_transform_detail d ON d.xform_id = h.xform_id
JOIN item_master im ON im.item = h.from_item
WHERE (h.end_date IS NULL OR h.end_date > SYSDATE)
GROUP BY h.xform_id, h.from_item, im.item_desc
HAVING ABS(SUM(d.cost_alloc_pct) - 100) >= 0.01
ORDER BY h.from_item;4. SOH and cost position across input and output items at a location
-- Current SOH and average cost for all items in a transformation rule at a location
-- Use to monitor transformation pipeline inventory at a specific store or warehouse
SELECT 'INPUT' item_role,
h.from_item item,
im_f.item_desc,
soh_f.stock_on_hand,
soh_f.av_cost,
ROUND(soh_f.stock_on_hand
- soh_f.av_cost, 2) total_cost_value
FROM item_transform_head h
JOIN item_master im_f ON im_f.item = h.from_item
JOIN item_loc_soh soh_f ON soh_f.item = h.from_item
AND soh_f.loc = :v_loc
AND soh_f.loc_type = :v_loc_type
WHERE h.xform_id = :v_xform_id
UNION ALL
SELECT 'OUTPUT' item_role,
d.to_item item,
im_t.item_desc,
soh_t.stock_on_hand,
soh_t.av_cost,
ROUND(soh_t.stock_on_hand
- soh_t.av_cost, 2) total_cost_value
FROM item_transform_detail d
JOIN item_master im_t ON im_t.item = d.to_item
LEFT JOIN item_loc_soh soh_t ON soh_t.item = d.to_item
AND soh_t.loc = :v_loc
AND soh_t.loc_type = :v_loc_type
WHERE d.xform_id = :v_xform_id
ORDER BY item_role DESC, item;
5. PL/SQL — validate a transformation rule before processing a transaction
-- Validate all pre-conditions for processing a transformation at a location
-- Call before any programmatic transformation transaction
FUNCTION validate_transformation (
p_xform_id IN item_transform_head.xform_id%TYPE,
p_loc IN item_transform_head.loc%TYPE,
p_loc_type IN item_transform_head.loc_type%TYPE,
p_xform_qty IN NUMBER -- multiples of FROM_QTY to transform
) RETURN VARCHAR2 IS
l_from_item item_transform_head.from_item%TYPE;
l_from_qty item_transform_head.from_qty%TYPE;
l_soh item_loc_soh.stock_on_hand%TYPE;
l_alloc_sum NUMBER;
l_output_cnt PLS_INTEGER;
l_end_date item_transform_head.end_date%TYPE;
BEGIN
-- 1. Rule must exist and be currently effective
SELECT from_item, from_qty, end_date
INTO l_from_item, l_from_qty, l_end_date
FROM item_transform_head
WHERE xform_id = p_xform_id
AND SYSDATE >= effective_date;
IF l_end_date IS NOT NULL AND l_end_date < SYSDATE THEN
RETURN 'RULE_EXPIRED: end_date ' || TO_CHAR(l_end_date, 'YYYY-MM-DD');
END IF;
-- 2. Input item must have sufficient SOH at this location
SELECT NVL(stock_on_hand, 0) INTO l_soh
FROM item_loc_soh
WHERE item = l_from_item
AND loc = p_loc
AND loc_type = p_loc_type;
IF l_soh < (l_from_qty * p_xform_qty) THEN
RETURN 'INSUFFICIENT_SOH: available=' || l_soh
|| ' required=' || (l_from_qty * p_xform_qty);
END IF;
-- 3. Cost allocation must sum to 100
SELECT SUM(cost_alloc_pct), COUNT(to_item)
INTO l_alloc_sum, l_output_cnt
FROM item_transform_detail
WHERE xform_id = p_xform_id;
IF l_output_cnt = 0 THEN
RETURN 'NO_OUTPUTS: transformation rule has no output items';
END IF;
IF ABS(l_alloc_sum - 100) >= 0.01 THEN
RETURN 'ALLOC_INVALID: cost_alloc_pct sums to ' || l_alloc_sum;
END IF;
RETURN 'OK';
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'RULE_NOT_FOUND: xform_id=' || p_xform_id
|| ' not effective or does not exist';
WHEN OTHERS THEN
RETURN 'ERROR: ' || SQLERRM;
END validate_transformation;
Common Gotchas for Developers
- !
ITEM_XFORM_IND = 'N' on either the input or an output item. The flag must be
'Y'on every item that participates in a transformation — both the item being consumed and every item being produced. A transformation rule that references an item withITEM_XFORM_IND = 'N'cannot be saved via the RMS UI, and a programmatic insert toITEM_TRANSFORM_DETAILfor such an item will fail at transaction processing time even if the insert itself succeeds. - !
COST_ALLOC_PCT not summing to exactly 100 due to rounding. When entering percentages like 33.33%, 33.33%, 33.34% for three outputs, integration scripts that calculate these values programmatically often introduce floating-point rounding errors that leave the sum at 99.99 or 100.01. Oracle RMS validates this at save time in the UI. Direct inserts to
ITEM_TRANSFORM_DETAILmay not be validated until the first transaction is processed — at which point cost allocation produces incorrect results. Always verify the sum before inserting. - !
Setting output items as ORDERABLE_IND = 'Y' when they should never be purchased.
Output items — salmon fillets, cut panels, repacked bags — are produced through transformation, not purchased from suppliers. Setting
ORDERABLE_IND = 'Y'on them allows replenishment to raise purchase orders for items that no supplier actually sells. Always setORDERABLE_IND = 'N'on output items unless there is a deliberate dual-source strategy where the item can be both produced and purchased. - !
Processing a transformation at a location where output items are not ranged.
When a transformation transaction increases the SOH of an output item, the system needs an
ITEM_LOC_SOHrecord to credit the inventory to. If the output item is not ranged at the location (ITEM_LOCrow missing), the transformation will either fail entirely or post the inventory to a location-level holding account, depending on RMS version configuration. Always ensure all output items are ranged at every location where transformations will be processed. - !
Using the same item as both input and output in the same transformation rule.
A transformation where the same item appears in both
FROM_ITEMandTO_ITEMcreates a circular reference — consuming an item to produce itself. This is not a meaningful operation and will produce incorrect SOH and cost results. Oracle RMS may or may not prevent this at the UI level depending on version. Always validate that no item appears on both sides of a transformation rule in integration scripts. - !
Not end-dating expired transformation rules. Active transformation rules with no
END_DATEremain permanently available for selection. When product specifications change — a different portioning method, new output items, revised yield percentages — the old rule must be explicitly end-dated before the new rule is created. Without this, both the old and new rules are presented as valid options, and operators may accidentally process transformations against the outdated ratios and cost allocation percentages. - !
Querying only ITEM_TRANSFORM (the older table name) in mixed-version RMS environments.
Older RMS versions (13.x and earlier) stored transformation rules in a single
ITEM_TRANSFORMtable rather than the head-detail split of newer versions. If your queries useITEM_TRANSFORMand get an ORA-00942, the instance uses the newer schema. If you queryITEM_TRANSFORM_HEADand get ORA-00942, you are on an older version. Always verify the actual table names present in your specific RMS instance before building any transformation-related queries.
Key Takeaways
- ✓ITEM_XFORM_IND = 'Y' must be set on ITEM_MASTER for every item that participates in a transformation — both the input item being consumed and every output item being produced.
- ✓Transformation rules are defined in ITEM_TRANSFORM_HEAD (input item, base quantity, location scope) and ITEM_TRANSFORM_DETAIL (one row per output with TO_QTY ratio and COST_ALLOC_PCT).
- ✓Yield loss is implicit — TO_QTY values across all outputs do not need to sum to FROM_QTY. The difference is the waste or trim that the retailer accepts as part of the processing step.
- ✓COST_ALLOC_PCT values across all ITEM_TRANSFORM_DETAIL rows for a rule must sum to exactly 100. A rule that does not sum to 100 misallocates cost on every transaction it processes.
- ✓Transformations are financially self-balancing: cost removed from the input item equals the total cost added to all output items. Transformation entries in STKLEDGR always net to zero.
- ✓Output items should have ORDERABLE_IND = 'N' — they are produced through transformation, not purchased from suppliers. All output items must also be ranged at any location where transformations will be processed.
- ✓Transformation differs from pack breakdown: transformations support yield loss and explicit cost allocation percentages; pack breakdowns use a fixed component structure in PACKSKU with no yield loss concept.
