{Country} payroll regulation for {Full Legal Name} — {Year}.
Implemented as a Payroll Engine regulation. Targets payroll periods from {Year} onwards. Rates and parameters are sourced directly from official {AuthorityName} publications.
Status: {e.g. stable / beta / in progress — short note on current phase} Scope: {e.g. Régimen General — key components covered in one line} Certification: {e.g. SILTRA/Sistema RED — out of scope | not applicable}
| Component | Included |
|---|---|
| {Component 1} | ✅ |
| {Component 2} | ✅ |
| {Component 3 — out of scope} | ❌ |
| {Component 4 — planned} | 🔜 |
The regulation is split into a core layer (calculation logic) and data layers (annual rates and parameters). Each data source can be updated independently without touching the calculation scripts.
{CC}.{Name} Core — logic, cases, wage types, scripts
{CC}.{Name}.Data.{Source1} {Description} ({Authority})
{CC}.{Name}.Data.{Source2} {Description} ({Authority})
Annual updates require only new data files (e.g. {CC}.{Name}.Data.{Source1}.{Year+1}.json)
with a matching validFrom. The core regulation and scripts remain unchanged unless
the calculation logic itself changes.
| Regulation | Type | Content |
|---|---|---|
{CC}.{Name} |
Functional | Cases, WageTypes, Collectors, Scripts |
{CC}.{Name}.Data.{Source1} |
Data | {Description} |
{CC}.{Name}.Data.{Source2} |
Data | {Description} |
Regulation.{CC}.{Name}/
{Year}/
Regulation/
{CC}.{Name}.{Year}.json
{CC}.{Name}.Scripts.{Year}.json
{CC}.{Name}.Collectors.{Year}.json
{CC}.{Name}.Cases.Company.{Year}.json
{CC}.{Name}.Cases.Employee.Core.{Year}.json
{CC}.{Name}.Cases.Employee.{Scope}.{Year}.json (optional: additional splits)
{CC}.{Name}.WageTypes.Guard.{Year}.json
{CC}.{Name}.WageTypes.Gross.{Year}.json
{CC}.{Name}.WageTypes.Deductions.{Year}.json
{CC}.{Name}.WageTypes.Employer.{Year}.json
Scripts/
WageTypeValueFunction.Shared.Action.cs Shared helper methods (no action attributes)
WageTypeValueFunction.Guard.Action.cs Guard actions (WT 1–9)
WageTypeValueFunction.{Scope}.Action.cs Domain actions (Gross, Deductions, Employer, …)
CaseValidateFunction.Action.cs CaseValidate actions
{CC}{Domain}Algorithm.cs Pure algorithm classes (unit-testable)
Tests/
{CC}.Test.Setup.json
{CC}.Test.CompanyCases.json
WT-TC{nn}-{CC}-{Scope}/ Wage type test cases
GUARD-TC{n}-{CC}-{Scope}/ Guard test cases
Tests.Unit/ xUnit tests for algorithm classes
Reports/
{ReportFolder}/
README.md
Setup.pecmd
Test.All.pecmd
Data.{Source1}.{Year}/
Data.{Source2}.{Year}/
Docs/
Schemas/
Collectors:
| Collector | Role | NettoLoon |
|---|---|---|
{CC}.{GrossCollector} |
Gross income — all gross salary components | + |
{CC}.{DeductionCollector} |
Employee deductions | − |
{CC}.{EmployerCollector} |
Employer social costs | info |
NettoLoon (WT {nr}) = {CC}.{GrossCollector} − {CC}.{DeductionCollector}
Matrix:
| Nr | Name | Gross | Ded | Empl | Action / Expression |
|---|---|---|---|---|---|
| 1 | Guard | {CC}GuardMandatoryFields — aborts on missing {Field1}/{Field2} |
|||
| 2 | Guard{X} | {CC}Guard{X} — aborts when {Condition} |
|||
| 10 | {TechnicalWT} | {ActionName} — sets {CC}.{RuntimeValue} |
|||
| 1000 | {GrossWT1} | ✓ | {ActionName} — {short description} |
||
| 1100 | {GrossWT2} | ✓ | {expression} |
||
| 5000 | {GrossMirror} | ^&{GrossCollector} — collector mirror, informational |
|||
| 5100 | {TaxWT} | {ActionName} — {short description} |
|||
| 5110 | {CreditWT} | {ActionName} — negative; {short description} |
|||
| 5130 | {TaxNet} | ✓ | ^${5100} + ^${5110} |
||
| 6500 | NettoLoon | ^&{GrossCollector} − ^&{DeductionCollector} |
|||
| 6700 | {EmployerWT1} | ✓ | {ActionName} — {short description} |
||
| 6710 | {EmployerWT2} | ✓ | {ActionName} — {short description} |
Notes:
- WTs 1–{n} (Guards), {tech WTs}: no collector — runtime setters / control flow.
- WTs 5100–5120: no collector — intermediate values summed in WT 5130.
Actions are split across domain files in Scripts/:
| File | Scope | Description |
|---|---|---|
WageTypeValueFunction.Guard.Action.cs |
Guards (WT 1–9) | Abort on missing fields/lookups |
WageTypeValueFunction.Shared.Action.cs |
Helpers | Private methods, no action attributes |
WageTypeValueFunction.{Scope}.Action.cs |
Domain | Replace with actual domain name |
| Action | WT | Description |
|---|---|---|
{CC}GuardMandatoryFields |
1 | Validates {Field1} > 0, {Field2} set, Lookup[{Year}] exists; AbortExecution on failure |
{CC}Calculate{WageTypeName} |
{nr} | {short description} |
| Action | Case | Description |
|---|---|---|
{CC}ValidateNationalId |
{CC}.{Case1} |
{short description} |
| Case | Fields | Description | Availability |
|---|---|---|---|
{CC}.{Case1} |
{CC}.{Field1}, {CC}.{Field2} |
{Description} | always |
{CC}.{Case2} |
{CC}.{Field3} |
{Description} | {Condition} is set |
| Case | Fields | Description |
|---|---|---|
{CC}.{CompanyCase1} |
{CC}.{Field1} |
{Description} |
"layers": [
{ "level": 1, "priority": 1, "regulationName": "{CC}.{Name}" },
{ "level": 1, "priority": 2, "regulationName": "{CC}.{Name}.Data.{Source1}" },
{ "level": 1, "priority": 3, "regulationName": "{CC}.{Name}.Data.{Source2}" }
]PE selects the correct regulation version automatically based on the
payrun EvaluationDate — retro-payruns use historical versions without manual config.
| Folder | Content | Version |
|---|---|---|
{Year}/ |
Functional regulation {Year} | {Year}.1-alpha.dev |
Data.{Source1}.{Year}/ |
{Source1} data regulation {Year} | {Year}.1-alpha.dev |
Data.{Source2}.{Year}/ |
{Source2} data regulation {Year} | {Year}.1-alpha.dev |
# Standard payroll
Test.{Year}.pecmd
# {Special scenario, if applicable}
Test.{Scenario}.{Year}.pecmd
# 1 — Import regulation and data
{Year}/Setup.pecmd
# 2 — Run all tests
{Year}/Test.All.pecmd
| Regulation | Source | Update Cycle |
|---|---|---|
Data.{Source1} |
{Authority} — {Publication name} | Annual ({Month}) |
Data.{Source2} |
{Authority} — {Publication name} | Annual ({Month}) |
Data.{Source3} |
{Authority} — {Publication name} | Semi-annual (1 Jan + 1 Jul) |
Reports are independent of the test suite and located in {Year}/Reports/.
Each report lives in its own subfolder with all required files co-located.
| ID | Name | DB Name | Description |
|---|---|---|---|
| R01 | {ReportName1} | {CC}.{ReportName1} |
{Description — period/YTD/annual} |
| R02 | {ReportName2} | {CC}.{ReportName2} |
{Description} |
See {Year}/Docs/{CC}.{Name}-UpdateWorkflow.md
for the complete year-over-year update process ({key items: rates, brackets, ceilings, etc.}).
{Description — what is missing, why, and how the gap can be closed if needed.}
{Description.}
- {Law/Ordinance 1} — {short description of what it governs}
- {Law/Ordinance 2} — {short description}
- {Official Website} — https://{url}