00 · Why this page exists

Anyone can name a T-code. A consultant can read the posting.

In Financial Accounting, every argument ends at the document. Not at the design slide, not at the config screenshot — at the rows SAP actually wrote. So this page does the one thing a static reference cannot: it posts a document in front of you, then opens every table it touched and explains every column.

Pick a business event, set the configuration a consultant actually owns, and press Post. The number range assigns a document number, the database writes fill in one by one, and five tables appear with their real field names. Then click any column header — you get what the field is, where its value came from (user entry, master data, configuration, or derived by SAP), and why it matters when something goes wrong.

◆ The honest framing

This is a teaching model, not a sandbox client. The amounts, accounts and document numbers are illustrative; the mechanics — which table receives which field, which transaction key labels which line, which IMG node determines an account — are standard SAP S/4HANA behaviour. Verify a rate or a field name in the system before you rely on it.

01 · The workbench

Post a document. Watch the tables fill.

A Fiori-style posting surface. Change the configuration on the left and the document on the right is rebuilt from it — no journal line here is hard-coded. Every column header is a button into the field dictionary.

Create Supplier Invoice Financial Accounting · company code 1000

Configuration & entry

Posting pipeline
— Not posted
Press Post to assign a document number from the number range.

Database tables written

Posted rows
Field dictionary

Click any column header above to see what that field holds, where SAP gets it from, and which configuration decides it.

Rendered in SAP Fiori's own semantic palette (brand #0a6ed1, shell #354a5f, success #107e3e). SAP ships the proprietary 72 typeface; this page substitutes IBM Plex, so treat the look as faithful rather than pixel-identical.

02 · The shape of a document

One posting. Five tables. Each answers a different question.

A new consultant's most common mistake is looking for everything in one table. An FI document is deliberately spread across five, because five different readers need it — the accountant, the auditor, the tax authority, the controller and the subledger.

BKPF

One row per document

What happened, once. Company code, document number, year, type, dates, currency, rate, and the reference back to the MM or SD document that caused it.

BSEG

One row per entered line

What the user posted. The entry view — posting keys, accounts, amounts in document and local currency. The compatibility view in S/4HANA.

ACDOCA

One row per ledger per line

The single source of truth. The Universal Journal: FI + CO + asset + material ledger in one table, after document splitting, with every currency and reporting dimension.

BSET

One row per tax code

What the tax authority needs. Base and tax amount per tax code, in every currency — this is what the VAT return reads.

WITH_ITEM

One row per line per WHT type

What the payee's certificate needs. Withholding base, withheld amount, code, recipient type and certificate number.

Say this in a meeting "VAT lives in BSET, withholding lives in WITH_ITEM, and the balance lives in ACDOCA. If a tax report disagrees with the general ledger, those are the three tables to reconcile — in that order."

The open- and cleared-item tables you may know from ECC — BSIK/BSAK (vendor), BSID/BSAD (customer), BSIS/BSAS (G/L) — still answer queries in S/4HANA, but they are now views over ACDOCA, not separate stores.

03 · BKPF

The header: the facts that apply to the whole document.

BKPF is small and boring until something is wrong — then it is the first place you look, because almost every "why did it post like that?" question traces back to a header field.

The key is three fields: BUKRS + BELNR + GJAHR — company code, document number, fiscal year. Document numbers are only unique within a company code and year, which is why every FI table repeats all three.

What each group of header fields is for

GroupFieldsWhy a consultant reads it
Identity BUKRS BELNR GJAHR BLART The document type (BLART) drives the number range and which account types are allowed. A document in the wrong range usually means the wrong type was used.
Dates BLDAT BUDAT MONAT CPUDT Document date is the invoice date; posting date decides the period and therefore the tax return. When a VAT report and a G/L balance disagree on timing, this is nearly always why.
Currency WAERS KURSF HWAER KURSF is the rate actually used by this document. For a foreign-currency payment, quoting this field settles the argument about which rate applied.
Provenance AWTYP AWKEY TCODE USNAM The reference pair points back to the source: MKPF a material document, RMRP a logistics invoice, VBRK a billing document. This is how you prove an FI document came from MM or SD rather than a manual journal.
Reversal STBLG STJAH XREVERSAL A filled STBLG means this document was reversed. Reports that forget to exclude reversals double-count.

Open any document with FB03 and read the header before the lines. Ninety percent of "wrong posting" tickets are a wrong posting date, a wrong document type, or a wrong exchange rate — all three are header fields.

04 · BSEG

The entry view: what the user actually typed.

BSEG holds the document as it was entered — before document splitting, one row per line, with the posting keys that decided debit, credit and account type.

Two fields do most of the explaining:

BSCHL

The posting key — what the user chose. It fixes the account type and the debit/credit sign together: 40/50 G/L debit/credit · 31/21 vendor credit/debit · 01/11 customer debit/credit · 70/75 asset · 25 vendor payment · 89/96 stock / GR-IR.

KTOSL

The transaction key — why SAP generated the line. This is the single most useful field on the page: VST input tax · MWS output tax · NVV non-deductible · ESA/ESE reverse-charge pair · WIT withholding · WRX GR/IR · BSX stock · KDF exchange-rate difference.

SHKZG

The debit/credit indicator, S or H. Amounts in BSEG are stored unsigned — the sign lives here. Reports that sum DMBTR without reading SHKZG produce nonsense.

◆ The trap worth remembering

A user picks BSCHL. SAP fills KTOSL. So when a tax line posts to an unexpected account, the user did not choose that account — the account key behind the transaction key did, in OB40. Checking the user's entry is the wrong first move; check the determination.

Amount fields come in pairs: WRBTR in document currency and DMBTR in local currency, with MWSTS for the tax portion. Clearing adds AUGBL (the clearing document) and AUGDT — an open item is simply a line where those are empty.

05 · ACDOCA

The Universal Journal: one table, every dimension.

S/4HANA's defining change. Where ECC kept FI in BSEG, CO in COEP, assets in ANEP and the material ledger elsewhere — and reconciled them nightly — S/4HANA writes one row carrying all of it.

The consequence is practical: a cost-centre report and a G/L balance can no longer disagree, because they read the same row. The reconciliation job that used to exist has nothing left to do.

The key, and why it has five parts

RLDNR + RBUKRS + GJAHR + BELNR + DOCLN — ledger, company code, year, document, line. The ledger comes first because the same posting exists once per ledger. Forget RLDNR = '0L' in a SE16N query and every amount you see is multiplied by the number of ledgers.

Say this in a meeting "Which ledger are we looking at? ACDOCA is one row per ledger per line, so a total without a ledger filter is not a number — it's a sum of several books."

Field families

FamilyFieldsWhat it gives you
Ledger & keyRLDNR RBUKRS GJAHR BELNR DOCLNWhich book, which document, which line.
AccountRACCT KTOSL MWSKZ DRCRKThe G/L account plus the reason the line exists and its tax code.
AmountsWSL HSL KSL OSL RWCURTransaction, company-code, group and freely-defined currency — signed, unlike BSEG.
ReportingRCNTR PRCTR SEGMENT RFAREACost centre, profit centre, segment, functional area — the dimensions a balance sheet can be sliced by.
SubledgerLIFNR KUNNR ANLN1 MATNRVendor, customer, asset, material on the same row — no join needed.

Amounts in ACDOCA are signed; amounts in BSEG are not. That single difference is behind a surprising number of custom-report defects: logic ported from ECC keeps reading SHKZG, which ACDOCA does not need, and flips half the lines.

06 · BSET

The tax lines: what the VAT return actually reads.

One row per tax code per document. Not per line item — per tax code. Three expense lines sharing one tax code produce one BSET row with the summed base.

The amount fields come in pairs, once per currency, and the naming is worth memorising because every tax report in SAP uses it:

CurrencyBaseTaxWhich currency
DocumentFWBASFWSTEThe currency on the invoice
Local 1HWBASHWSTECompany-code currency — what the return is filed in
Local 2H2BASH2STEGroup currency, if configured
Local 3H3BASH3STEThird currency, often a tax-specific one

Alongside them: MWSKZ the tax code, KTOSL the account key that sent it to a G/L account, KSCHL the condition type from the tax procedure, KBETR the rate as applied, and HKONT the account it landed in.

◆ Two cases that confuse everyone

A non-deductible tax code shows no separate tax line. With account key NVV the tax is added into the expense or GR/IR line, so BSEG has nothing tax-shaped in it — but BSET still records the base and the amount. Read BSET, not the lines.

A reverse-charge code produces two BSET rows. The ESE/ESA pair self-assesses the tax: one row is the input tax you may reclaim, the other the output tax you owe. The net cash effect is nil, which is exactly why it is easy to miss.

The standard VAT return report is RFUMSV00 (S_ALR_87012357). It reads BSET. If a tax amount is missing from the return but visible in the G/L, the posting reached BSEG without reaching BSET — usually a tax code with no condition record or a manual posting to a tax account.

07 · WITH_ITEM

Withholding tax: a separate engine, a separate table.

VAT and withholding tax are often spoken of together and configured nowhere near each other. VAT is a tax code on a line. Extended Withholding Tax is its own engine, keyed by type and code, writing to its own table.

The key is BUKRS + GJAHR + BELNR + BUZEI + WITHT — note the last part: one row per withholding type on the line. A vendor subject to two types produces two rows on the same line.

Type versus code — the distinction that matters

WHT type · T059P

When and how tax is calculated: at invoice or at payment, the base amount type, rounding, accumulation, and whether the posting is with or without offsetting. Changing a type changes timing.

WHT code · T059Z

How much: the rate (QSATZ) and the income type (QEKAR) that decides which return the amount appears on. Changing a code changes the number.

Vendor data · LFBW

Per company code: which types apply, the liable flag, the default code and the recipient type. If the liable flag is off, nothing is withheld — and that is the first thing to check when a deduction is missing.

◆ Why a row can show a base but zero tax

For a deduct-at-payment type, the invoice writes a WITH_ITEM row with the type, the code and the base — but amount zero. The amount only appears on the payment document. A row with a base and no amount is not a defect; it is the invoice half of a two-document story. Run the payment in the simulator above and watch the amount appear on the second document.

Amount fields follow the same per-currency pattern as BSET: WT_QSSHB/WT_QBSHB base and tax in document currency, WT_QSSHH/WT_QBSHH in local currency 1, then …SH2 / …SH3 for further currencies. QSREC carries the recipient type and CTNUMBER the certificate number.

Reporting runs through RFIDYYWT — Generic Withholding Tax Reporting (S_P00_07000134). One selection screen produces forms, lists and e-filing files; which of them you get is decided by the output group, not by the selection. A report that "runs but produces nothing" is usually the wrong output group.

08 · Entry view vs general ledger view

Document splitting: the same document, told twice.

Turn on splitting in the workbench and the row count changes. Nothing was posted twice — you are looking at the second view of one document.

A user enters an expense against a profit centre and a vendor line with none; the vendor is a balance-sheet account and carries no reporting dimension of its own. Document splitting pushes the characteristics of the P&L lines onto the balance-sheet lines, in proportion to the amounts, so that a balance sheet can be produced per profit centre or segment.

Entry view — BSEG

What the user posted. The vendor and tax lines are single rows with no profit centre. This is what FB60 showed them.

GL view — ACDOCA

After splitting. The vendor and tax lines are now several rows, one per profit centre, each balanced in its own right.

Why it matters

A report that reads "the" profit centre of a document must decide which line's profit centre it means. Often there is no single answer.

◆ Two consequences that generate real defects

Tax lines multiply. One invoice across two profit centres produces two tax lines in the GL view, each with its own dimension. A tax report joining on "the tax line" of a document will find two and must decide whether to sum them or pick one.

Zero-amount split lines exist. A characteristic can be carried with 0.00. Reports that do not skip them show phantom rows — and a reviewer who sees a 0.00 line assumes the report is broken.

In FB03, always choose the General Ledger View and name the ledger before discussing segment or profit centre. Arguing about dimensions from the entry view is arguing about a document that does not exist in the ledger.

09 · Currencies

Every line carries several amounts — and all of them must balance.

Switch the workbench to USD and watch a second and third amount column come alive. S/4HANA stores up to ten currencies per line; most implementations use three.

FieldCurrency typeWhat it is
WSL—Transaction currency — what the invoice was written in.
HSL10Company-code currency (local 1) — what the statutory books and the tax return are in.
KSL30Group currency — what consolidation reads.
OSL / VSL40+Freely defined — a hard currency, an index currency, or a tax-specific currency.

Each amount is converted at the moment of posting using a rate from TCURR, selected by rate type (KURST, commonly M for average) and valid-from date (GDATU, which is stored inverted — a detail that has broken many a custom report). Maintain rates in OB08.

The 10-second integrity check on any document Per ledger: ΣWSL = 0, ΣHSL = 0, ΣKSL = 0. If the transaction currency balances but the local currency does not, you are not looking at a posting error — you are looking at a rounding or rate problem.

Rates are set at posting and then frozen. Period-end foreign-currency valuation (FAGL_FCV) does not change them — it posts additional lines for the difference on open items. So an open item legitimately shows an old rate; the revaluation sits beside it, not on it.

10 · Configuration

Nothing on a line is typed. Trace any field to the node that decides it.

This is the table a consultant actually works from. Read it right to left: a field on the document, the thing that determines it, and the IMG node or transaction where you change it.

OBBGCountry → procedure
Assigns the tax calculation procedure to a country. Every company code in that country shares it — which is why a tax code is never company-code-specific.
BSET-KSCHLwhich conditions exist
OBYZProcedure & condition types
Defines the condition types and account keys in the procedure, and the order they calculate in.
BSET-KTOSLaccount key per condition
FTXPTax codes & rates
Creates the tax code and its rate per condition. Change a rate here and every later posting changes; earlier documents keep the rate they were posted with.
BSET-MWSKZ · KBETRcode and rate as applied
OB40Tax account determination
Maps each account key to a G/L account (table T030K). This — not the user — decides where a tax line lands.
BSET-HKONT · BSEG-HKONTthe tax account
OBCNTransaction keys
Defines the processing keys themselves — whether a key is deductible, non-deductible, or part of a reverse-charge pair.
ACDOCA-KTOSLwhy the line exists
OBYCMM → FI
Automatic account determination for goods movements: BSX picks the stock account from the material's valuation class, WRX the GR/IR clearing account.
BSEG-HKONTon a goods receipt
VKOASD → FI
Revenue account determination: account key ERL sends billing to the right revenue line while output tax goes to its own account.
BSEG-HKONTon a billing document
BP / OBD3Account group
The business partner's account group fixes the reconciliation account — the one G/L account that mirrors every subledger posting.
BSEG-HKONTvendor / customer line
T059PExtended WHT · type
Defines when withholding is calculated — at invoice or at payment — plus base type, rounding and accumulation.
WITH_ITEM-WITHTand whether the amount is 0
T059ZExtended WHT · code
Carries the rate (QSATZ) and the income type that decides which statutory return the amount lands on.
WITH_ITEM-WT_WITHCDand WT_QBSHB
LFBWVendor WHT data
Per company code: types allowed, the liable flag, default code, recipient type. Liable off means nothing is withheld, however correct the config above is.
WITH_ITEM exists at allplus QSREC
OBWWWHT accounts
The G/L accounts withholding tax is posted over to, and the offsetting account used when the company bears the tax (gross-up).
BSEG-HKONTthe WIT line
FINSC_LEDGERLedgers & currencies
Which ledgers exist, which currency types each carries, and which fiscal year variant applies. Decides how many ACDOCA rows one line becomes.
ACDOCA-RLDNRand HSL / KSL / OSL
OB08Exchange rates
Maintains TCURR by rate type and valid-from date. The document freezes the rate it found at posting.
BKPF-KURSFand every HSL
Document splittingSPRO · G/L global settings
Which characteristics are split, which are mandatory, and the splitting method. Decides whether the GL view has more rows than the entry view.
ACDOCA-PRCTR · SEGMENTon balance-sheet lines
KE51 / GGB1Profit centre · substitution
Segment is normally derived from the profit centre master; a substitution can derive or overwrite it at posting. Both are legitimate, and knowing which is in play saves a long argument.
ACDOCA-SEGMENTderived, not entered
FBN1Number ranges
The number range per document type and fiscal year. The range a document sits in tells you which type was used, even if nobody remembers choosing it.
BKPF-BELNRthe document number
OB52Period control
Which posting periods are open, per account type and authorisation group. The most common cause of "it won't post" that is not a config error at all.
BKPF-BUDAT · MONATaccepted or refused

Two of these are worth internalising because they are asked at interview: a tax code belongs to a country, not a company code (OBBG), and the account key, not the user, chooses the tax account (OB40).

11 · Method

How to read any FI document in sixty seconds.

The same order, every time. It works because it moves from the facts that apply to the whole document down to the line that is actually wrong.

Header first, in the general ledger view

FB03 → General Ledger View, and name the ledger. Read BLART, BUDAT, WAERS, KURSF. Most "wrong posting" reports die here.

Check it balances, per currency

ΣHSL = 0 and ΣWSL = 0. If only one of them balances, the problem is a rate or a rounding difference, not the posting logic.

Read KTOSL down the lines

It tells you which lines SAP generated and why. A missing VST line means tax determination did not fire; an unexpected KDF means a currency difference.

Reconcile tax against its own table

VAT in BSET, withholding in WITH_ITEM. Compare the base, not just the tax — a wrong base with a right rate is a different defect from a wrong rate.

Three-layer diagnosis, in order

Does the master data exist (vendor liable flag, tax classification)? Is the configuration right for this company code? And what was actually posted? Checking them out of order wastes the most time.

Isolate with a discriminating pair

Find two documents that differ in exactly one variable — one currency, one tax code, one profit centre. The difference between them is the cause. One document is an anecdote; a pair is an argument.

Check the design before raising anything

Never raise as a defect what the signed design says is intended. Evidence before action: table trace, document, configuration — then raise it.

◆ Where to go next

The module around these documents — organisational units, master data, ledgers and currencies, the period-end close, and Thailand's VAT and withholding returns — is on the companion page: Functional Module of Finance — SAP FI. How configuration turns into a posting in the first place is on the FI/CO Configuration Simulator, and the consulting role around it all is in Scope of Work.