Pakarti pakarti.id
All posts

January changes the law. Last year must not change.

Statutory software has a time axis that most business software does not, and it is a schema decision.

Indonesian tax parameters change. PTKP thresholds, TER brackets, BPJS ceilings — they are revised, typically with effect from January, and the revision is not retroactive.

That sentence has a schema consequence that is easy to miss and expensive to retrofit.

A rate is not a constant

The natural way to store a BPJS ceiling is a column with a number in it. That representation is correct for exactly as long as the number does not change, and wrong from the first January afterwards — in a specific and nasty way.

The moment you overwrite it, recalculating any prior period produces a figure that does not match what was filed. Not visibly wrong. Not an error. A different number, produced confidently, by the same code that produced the original.

And someone will recalculate a prior period. An employee disputes a deduction. An audit asks for a working. A correction is filed. It is routine, and when it happens the system has to reproduce the law that applied then, not the law that applies now.

So the effective date is part of the key

Every reference table carries a validity date, and every lookup takes the payroll period as an argument rather than reading “the current rate”. PTKP thresholds, TER brackets by category, BPJS configuration per programme — all of them.

This is a schema decision, not a report filter. You cannot add it afterwards, because by then the historical values are gone.

Never invent a statutory value

The rule we hold hardest: no rate, threshold, ceiling, depreciation life or deadline may be written from memory, inferred from a comment, copied from a fixture, or interpolated from an adjacent year.

The interpolation clause is the one that catches people. Brackets often move in a smooth-looking progression, and filling a gap is genuinely tempting. But the progression is a coincidence of policy, not a formula, and a value derived from it is a made-up number sitting in a statutory filing.

Missing configuration throws

If a rate is not configured for the period being calculated, the system raises an error. It does not fall back to the nearest year, the previous value, or zero.

A default here is worse than a crash. A crash is caught immediately, by whoever ran the payroll, while they are looking at it. A plausible default produces a complete, correct-looking payslip and a wrong filing, and nobody finds it until someone asks, months later, why the numbers do not add up.

It is the same principle as the ledger: given a choice between a loud failure and a quiet wrong answer, take the loud failure every time. In regulated work the quiet wrong answer is not the smaller problem. It is the larger one, with a delay on it.

Calculations are pure

The compliance layer computes and has no side effects — no writes, no state. A bracket lookup takes a status, a gross amount and a date, and returns a rate.

That is a testability decision. It means the calculations can be checked directly against the worked examples published with the regulations, which is the only external source of truth available. A tax calculation you cannot test against the regulation’s own example is a tax calculation you are guessing at.

The system this came from Gajii and Akunta — payroll, books and tax Next The best explanation is a shortlist