William A. Green Oracle EBS Financials

← Blog

The Tables Behind Every Rate Change: An E-Business Tax Update Runbook

August 7, 2026 · William A. Green

A tax rate change looks like a one-field edit. On a supported instance, doing it sloppily was survivable — if you mangled the setup badly enough, Oracle Support would eventually help you untangle it. On an unsupported instance there is no such backstop, which means the discipline has to live with you. This is the runbook I use: the data model, the procedure, and the verification, table by table.

The regime-to-rate data model

E-Business Tax stores your entire tax configuration in the ZX schema as a strict hierarchy. Every level is date-effective and most tables come in _B (base) and _TL (translated) pairs:

LevelTableOne row meansExample
Tax RegimeZX_REGIMES_BA system of regulations administered togetherUS-SALES-TAX, GB-VAT
TaxZX_TAXES_BOne tax within a regime, per configuration ownerSTATE, COUNTY, CITY; or GST, HST
Tax StatusZX_STATUS_BThe taxable nature bucket a rate belongs toSTANDARD, REDUCED, ZERO, EXEMPT
Tax JurisdictionZX_JURISDICTIONS_BThe geographic incidence of a taxGeorgia state; Fulton County; City of Atlanta
Tax RateZX_RATES_BOne percentage, for one status or jurisdiction, for one effective periodFulton County 3% effective 2019-04-01 → 2026-03-31

Around that spine sit the tables that decide when a tax applies and to whom:

ConcernTablesNotes
Tax rulesZX_RULES_BRule per determination step (applicability, place of supply, registration, rate determination…)
Determining factorsZX_DET_FACTOR_TEMPL_B and relatedThe “IF” vocabulary: geography, party registration, fiscal classifications, transaction attributes
ConditionsZX_CONDITION_GROUPS_B, ZX_CONDITIONSThe concrete values a rule tests (MOS note 1111553.1 walks the setup)
Party profilesZX_PARTY_TAX_PROFILETax registrations and attributes for legal entities, operating units, suppliers, customers
ExemptionsZX_EXEMPTIONSCustomer/product exemption certificates with their own effective dates
Migrated 11i codesLookups ZX_INPUT_CLASSIFICATIONS, ZX_OUTPUT_CLASSIFICATIONSWhere your upgraded AP/AR tax codes live if you came from 11i
GeographyHZ_GEOGRAPHIES (TCA)Master geography — for the US: State → County → City → Postal Code. Jurisdictions can be mass-created from it, and it accepts exactly one master source; you cannot mix providers
AccountingZX_ACCOUNTSWhich liability/recovery accounts each rate posts to

And the runtime side — the tables your update ultimately has to prove itself in:

TableWhat lands there
ZX_LINESEvery calculated tax line, per transaction
ZX_LINES_DET_FACTORSThe snapshot of determining factors the engine used for each transaction line (this is where PO and requisition tax context lives)
ZX_REP_EXTRACT (via ZX_REP_EXTRACT_V)The reporting extract behind the Financial Tax Register
JG_ZZ_VAT_REP_ENTITIES, JG_ZZ_VAT_TRX_DETAILSEMEA VAT reporting entities (one per legal entity + regime + registration number) and their transaction details

The golden rule: end-date and create, never update

ZX_RATES_B is deliberately built so that one rate percentage for one period is one row. When Fulton County moves from 3% to 3.5% on April 1, the correct change is:

  1. The existing rate row gets EFFECTIVE_TO = 31-MAR-2026.
  2. A new rate row is created: same regime, tax, status, jurisdiction — PERCENTAGE_RATE = 3.5, EFFECTIVE_FROM = 01-APR-2026, effective-to open.

Never edit the percentage on the live row. Three reasons, in increasing order of severity: transactions dated in the old period must continue to calculate and recalculate at the old rate (credit memos against March invoices care deeply about this); your audit trail is the row history itself; and the engine caches and validates against effective ranges, so in-place edits are where the classic date-overlap errors come from (“Enter a date range that is within the date range of this component” — the subject of its own MOS note, 2184159.1, and of two more on repairing rates that were end-dated or disabled wrongly: 2353608.1 and 2109672.1). If you have inherited a setup where somebody did overwrite percentages in place, treat that as a finding — historical recalculations may already be wrong.

The same end-date-and-create discipline applies one level up. A new tax (say, a state adopts a retail delivery fee, which is legally a fee per order, not a rate on a line) is a new ZX_TAXES_B entry with its own statuses and rates — not a contortion of an existing rate. A boundary change (Texas publishes city annexation lists quarterly) is a geography and jurisdiction problem: the address moves between jurisdictions, so the fix is in TCA geography and ZX_JURISDICTIONS_B, and no amount of rate editing will produce the right answer.

The procedure

All of this is done from the Tax Managers responsibility. On 12.2 the Tax Configuration Workbook (an Excel upload with nine worksheets) can carry bulk loads; on 12.1 you are in the HTML UI — which is fine, because a quarterly change set is rarely more than a few dozen rows.

In a clone first. Always. The sequence:

  1. Diff sources against setup. Take the quarter’s rate/boundary files and DOR bulletins (see the companion article on sources and schedules) and produce the change list: rate changes, new jurisdictions, boundary moves, base changes that need a rule edit rather than a rate edit.
  2. Apply in the clone. Tax Managers → Tax Configuration → Tax Rates: query the rate, set the end date, create the successor row effective the first of the quarter. New jurisdictions: create from the geography hierarchy so the jurisdiction ties to TCA geography rather than free text.
  3. Verify the setup rows. A query like this confirms what the UI did:
SELECT r.tax_regime_code, r.tax, r.tax_status_code,
       j.tax_jurisdiction_code, r.percentage_rate,
       r.effective_from, r.effective_to, r.active_flag
FROM   zx_rates_b r
       LEFT JOIN zx_jurisdictions_b j
              ON r.tax_jurisdiction_code = j.tax_jurisdiction_code
             AND r.tax_regime_code      = j.tax_regime_code
WHERE  r.tax_regime_code = 'US-SALES-TAX'
AND    r.tax = 'COUNTY'
AND    j.tax_jurisdiction_code LIKE '%FULTON%'
ORDER  BY r.effective_from;

You want to see contiguous, non-overlapping effective ranges: old row closed March 31, new row open from April 1, no gap, no overlap.

  1. Prove it on transactions. Enter one transaction per changed jurisdiction, dated in the new period, in each affected module — an AP invoice, an AR invoice, a PO if procurement matters to you. Then check the engine’s answer at the source:
SELECT trx_id, tax, tax_rate, tax_amt, tax_jurisdiction_code
FROM   zx_lines
WHERE  application_id = 222       -- 222 AR, 200 AP, 201 PO
AND    trx_id = :your_test_transaction
ORDER  BY tax_line_number;

And one transaction dated in the old period, to prove history still calculates at the old rate.

  1. Run the Financial Tax Register over the test window and eyeball the changed jurisdictions. If EMEA VAT reporting applies, run the relevant VAT register against the reporting entity too — reporting reads the extract, not your good intentions.
  2. Migrate to production by repeating the UI steps (or workbook load on 12.2) inside a change ticket with the source bulletin attached. Then spot-check the first live transactions of the new quarter — the first Tuesday of a new quarter is when a missed jurisdiction announces itself.

What not to do

Do not update ZX tables with SQL. I write data fixes against Oracle Financials for a living, and I still say it: tax setup is the wrong place for direct DML. (What you use instead — the screen, program, or workbook for every object — is covered object-by-object in the supported update paths article.) The UI maintains a web of consistency — rate-to-status links, jurisdiction geography references, _TL translations, flexfield defaults, cache invalidation — that a direct update silently bypasses. The engine may keep working while the reporting extract, or a credit memo eight months from now, quietly disagrees. Data fixes belong on the transaction side (repairing bad ZX_LINES the engine already produced — a different article’s subject), not the configuration side.

Do not “fix” a wrong rate by deleting anything. Setup rows that have been used by transactions are load-bearing. The correction for a wrongly created rate is an end date; the correction for a wrongly end-dated rate is documented in the MOS notes above and is fussier than you expect — which is the point of doing all of this in a clone first.

Do not let the geography go stale. Rates get all the attention, but three years of unapplied annexations and new incorporations means addresses silently calculating in the wrong jurisdiction at the correct rate — the hardest kind of wrong to spot. Boundary files are published on the same quarterly schedule as rates; process them with the same discipline.

The uncomfortable part

Everything above assumes the engine itself behaves. On a supported release, when it doesn’t — a recovery rate that misapplies, a determining-factor bug, a reporting extract that drops lines — you file an SR and eventually get a patch. On 12.1 since January 2022, no patch is coming. The remedy is a diagnosed, tested, custom fix, which is precisely the third-party-support skill set: reproduce it, find it in the ZX code or data, correct it, and stand behind the correction. That, plus the quarterly discipline above, is what “keeping E-Business Tax current without Oracle” actually consists of.

Inherited a tax setup with overlapping rates, free-text jurisdictions, or in-place edits in its history? Describe what you’re seeing — I’ll tell you what a cleanup costs before you commit to anything.

Running into this on your own system?

Describe the problem — EBS version, module, what you're seeing — and I'll tell you what it likely is, what it takes to fix, and roughly what it costs.

Describe a specific issue