Time-effective statutory parameters: when a rate changes, the past must not
A VAT rate changes once a decade — which is exactly why most systems store it somewhere that makes it impossible, after a change, to prove what was applied to a document from a closed period.
- Published
- Author
- Konis Software
Since VAT was introduced in Serbia in 2005, the rates have moved twice: the standard rate from 18 to 20 percent on 1 October 2012, the reduced rate from 8 to 10 percent on 1 January 2014. Two changes in twenty years. That rarity is why the rate still sits, in many systems, as a constant in code or one row overwritten when needed — and why the problem surfaces only when a change lands, too late to fix the model cheaply.
Three places a rate can live
- A constant in code — the rate is written into the calculation. Changing it is a software change and a release.
- A single row in a settings table — the rate is data, but holds one value: the current one. Changing it is an UPDATE.
- A versioned parameter — every value carries a validity range and a source. Changing it is a new record; the old stays.
A constant in code
When the rate is a constant, a statutory change becomes an engineering task with a deadline set by the official gazette. Inconvenient, but survivable once a decade. The consequence is not: the build that knew the old rate leaves production the moment the new one arrives. From 2 October 2012, the system cannot credit a September supply, because 18 percent no longer exists in it even as a concept. What teams do next always looks the same: a date branch buried in one method, undocumented, invisible in any settings screen. That is parameter versioning — in the worst possible place.
One row that gets overwritten
The second approach looks like a solution: the rate is data, an accountant maintains it, no developer required. The price is paid in one statement nobody watches. An UPDATE takes milliseconds and has no inverse — the old value does not move into history, it stops existing. From then on, every report reading the rate from the settings table rather than the posted line returns new numbers for every past period.
Posting does not ask what today's rate is
This is where the model usually breaks. A rate is not resolved as of now; it is resolved as of a determining date, and that date differs by parameter. A serious ERP carries several dates on a document — document, supply, posting, value, entry — because no single one serves every calculation.
| Parameter | Determining date | Common mistake |
|---|---|---|
| VAT rate, standard and reduced | Date the liability arises: supply, advance or customs debt — whichever is first | Invoice issue date or posting date is used |
| Flat-rate VAT compensation to farmers | Date the compensation is paid | Purchase note date is used |
| Contribution and payroll tax rates | Date the salary is paid out | The month the calculation relates to is used |
| Minimum and maximum contribution base | Date the salary is paid out | This year's base applied to last year's payout |
| National Bank middle exchange rate | Date the obligation arises | The rate on the posting date is used |
| Statutory default interest | Each day of delay separately | Whole period computed at the latest reference rate |
The table carries a conclusion invisible until written down: on the same day, in the same system, three parameters resolve against three different dates. The current value is therefore not a simplification of the model — it is a term with no definition in this domain. The exchange rate is the control case: nobody hardcodes it, nobody keeps only the latest, because it moves daily and history is obviously needed. Its model is identical to the VAT rate's — a value with a validity range, resolved on a determining date. Only frequency differs.
How often a parameter changes says nothing about how it should be modelled. It only says how long the defect stays unnoticed.
Backdated documents are the rule, not the exception
If every document were created on the day of its own supply, this would be an academic argument. In real operations, a document dated in the past is ordinary:
- A credit note against last year's supply — the base is reduced at the rate in force on the original supply date, not today's.
- A reversal, executed after a rate change, of an invoice issued before it.
- A supplier invoice arriving two months late, with its own supply date and its own right to deduct input VAT.
- A customs declaration cleared after goods receipt: landed cost enters acquisition value retroactively and forces stock revaluation, while some affected lots have already shipped under FEFO.
- An inventory shortage recorded through an internal VAT self-charge.
- An amended payroll return (PPP-PD) for a past month, after one calculation line is corrected.
The first case deserves full detail. An invoice from September 2012: base 100,000 dinars, VAT 18,000. The customer complains in November and a full credit note is issued. A system resolving the rate as of now writes 20,000 dinars of VAT onto it. The company charged 18,000 and is reducing by 20,000 — a 2,000 dinar difference with nowhere to sit in the VAT review. On one document, an error fixed by hand. On four thousand documents from a disputed quarter, a position neither explainable nor reconstructable in reasonable time.
Payroll: same mechanism, worse consequences
VAT parameters change rarely. Payroll parameters change almost every year, in several places at once: the minimum and maximum monthly contribution base, the non-taxable salary amount, periodically the rates themselves. The Serbian payroll return is filed per recipient, with an income-type code deciding which parameters apply at all. The combinations a single current value can miss outnumber VAT by an order of magnitude.
An amended return for March, filed in July, is routine work. A correct system re-runs the March calculation against March parameters and changes exactly what was wrong. A system knowing only July's values produces a return differing from the original on every line, though one item is being fixed. The tax authority does not see a correction; it sees a different calculation. Explaining that takes days, leaves no written trace, and repeats on every amendment — because the system still believes it is right.
Two axes of time
A second order of the problem shows up only in live operation: a parameter has two times — when it is in force, and when we learned that it is. An amendment published in December, applying from 1 January, keeps them aligned. A correction published in March, applying retroactively from 1 January, pulls them apart. The system must then answer two questions: what was applied in January (the truth in the filed return) and what should have been (the basis for the amendment). The difference is exactly what gets reported. A single-axis model cannot pose the question. That is why fixing a mistyped parameter is never an UPDATE — it is a new record over the same validity range, with its own entry timestamp.
A model that holds
- 1
A parameter is an interval, not a value
Every version carries a code, a value, a validity range and a source — a gazette reference or an internal decision. Values are never overwritten.
- 2
Resolution runs through a determining date
Each parameter type declares which document date resolves it. The posting date is a sound default for exactly zero tax parameters.
- 3
The result is frozen onto the line
A posted line carries the applied value and the version reference. The value, so reports need no recalculation. The reference, so it is known who said so.
- 4
Recalculation is an event, not a side effect
A retroactive correction does not quietly rewrite lines. It lists affected documents, computes the delta and asks for a decision: correct, amend the filing, or keep the position with a stated reason.
- 5
Every line can explain itself
Why 18 percent reads: supply date 12 September 2012, this parameter resolves on the supply date, the version in force then was this, its source is that. Without the chain, an audit gets an assertion, not evidence.
| Audit question | Constant in code | Single current value | Versioned parameter |
|---|---|---|---|
| Which rate was applied in 2012? | Depends on the build then in production | Whatever the table says today | Recorded on the line itself |
| Why that rate? | Because it was written that way | No answer available | Supply date resolves a version with a validity range |
| Can the report be reproduced? | Only from archived code and data | No — it returns a different number | Yes, deterministically |
| What about a retroactive fix? | New release, manual corrections | The past silently changes too | Affected documents listed, amendment grounded |
Why this cannot be added later
This is one of the few ERP decisions that cannot be deferred. Backfilling the parameter table with history is easy: gazettes are public, intervals known, the work takes a day. What cannot be backfilled is the version reference on three hundred thousand posted lines. There is no source — it must be guessed, using the very date logic the system never had. Where the legacy system used the wrong date, the migration reproduces the error and dresses it as evidence: worse than an error that still looks like one.
Five questions for any ERP
- Regenerate the VAT review for a period three years back and compare it with what was filed. The numbers must match.
- Ask which document date resolves the VAT rate — and to be shown it in configuration, not told in conversation.
- Raise a credit note against a supply from before the last rate change and watch which rate is offered.
- Open one posted line and ask which parameter version was applied, and where it came from.
- Ask what a retroactive correction does: stay silent, or list the documents it touches.
None of these questions is hard. That is what makes them useful: a system with no answer to them has none to any harder one.