Currencies, Exchange Rates & VAT Regions
Oracle RMS is built for multi-currency retail from the ground up. Understanding how currency conversion, exchange rate types, and VAT regions work at the database level is essential for any developer working on purchasing, costing, or finance integrations.
How RMS Handles Multi-Currency
Oracle RMS is designed from the ground up to operate across multiple currencies. Every monetary value in the system — supplier costs, retail prices, order totals, stock ledger entries — is stored alongside a currency code, and the system maintains a complete exchange rate history to convert between them.
At the top of every financial transaction in RMS sits the concept of the primary currency — the currency in which the retailer's books are kept and to which all other monetary values eventually convert. The primary currency is set in SYSTEM_OPTIONS and cannot be changed after go-live without a full data migration.
Below the primary currency, RMS supports three scenarios:
- Single-currency operations — the vast majority of Indian retailers. Everything from suppliers to stores uses INR.
- Multi-currency purchasing — the retailer buys from international suppliers in USD, EUR, or GBP, but sells in INR. RMS converts costs at the point of PO creation using the configured exchange rate type.
- Multi-currency retail — full multi-currency operations including different retail prices in different currencies, typically for cross-border or franchise scenarios.
Currency codes follow ISO 4217
Every currency in RMS is identified by its three-letter ISO 4217 code — INR for Indian Rupee, USD for US Dollar, EUR for Euro. These codes are used as primary and foreign keys throughout the schema. Always store and pass currency codes in uppercase.
The CURRENCIES Table — Currency Master
The CURRENCIES table is the master list of all currencies the RMS instance recognises. A currency must exist here before it can be referenced anywhere else in the system — on suppliers, locations, exchange rates, or price zones.
The CURRENCY_CODE is the primary key and is the value referenced as a foreign key across the entire schema. The DECIMALS_USED column is critical — it determines how monetary values for this currency are rounded and displayed throughout the system. Setting this incorrectly at setup causes rounding drift across cost and retail calculations.
| Column | Type | Description |
|---|---|---|
CURRENCY_CODEPK | VARCHAR2(3) | ISO 4217 three-letter currency code (INR, USD, EUR, GBP) |
CURRENCY_DESC | VARCHAR2(120) | Full currency name (e.g. 'Indian Rupee') |
DECIMALS_USED | NUMBER(1) | Number of decimal places for this currency. 2 for INR/USD, 0 for JPY |
CURRENCY_FORMAT | VARCHAR2(30) | Display format mask used by the RMS UI (e.g. '999G999G990D00') |
STATUS | VARCHAR2(1) | A = Active. Inactive currencies cannot be used on new transactions. |
Exchange Rate Types — Operational vs Buy vs Sell
Oracle RMS does not use a single exchange rate. It maintains three separate rate types that serve different business purposes. Understanding which rate type is used where is essential for any developer working on purchasing or finance integrations.
| Column | Type | Description |
|---|---|---|
Operational | 'O' | Retail price conversion, internal cost calculations, stock ledger valuation |
Buying | 'B' | Purchase order cost conversion at time of PO creation |
Selling | 'S' | Sales audit and revenue conversion for multi-currency stores |
PO cost conversion uses the Buying rate, not Operational
A very common integration mistake: when converting a supplier's USD cost to
your primary currency for display or calculation, developers often use the
Operational rate. But Oracle RMS uses the Buying rate (RATE_TYPE =
'B') at PO creation time. Using the wrong rate type causes PO cost
discrepancies that are hard to trace after the fact.
CURRENCY_RATES — The Daily Rate Feed
Exchange rates in RMS are date-effective. Every day's rate for every currency pair is stored as a separate row in CURRENCY_RATES, creating a full history. The batch job CURRCONV is responsible for loading new exchange rates into this table — it's one of the most critical foundation batches that must run before any purchasing activities.
The composite primary key is FROM_CURRENCY + TO_CURRENCY + RATE_DATE + RATE_TYPE. To get the rate in effect for a given date, query with the date range condition shown in the SQL examples below — RMS uses the most recent rate on or before the transaction date.
| Column | Type | Description |
|---|---|---|
FROM_CURRENCYPKFK | VARCHAR2(3) | Source currency code — FK → CURRENCIES |
TO_CURRENCYPKFK | VARCHAR2(3) | Target currency code — FK → CURRENCIES |
RATE_DATEPK | DATE | Effective date of this exchange rate |
RATE_TYPEPK | VARCHAR2(1) | O = Operational · B = Buying · S = Selling |
CONVERSION_RATE | NUMBER(20,10) | Units of TO_CURRENCY per 1 unit of FROM_CURRENCY |
CURRCONV batch must run before purchasing
The CURRCONV batch job loads exchange rates from your source system
(ERP, treasury management, or a manual feed) into CURRENCY_RATES.
If this batch hasn't run, any PO raised in a foreign currency will fail
validation — RMS cannot calculate the primary currency equivalent cost
without a valid rate. Always check CURRENCY_RATES has today's rates before
investigating PO creation failures.
Primary Currency & Cost Conversion Flow
Understanding exactly how RMS converts costs when a PO is created against a foreign-currency supplier is important for both developers and finance teams. The conversion follows a strict chain:
- Supplier cost is stored in
ITEM_SUPPLIER.UNIT_COSTin the supplier's currency (SUPS.CURRENCY_CODE) - At PO creation, RMS looks up
CURRENCY_RATESforFROM_CURRENCY = supplier_currency,TO_CURRENCY = primary_currency,RATE_TYPE = 'B', with the effective date ≤ the PO's order date - The converted cost is stored on
ORDLOC.UNIT_COSTin the primary currency - All stock ledger entries use the primary currency cost
RC:OMS handles currency-aware inventory costing natively — every stock receipt is valued in your primary currency regardless of the supplier's billing currency. Connect Amazon Global, Flipkart, and your own Storefront into one unified ledger.
Explore RC:OMS →VAT Regions — How Tax Geography Works in RMS
In Oracle RMS, tax is not calculated at the item level in isolation. Tax is determined by the intersection of where the item is sold (the VAT Region) and what the item is (the VAT Code on the item's Department or the item itself). This two-axis model allows a single item to be taxed differently in different states or countries.
A VAT Region is a geographic grouping — it could be a country, a state, a tax jurisdiction, or any other geographic boundary that has its own tax rules. In India, for example, you might have a VAT Region per GST state code, or a single national VAT Region if you operate a simplified tax structure.
Every Store and Warehouse in RMS has a VAT_REGION column that links it to its applicable tax region. This drives which VAT rates apply when items are sold from or transferred to that location.
| Column | Type | Description |
|---|---|---|
VAT_REGIONPK | NUMBER(4) | Unique VAT region identifier |
VAT_REGION_NAME | VARCHAR2(120) | Descriptive name (e.g. 'India — GST Standard', 'Maharashtra') |
COUNTRY_ID | VARCHAR2(3) | ISO country code this VAT region belongs to |
DEFAULT_TAX_TYPE | VARCHAR2(6) | Default tax calculation method for items without a specific VAT code |
VAT Codes & the Tax Calculation Chain
VAT Codes define the actual tax rates and calculation methods. They link to VAT Regions via the VAT_CODE_RATES table, which stores the actual percentage for each VAT Code within each VAT Region. This allows the same VAT Code (e.g., "Standard Rate") to map to 18% in one region and 12% in another.
| Column | Type | Description |
|---|---|---|
VAT_CODEPK | VARCHAR2(6) | Unique VAT code identifier |
VAT_CODE_DESC | VARCHAR2(120) | Human-readable description (e.g. 'GST 18%', 'GST Exempt') |
INCL_IN_COST_IND | VARCHAR2(1) | Y = Tax is included in cost price (tax-inclusive costing) |
INCL_IN_RETAIL_IND | VARCHAR2(1) | Y = Tax is included in retail price (MRP-inclusive model, common in India) |
India GST — INCL_IN_RETAIL_IND is typically Y
Indian retail pricing is almost always MRP-inclusive (Maximum Retail Price
includes GST). This means INCL_IN_RETAIL_IND = 'Y' for most Indian
RMS deployments. When this is set, RMS backs the tax out of the retail price
for ledger valuation rather than adding it on top. Misunderstanding this
setting causes the most common margin calculation errors in Indian RMS go-lives.
Key Tables — Quick Reference
Practical SQL Examples
1. Get the current Buying rate for a currency pair
2. Convert a supplier cost to primary currency
3. VAT rate applicable at a store for an item's department
4. PL/SQL — validate currency rates exist for today before batch
Common Gotchas for Developers
Important Gotchas
- !
Using Operational rate instead of Buying rate for PO costs. RMS uses
RATE_TYPE = 'B'(Buying) for purchase order cost conversion. Using'O'(Operational) gives a different number. This discrepancy is invisible in single-rate setups but breaks immediately when your treasury feeds different buy/sell/operational rates. - !
Not handling the "latest rate on or before date" pattern. Exchange rates in
CURRENCY_RATESare effective-dated. A simpleWHERE RATE_DATE = TRUNC(SYSDATE)will return zero rows on weekends and holidays when no rate feed runs. Always use the MAX subquery pattern to get the most recent rate on or before the transaction date. - !
Confusing INCL_IN_RETAIL_IND with INCL_IN_COST_IND. In India, retail prices are MRP-inclusive (INCL_IN_RETAIL = Y), but costs from suppliers are typically exclusive (INCL_IN_COST = N). Getting these backwards causes all margin calculations to be wrong — and the error only surfaces when comparing cost and retail in reporting.
- !
Setting DECIMALS_USED incorrectly at currency setup. Once transactions exist in the system using a currency, changing
DECIMALS_USEDis a data migration, not a config change. Setting 2 decimals for JPY (which uses 0) or vice versa causes systemic rounding errors across all cost and retail calculations. Audit this at setup time. - !
Forgetting that VAT_CODE is on DEPS, not ITEM_MASTER. Individual items inherit their VAT treatment from their Department's
VAT_CODE. Items can have their own VAT code override, but the default is always at Department level. Queries that look for VAT code onITEM_MASTERwithout a fallback toDEPSwill miss the vast majority of items.
Key Takeaways
Key Takeaways
- The CURRENCIES table is the master list of all recognised currencies. DECIMALS_USED must be set correctly at setup and cannot easily be changed post-go-live.
- CURRENCY_RATES stores date-effective exchange rates with three types: O (Operational), B (Buying), S (Selling). PO cost conversion uses the Buying rate.
- Always use the MAX(RATE_DATE) subquery pattern to retrieve exchange rates — never filter by RATE_DATE = SYSDATE directly.
- VAT in RMS is determined by two axes: the VAT Region (where the item is sold) and the VAT Code (what the item is). The intersection in VAT_CODE_RATES gives the actual tax rate.
- In India, INCL_IN_RETAIL_IND = 'Y' is the norm (MRP-inclusive pricing). RMS backs tax out of the retail price rather than adding it on top.
- The CURRCONV batch must run successfully before any purchasing activity. Always validate CURRENCY_RATES has today's rates before running PO-related batches.


