Advanced Payroll
This tutorial extends the Basic Payroll with two additional regulations:
- Insurance regulation — income-dependent contribution using a range lookup
- Company regulation — employee benefits that can occur multiple times per month
Both regulations are loaded on top of StartRegulation as separate payroll layers and verified in a combined test.
Insurance Regulation
The insurance contribution is determined by the employee's gross salary, divided into three rate classes:
| Class | Salary range | Rate |
|---|---|---|
A |
1 – 2 999 | 30 |
B |
3 000 – 5 999 | 45 |
C |
6 000+ | 60 |
The rate is stored in a Lookup and resolved at runtime using a range lookup function.
Example Insurance.yaml:
# yaml-language-server: $schema=PayrollEngine.Exchange.schema.json
createdObjectDate: 2023-01-01T00:00:00Z
tenants:
- identifier: StartTenant
regulations:
- name: InsuranceRegulation
sharedRegulation: true # available to other tenants as a shared regulation
baseRegulations:
- StartRegulation # inherits cases and wage types from StartRegulation
wageTypes:
- wageTypeNumber: 200 # processed after WT 100 (Salary)
name: InsuranceRate
valueExpression: GetRangeLookup<decimal>("InsuranceRate", WageType[100]) # lookup rate by salary
collectors:
- Deduction
lookups:
- name: InsuranceRate
values:
- key: A
value: "30"
rangeValue: 1 # class A: salary >= 1
- key: B
value: "45"
rangeValue: 3000 # class B: salary >= 3000
- key: C
value: "60"
rangeValue: 6000 # class C: salary >= 6000
payrolls:
- name: StartPayroll
layers:
- regulationName: InsuranceRegulation
level: 2 # layer 2 runs after StartRegulation (level 1)
updateMode: NoUpdate # extend the payroll, do not replace it
updateMode: NoUpdate
GetRangeLookup selects the lookup entry whose rangeValue is the highest value still at or below the input — here WageType[100], the salary from level 1. For a salary of 5 000, class B is selected and the contribution is 45.
Load the insurance regulation:
Insurance.Setup.pecmd
Company Regulation
Employees can receive a project benefit any number of times within a month. Each benefit entry is a discrete Moment value — not a period — so multiple entries for the same month are summed independently.
Example Company.yaml:
# yaml-language-server: $schema=PayrollEngine.Exchange.schema.json
createdObjectDate: 2023-01-01T00:00:00Z
tenants:
- identifier: StartTenant
regulations:
- name: CompanyRegulation
baseRegulations:
- InsuranceRegulation # inherits from both lower regulation layers
cases:
- name: Benefit
caseType: Employee
fields:
- name: Benefit
valueType: Money
timeType: Moment # one-time value — not tied to a calendar period
wageTypes:
- wageTypeNumber: 100.1 # processed between WT 100 and WT 200
name: Benefit
valueActions:
- ^^Benefit # sum all Benefit Moment entries for the period
collectors:
- Income
payrolls:
- name: StartPayroll
layers:
- regulationName: CompanyRegulation
level: 3 # top layer — can override anything in layers 1 and 2
updateMode: NoUpdate
updateMode: NoUpdate
Load the company regulation:
Company.Setup.pecmd
Payroll Test
The combined test verifies all three layers at once. Two benefit entries and one salary are set up, and the expected results cover all active wage types and collectors.
Full test file: Company.Test.et.yaml
Case data:
cases:
- case:
caseName: Salary
values:
- caseFieldName: Salary
value: "5000"
start: 2023-01-01T00:00:00Z
created: 2022-11-04T00:00:00Z
- reason: Project A
case:
caseName: Benefit
values:
- caseFieldName: Benefit
value: "225"
start: 2023-01-14T00:00:00Z # Moment: 14th Jan
created: 2022-12-12T00:00:00Z
- reason: Project B
case:
caseName: Benefit
values:
- caseFieldName: Benefit
value: "250"
start: 2023-01-26T00:00:00Z # Moment: 26th Jan — independent entry
created: 2022-01-14T00:00:00Z
updateMode: NoUpdate
Expected results for January 2023:
| Wage Type / Collector | Expected | Calculation |
|---|---|---|
100 Salary |
5 000 | base salary |
100.1 Benefit |
475 | 225 + 250 (two Moment entries) |
200 InsuranceRate |
45 | class B (salary 5 000) |
Income |
5 475 | 5 000 + 475 |
Deduction |
−45 | negated insurance contribution |
Run the test:
Company.Test.pecmd
mario.nuñez@foo.com.
Next Steps
- Forecasts — what-if scenarios without affecting production
- Reports — generating payroll documents
- Automation — No-Code and Low-Code regulation scripting
- Payroll Testing — automated test patterns
- Extended Functions
- Custom Actions
- Examples — all payroll examples and demos
- Articles — blog posts and technical articles