00 · The case

I inherited a stalled custom VAT report and found its real defects by testing it like a forensic experiment.

Role — SAP FI-Tax Consultant, WRICEF object owner during the Functional Unit Test (FUT) phase of a large S/4HANA implementation for an upstream oil & gas company. The object: the statutory VAT report for the Omani company code — a custom clone of SAP standard report RFUMSV00 (Advance Return for Tax on Sales/Purchases), extended to display Joint Venture Accounting (JVA) cash-call transactions that the standard report structurally cannot see. Environment: 3-decimal local currency (OMR), documents posted in USD, a parallel group-currency (LC2) ledger, and quarterly VAT filing where the report's final balance page is the filing basis.
01 · READ THE CODE

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.

02 · DISPROVED A NULL TEST

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.

03 · ENGINEERED THE DEFECTS

Seven findings, one root cause per ticket, each shipped with pre-computed expected values from posted data so retest completes in a single run.

04 · EVIDENCE-FIRST

Every claim carries a confidence label — observed · arithmetic · code-confirmed · inference — so no conclusion ever outruns its evidence.

01 · Situation

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.

02 · Before touching anything

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.

◆ The confidence labels
Every claim is tagged with how it is known:
observed on screenarithmetic code-confirmedinference
03 · The master key

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.

04 · The disputed feature

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.

LOCATED IN CODE

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).

THE LOGIC TRAP

Identical before/after totals cannot distinguish "split works at 100% equity share" from "split does nothing" — a positive result both hypotheses predict proves neither.

DISCRIMINATING RUN

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.

NEW DEFECT EXPOSED

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.

The moveDesign the run whose outcome would come out different under each hypothesis — then the result actually decides something.
05 · Findings register

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.

AreaDefect foundRoot cause
Final balance pageCash-call amounts reach "Balance per company code" but never the final "Balance of all company codes" — the page the VAT return is filed fromConsolidation step for the custom path left unimplemented in code
Currency displayCash-call block shown under USD / 2 decimals with a blank transaction key, although amounts were already correct OMR valuesReporting-currency key never assigned on the custom path
Document scopeOnly vendor-side cash calls selectable; FD requires customer side tooDocument type hardcoded
Line attributesEquity Group and Tax Reporting Date blank on cash-call linesFields fetched but never assigned / wrong source field
JVA split outputSplit lines inherit the first venture's attributesAttributes assigned per document instead of per split line
Report layoutFour 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 fieldsDisplay gap, not data gap — proven by SE16N before development started
Exchange rateRate type deviates from the FD-specified configuration sourceDefault 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.

06 · Method

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.

One root cause per ticket. Bundled tickets die of partial fixes — the first fix closes the ticket and the second defect ships. Related tickets carry an explicit "must not be closed by the other fix" line.
Expected results pre-computed from posted data. Every ticket ships with verification documents and exact expected values, so retest completes in a single run the day the fix lands.
Guards against predictable wrong fixes written into the ticket itself — e.g. "amounts are already correct OMR; assign the currency key, do not convert again", preventing a double conversion that would corrupt correct values.
Read from the document, never recalculate. Report values must equal what posting wrote to the ledger; runtime conversion breaks reconciliation with the GL the moment a rate table moves.
Evidence discipline. Selection screen captured before every execute; ground truth via SE16N / FB03 before any conclusion; the strongest evidence built as an A/B contrast inside a single artifact — a correct standard line beside the defective custom line, or the same amount present on one balance page and absent on the next.
Environment traps codified. SE16N shows 3-decimal-currency fields as raw values (a ×10 reading trap, caught by cross-checking arithmetic against FB03); update-run mode is never ticked during testing because it permanently stamps the documents.
07 · The human layer

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.

Reframed an invalid comparison. When the developer asked to "compare the behaviour in the standard TCODE", the trap was that cash calls cannot appear in the standard report at all — a naive comparison would show an empty screen and end the discussion. I reframed the valid comparison (the currency-key behaviour the standard applies to every line it outputs), ran the standard baseline, and delivered retest criteria with it.
Held the line on a statutory defect. A fix initially described as "display beautification" was kept on record as a statutory-currency defect — without confrontation, by anchoring to what the reporting currency means on a VAT filing.
Scope governance. When two on-hold columns could ride the same code change for free, I requested written reviewer approval before instructing the developer, and delivered them hidden-by-default pending the end user's decision — build-to-spec efficiency without silent scope creep.
Took formal ownership of the object at the outgoing consultant's roll-off, including redirecting the development team's future defect and configuration questions to me directly.
08 · Principles this burned in

Five rules I now test everything against.

Design for differenceA positive result that every hypothesis predicts proves nothing — design the run that would come out different.
Null testsA test with nothing to act on is a null test, no matter how clean it looks.
Reports read; they don't fixWrong posted values are corrected at the source, never masked in the display.
Label every claimEvery claim gets a label — observed, arithmetic, code-confirmed, or inference — and the label travels with it.
Retest should cost one runExpected values are ready before the fix is.
09 · Skills & tools demonstrated

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.

SAP FI-TAX & PLATFORM
SAP S/4HANA FI-TaxRFUMSV00 report familyOB40 / FTXPExtended Withholding Tax
JOINT VENTURE ACCOUNTING
ventures & equity groupsrecovery indicatorscash callstax-line splitting
SAP DATA MODEL & CODE
BKPFBSEGBSETACDOCAT005TCURROB08SE16NFB03ABAP code reading
MULTI-CURRENCY
3-decimal currenciesdocument / local / group / report layers
TEST DESIGN & DELIVERY
hypothesis matricesnegative testingnull-test detectionsingle-variable disciplinedefect lifecycle · JIRAevidence-first documentationbilingual TH/EN stakeholder comms

Companion reading: FI Tax Consultant — Scope of Work · Functional Module of Finance — SAP FI