Early accessSome features may be unavailable
Back to Blog
DataSynth 5.29saps4hanamulti-currencywrbtrwaersfxintegration

SAP-style multi-currency JEs: WRBTR, WAERS, and the document/local-currency split

DataSynth 5.29 added `transactions.foreign_currency_rate` — a SAP-faithful split between document currency (WRBTR/WAERS) and local-ledger currency (DMBTR). Here's why the trial balance stays clean, how the JE balances in both currencies, and what it means for S/4HANA-realistic test data.

VynFi Team · EngineeringMay 27, 20267 min read

Real SAP ledgers carry every JE in two currencies simultaneously: the company-ledger currency (used for the trial balance and every consolidation aggregation) and a per-document foreign currency (used for the customer/vendor side of the transaction). The two are linked by an exchange rate stamped on the document header. Synthetic test data that skips this split fails any S/4HANA round-trip test that involves a non-local invoice — exactly the case where multi-jurisdictional audit teams need the test data to behave.

**TL;DR** — DataSynth 5.29's `transactions.foreign_currency_rate` lever generates JEs where a fraction post in a foreign document currency. `debit_amount` / `credit_amount` / `local_amount` stay the company-ledger amount (SAP **DMBTR**); a new per-line `transaction_amount` column (**WRBTR**) plus `header.currency` (**WAERS**) and `header.exchange_rate` carry the foreign value. **The JE balances in both currencies**. The trial balance and every ledger aggregation are untouched. Default-off (opt-in); enable for FX realism (corpus shows ~3.5%). Surfaced as a Scale+ wizard toggle in /dashboard/generate.

The SAP terminology — and why it matters

  • **DMBTR** (`Debit/Credit Amount Local Currency`) — the company-code currency amount. Aggregated to the trial balance. This is what consolidation reads.
  • **WRBTR** (`Debit/Credit Amount Document Currency`) — the document/transaction currency amount. This is what appears on the customer invoice or vendor payment.
  • **WAERS** (`Document Currency`) — the ISO 4217 code of WRBTR (e.g., USD, JPY, GBP).
  • **KURSF** (`Exchange Rate`) — the rate that links WRBTR to DMBTR. Stamped on the header at the moment the document is posted.

An SAP audit firm running TB reconciliations only ever looks at DMBTR. An auditor looking at supplier invoices in the source document looks at WRBTR. An IFRS group consolidator hits both — DMBTR for the local trial balance, then translates back via WAERS/KURSF to the presentation currency. The 5.28 engine modeled DMBTR perfectly and pretended WRBTR didn't exist. 5.29 closes that gap.

How the lever works

`transactions.foreign_currency_rate` is a fraction in [0, 1] — the probability that a given JE posts in a foreign document currency. The default is 0.0 (off). The corpus we measured shows ~0.035 (3.5% of JEs); enabling that value lands the synthetic data at corpus parity for FX prevalence.

For each JE that draws as 'foreign-currency': the document currency is sampled from a configurable pool (defaults to the global majors — USD, EUR, GBP, JPY plus a long tail), the exchange rate is sampled from a calibrated band around recent quotes, the header gets `currency` and `exchange_rate` populated, and each line emits both `local_amount` (DMBTR) and `transaction_amount` (WRBTR). For 'local-currency' JEs the new `transaction_amount` column equals `local_amount` and `header.currency` equals the company code's local currency.

The lever applies on the **normal posting path only**. Reversals and allocation batches stay company-currency (matches the SAP convention — a reversal is always in the same currency as the original posting; an allocation batch is a cost-distribution within the local ledger).

JE balance in both currencies

The structural guarantee: every JE balances in `local_amount` (debits = credits in DMBTR) AND every JE balances in `transaction_amount` (debits = credits in WRBTR). This is enforced by construction — the engine generates the foreign-currency view first (using the document currency's amount distribution) then derives the local-currency view by multiplying through the exchange rate, with sub-cent rounding settled on a single line so both balance exactly.

Concretely, for a vendor invoice in USD with a EUR-functional German subsidiary at a 0.92 USD/EUR rate:

YAML
header:
currency: USD # WAERS
exchange_rate: 0.92 # KURSF — EUR per USD
lines:
- account: 1100 # Trade payables
debit_amount: 0.00 # DMBTR (local, EUR)
credit_amount: 920.00
transaction_amount: -1000.00 # WRBTR (doc, USD)
- account: 5000 # Office supplies expense
debit_amount: 920.00 # DMBTR
credit_amount: 0.00
transaction_amount: 1000.00 # WRBTR

Both `debit_amount = credit_amount = 920.00` (EUR DMBTR balanced) AND both `transaction_amount` rows sum to 0 USD (WRBTR balanced).

Trial balance is untouched

The trial balance, every consolidation aggregation, and the financial statements are computed from `local_amount` (DMBTR) exclusively. Enabling foreign_currency_rate changes the per-line WRBTR column but leaves every DMBTR aggregation byte-identical to a same-seed run with `foreign_currency_rate: 0.0`. That's the SAP-faithful behavior: turning on FX realism doesn't move the trial balance.

Why this matters for testing: an audit team running TB-level analytics against the synthetic data sees the same numbers regardless of the FX setting. A team running document-level WRBTR analytics (vendor-invoice spend by currency, etc.) gets the FX surface they need. Both views read from the same dataset.

What about the SAF-T export

VynFi's SAF-T exporter currently writes the local-amount view exclusively (matches the SAF-T spec's `<MovementCurrency>` element which IS the local-ledger currency). The document-currency view is exposed via the SAP CDS exporter and the canonical JE CSV/JSON downloads. Sub-ledger document-currency support is on the SAF-T roadmap — see the integrations/saf-t roadmap card.

How to try it

Wizard: /dashboard/generate → step 2 (Enrich) → 'Foreign-currency posting rate' expander (Scale+ tier-gated). Slider 0–10%. The hint text shows the corpus rate (~3.5%).

Via API:

JSON
{
"preset": "retail_us",
"rows": { "journal_entries": 10000 },
"transactions": { "foreign_currency_rate": 0.035 }
}

On a 10k retail run, ~350 JEs will post in a foreign currency. The Generate wizard's Review step now surfaces the FX rate so customers can verify the setting before submitting.

What's not in scope (yet)

  • **Sub-ledger FX revaluation entries.** SAP posts a month-end revaluation JE that hits the FX gain/loss accounts when KURSF moves. The 5.29 lever generates per-document FX but doesn't generate the period-end revaluation entries. Tracked.
  • **Cross-company-code FX transfers.** Real S/4HANA group consolidations generate intercompany FX entries when entities in different functional currencies trade. VynFi's group-audit feature (Wave 3) handles this at the consolidation layer via fx.rates pair-keyed translation; the lever discussed here is single-entity / single-ledger FX.
  • **Triangulation through a third currency.** Real ERP systems sometimes translate WRBTR → triangulation currency → DMBTR. 5.29 supports the direct WRBTR → DMBTR path only.

Ready to try VynFi?

Start generating synthetic financial data with 10,000 free credits. No credit card required.