Serbian payroll and local documents: the gap in every foreign ERP
Payroll and local documents are not features missing from foreign ERPs; they are a boundary data crosses by hand every month, which is precisely why an add-on does not close them.
- Published
- Author
- Konis Software
When a Serbian company selects an ERP, payroll rarely makes the top three requirements. It sits around fifteenth, below bank integration and above mobile access. The contract is signed, the project starts, and then — at the migration workshop, five months in — somebody asks how March gets calculated. The answer is almost always: payroll stays where it is.
The gap is not a missing feature — the gap is a boundary
Odoo, Business Central and SAP Business One are serious systems: breadth, dimensional posting, an API, a partner network. What they lack is Serbian payroll, and that is no oversight. Payroll is the most expensive localization there is — it changes yearly, an error shows on every payslip, and the market holds a few thousand buyers. No global vendor closes that case alone. It gets solved three ways:
- A partner localization package — an add-on maintained by a third party, on its own release cycle.
- A separate local payroll program — the calculation happens there; one summary journal entry returns each month.
- An accounting firm — payroll becomes a service, and the ERP receives a PDF or a spreadsheet.
Three answers, one shared property: a boundary data crosses by hand or by file. Painless while everything goes to plan. It hurts when someone must explain why labour cost in the ledger differs from the payslip total, and when March is recalculated in November.
What Serbian payroll actually requires
In a global product, payroll means: take gross, apply rates, produce net. Serbian payroll is a different object — a rules engine carrying history. What must exist inside it:
- Income tax at 10%, with a tax-free allowance changing on a valid-from date.
- Employee contributions at 19.90% and employer at 15.15%, bounded by a lowest and highest monthly base that cut the run at both ends.
- The seniority premium (minuli rad): a statutory minimum of 0.4% of base salary per full year of service.
- Compensation for leave, holidays and paid absence — each with its own base, as a rule a twelve-month average.
- Sick pay at 65% for illness and 100% for a work injury, with a thirty-day threshold after which the cost shifts to the fund.
- Meal allowance and holiday pay inside the salary; earnings outside it, and employment reliefs, carry their own thresholds and dates.
- Contracts outside employment — service, copyright, lease — each with its own income-type code.
The seniority premium is a good test. In a foreign system it becomes a custom field in the calculation schema, and the first run comes out clean. The trouble arrives later: service length is a history, not a number; it changes mid-month, and the base it applies to is not always what the system calls basic pay. A field correct yesterday is wrong today, and nobody knows when it turned — it has no date.
PPP-PD is not a report — it is a consequence of the run
PPP-PD, the individual return for calculated taxes and contributions, carries per employee an income-type code (OVP), a relief code (OL), a financing-method code (MFP), and via the BOP reference a link to a specific payment. It is not a list of salaries but an extract from the run per income type — and it is what you pay against. Retyped from another program, it opens the costliest divergence: the file is filed, the money paid against the BOP, the ledger believes something else.
The local documents nobody counts until the contract is signed
Payroll is the most visible part of the gap, not the only one. Beside it sits a family of documents a global product lacks because they have no international equivalent. Each is small alone. The sum is not.
| Document | What the rules require | Usual workaround | The cost |
|---|---|---|---|
| Cash desk (blagajna) | Daily cash report, receipts, holding limit, cashier apart from controller | A spreadsheet beside the system | Outside subledgers; shortfalls surface at stocktake |
| Travel order (putni nalog) | Advance, settlement on return, per diems by country, mileage | A Word template and an email | Lands without dimensions, a month late |
| KEP book and revaluations | Per-outlet turnover register, retail/wholesale costings, revaluation on price change | A separate retail application | Two stock figures per item, reconciled nightly |
| Purchases from individuals (otkup) | Purchase note, 8% VAT compensation, payment to an account, packaging | By hand, outside the system | Deduction rests on an unseen document |
| Set-off and cession | Statement, consent of all parties, open items closed both sides | A hand-typed journal entry | A dunning letter to a customer owing nothing |
| Payment order | Reference model 97 with check digit, IPS QR, bank statement formats | Typing the reference by hand | Never matches; hangs to quarter end |
None of these documents is hard. Each is a point where the system either knows what happened or does not. When six sit outside, a single business truth becomes six spreadsheets somebody reconciles — work that never appears in a project plan, yet consumes the finance team.
Why localization as an add-on does not solve it
The standard reply is that a localization package exists. It does — often written honestly, by people who know the regulation better than the core's vendor. The problem is not its quality, but where it sits.
- 1
The package lags the law; the deadline does not
An amendment lands in December, effective January. The package must ship, pass the partner's testing and reach your instance; the PPP-PD deadline does not move. The gap is bridged by hand — and a month done by hand leaves a result with no trace of how it arose.
- 2
Two upgrade cycles that never line up
The core has its release calendar; the package its own. A core upgrade can move what the package relied on; a package upgrade can demand a core version you cannot take. The instance freezes two years back, and that becomes policy.
- 3
The package lives above a model that did not anticipate it
If the core stores only a rate's current value, the package cannot add rate history — only simulate it in its own table. If postings carry no dimensions, it can only produce a report that disagrees with the ledger. An add-on inherits every assumption of the core and may change none.
- 4
Responsibility split three ways is nobody's responsibility
A run comes out wrong: the core vendor says payroll is the partner's, the partner says the change was in the core, the implementer says configuration. All three can be true at once. That helps nobody signing the return.
Anything that cannot be added later must be decided before the first module. A localization sitting above the core inherits its every assumption and may change none.
Two decisions that cannot be added later
First: every statutory parameter remembers the period it was valid for. A March recalculation run in November must use March's allowance, rates and bases, not today's. That is routine — a retroactive amendment, late-recognised sick leave, a service-length correction. A system storing only the current value produces a plausible, tidy and wrong result. Worse: silently.
Second: posting carries dimensions on the line. Labour cost is the largest cost in most companies and the one arriving as a single sum, with no organizational unit, project or cost centre. Somebody then spreads it across a key in a spreadsheet, monthly. That is reconstruction, not controlling. A dimension absent at posting cannot honestly be added later, only assumed.
How NG One solves it
In NG One, Serbian payroll and local documents are first-class content of the system, not a layer on top. Concretely:
- Payroll sits in the core, on the same platform as the general ledger, with the same workflow engine, authorization and immutable log. No export, no retyped summary.
- Statutory parameters remember the period they were valid for, and postings carry dimensions on the line. Both decisions sit in the foundation, made before the first line of payroll code. A March recalculation uses March's rates because the system still knows them — not because someone kept them in a spreadsheet.
- The PPP-PD XML, the payment orders and the journal entry come from one locked run — all three from the same source, not one from another. That is why they cannot drift.
- The cash desk, set-off and cession, the KEP book, revaluations, travel orders and purchases from individuals are document types in the core — each with its own state machine, authorization and posting, hitting the same stock and the same subledgers. None is a spreadsheet beside the system.
- The channels to the tax portal, the sick-leave register and CROSO go exactly as far as the portals allow: the system prepares, validates and signs the XML and keeps the record of submissions and statuses; a person takes the last step. Semi-automatic is an accurate description of the boundary here, not an excuse.
Five questions for a vendor
- Who writes and maintains Serbian payroll — you, a partner, or another program? Ask for the legal entity that signs for it.
- When the allowance changes in December effective January, how many days later does it reach our instance, who tests it, who pays?
- Recalculate one month from last year in front of us, on the rules valid then. Do not describe — do it.
- Show a payroll journal entry with organizational unit, project and cost centre on the line — no later allocation in a report.
- Where do the cash desk, travel order, KEP book and set-off live? If implementation handles it, ask how long and who maintains it afterwards.
None is a trap and none asks for a promise — all ask for a demonstration. Payroll is where the distance between supported and working surfaces only in the fifth month, when it is already expensive. A system is chosen not by modules on a slide, but by how many boundaries remain between where work happens and where it is decided. For payroll, zero.