I inherited a stalled custom VAT report and found its real defects by testing it like a forensic experiment.
Read the ABAP to uncover a two-data-path architecture — and turned defect hunting into prediction: check every column on both paths before anyone reports it broken.
A trusted on/off comparison had run on a cash-call-only date — nothing to split. Designed a discriminating run matrix that proved the JV split works, and exposed a new attribution defect.
Seven findings, one root cause per ticket, each shipped with pre-computed expected values from posted data so retest completes in a single run.
Every claim carries a confidence label — observed · arithmetic · code-confirmed · inference — so no conclusion ever outruns its evidence.
A stalled sign-off, behind the wrong blocker.
I inherited the object mid-phase from a consultant rolling off the project, with reviewer sign-off stalled behind a vaguely recorded blocker — a "JVA splitting function" — and go-live approaching.
The recorded blocker turned out to be wrong. The real defects were elsewhere entirely — invisible until the report was tested systematically. The first job wasn't to fix anything; it was to find out what was actually true.
Rebuilding the knowledge base from primary sources.
Rather than trusting the handover narrative, I re-verified every load-bearing claim against primary sources: the Functional Design document clause by clause, the ABAP main program, and the posted documents themselves.
Every statement in my working notes carries an explicit confidence label — so that no conclusion ever outruns its evidence. This habit repeatedly caught errors before they reached stakeholders.
One report, two data paths.
Reading the code revealed the architecture that explains nearly every defect found. Almost every defect reduced to one pattern: a feature was implemented on the standard path, and the second path was never followed through.
▸ Standard path
Tax lines selected from table BSET, exactly as standard RFUMSV00 works. All balance pages are built here.
▸ Cash-call path
JVA cash calls post as vendor special-G/L transfers with no tax line at all — therefore no BSET entry, therefore invisible to the standard logic. A custom read from BSEG / ACDOCA was added at END-OF-SELECTION to display them.
Recognizing the pattern converted defect hunting from guesswork into prediction — each new column or behaviour could be checked on both paths before anyone reported it broken.
Verifying "JVA splitting" scientifically.
The splitting feature — dividing tax lines among joint-venture partners by equity share — had been declared both "broken" and "working" by different observers. I treated it as a hypothesis problem.
Found the split call: gated by the activation checkbox plus a company-code JVA-active check, and applied only to the standard path — which proved a previously trusted on/off comparison, run on a cash-call-only date, was a null test (there was nothing to split).
Identical before/after totals cannot distinguish "split works at 100% equity share" from "split does nothing" — a positive result both hypotheses predict proves neither.
Designed a matrix — one variable per run, expected outcome written per hypothesis before execution — and found the decisive case: a single document spanning two ventures. The tax line split into two, correctly pro-rated → the split works.
The same run showed both split lines carrying the first venture's attributes (Profit Center / Joint Venture / Equity Group) — misattributing one partner's tax to another. Arithmetically right, informationally useless. Raised with per-line expected values from the posted document.
What systematic testing surfaced.
Condensed. Nearly every root cause traces back to the same pattern — a feature built on the standard path and never carried to the custom one.
| Area | Defect found | Root cause |
|---|---|---|
| Final balance page | Cash-call amounts reach "Balance per company code" but never the final "Balance of all company codes" — the page the VAT return is filed from | Consolidation step for the custom path left unimplemented in code |
| Currency display | Cash-call block shown under USD / 2 decimals with a blank transaction key, although amounts were already correct OMR values | Reporting-currency key never assigned on the custom path |
| Document scope | Only vendor-side cash calls selectable; FD requires customer side too | Document type hardcoded |
| Line attributes | Equity Group and Tax Reporting Date blank on cash-call lines | Fields fetched but never assigned / wrong source field |
| JVA split output | Split lines inherit the first venture's attributes | Attributes assigned per document instead of per split line |
| Report layout | Four FD-required currency columns (LC2 pair, report-currency pair) absent from the field catalog — while the data sits fully posted in the same BSET record and in ACDOCA group-currency fields | Display gap, not data gap — proven by SE16N before development started |
| Exchange rate | Rate type deviates from the FD-specified configuration source | Default rate type used instead of country configuration |
One earlier suspicion was formally withdrawn after negative testing disproved it — kept visible in the record deliberately: showing what was ruled out is part of the evidence.
Defect engineering, not just defect reporting.
A defect is only useful if it can be fixed once, correctly, without breaking a correct value on the way. That is a design problem, and I treated it as one.
The fix is only half the job.
A correct diagnosis routed to the wrong owner, or phrased so it invites the wrong fix, is worse than no diagnosis. Getting the fix to land is its own discipline.
Five rules I now test everything against.
What this engagement exercised.
Deep FI-Tax on the SAP data model, JVA, multi-currency, code reading for root cause, and test design that refuses to be fooled by a clean-looking null.
Companion reading: FI Tax Consultant — Scope of Work · Functional Module of Finance — SAP FI