Rule parameters¶
Legal values change over time: tax brackets, ceilings, contribution rates, minimum wages... A rule
parameter (hr.rule.parameter) stores such a value under a code, with one dated value
(hr.rule.parameter.value) per period of validity. Salary rules read the value valid at the
date of the payslip, so that:
a new legal year only requires a new dated value, not a change of the salary rules;
recomputing an old payslip uses the values of its period.
Parameters and values¶
hr.rule.parametername,code(unique among the active parameters),country_idandparameter_version_ids, the dated values.salary_rule_idslists the rules whose python code mentions the code between quotes.hr.rule.parameter.valuerule_parameter_id,date_fromandparameter_value. A value is valid from itsdate_fromuntil thedate_fromof the next value: there is no end date. Two values of a parameter cannot start on the same day; creating a value at an existingdate_fromreplaces the existing one.
parameter_value is a text holding a python literal, evaluated with
expr_eval(): numbers, strings, lists, tuples, dicts, sets,
arithmetic, comparisons and calls to min, max, round, float, int and set. There are
no variables. Invalid expressions are refused when the value is saved. Typical values are:
450000 # an amount
0.13 # a rate
[(100000, 0.05), (300000, 0.10), (400000, 0.15)] # tax brackets
{'single': 3000, 'married': 4500} # values by case
Reading a parameter¶
In a salary rule, call payslip._rule_parameter(code): it returns the value valid at the
reference date of the payslip (its date_to by default, see
the payslip page). A reference_date can be given
explicitly.
# amount_python_compute of the TAXABLE_AMOUNT rule of l10n_bd_hr_payroll
yearly_income_exempt = min(payslip._rule_parameter('l10n_bd_maximum_yearly_exempt'),
result_rules['GROSS']['total'] * 12 / 3)
result = result_rules['GROSS']['total'] - yearly_income_exempt / 12
Outside of the payslips, use
_get_parameter_from_code(), which returns the value of
the most recent value with date_from <= date (today if no date is given). If there is none, it
raises a UserError, or returns None with raise_if_not_found=False.
Example
from datetime import date
Parameter = env['hr.rule.parameter']
Parameter._get_parameter_from_code('l10n_bd_maximum_yearly_exempt', date(2026, 1, 1))
# 450000
Parameter._get_parameter_from_code('l10n_bd_yearly_tax_rates', date(2026, 1, 1))
# [(100000, 0.05), (300000, 0.1), (400000, 0.15), (500000, 0.2), (99999999999999999, 0.25)]
Parameter._get_parameter_from_code(
'l10n_bd_maximum_yearly_exempt', date(2020, 1, 1), raise_if_not_found=False)
# None (the first value starts on 2024-01-01)
# A new value for the second half of 2026
param = env.ref('l10n_bd_hr_payroll.l10n_bd_rule_parameter_maximum_yearly_exempt')
env['hr.rule.parameter.value'].create({
'rule_parameter_id': param.id,
'date_from': date(2026, 7, 1),
'parameter_value': '500000',
})
Parameter._get_parameter_from_code('l10n_bd_maximum_yearly_exempt', date(2026, 6, 30))
# 450000
Parameter._get_parameter_from_code('l10n_bd_maximum_yearly_exempt', date(2026, 7, 1))
# 500000
The lookup is cached per code, date and allowed companies. The cache is invalidated when values
are created or when their date_from or parameter_value change. The returned value is a deep
copy: a rule can modify the list or dict it receives without altering the next payslips.
Parameters in module data¶
Localization modules declare parameters and their values in a data file (usually
data/hr_rule_parameters_data.xml), e.g. in l10n_bd_hr_payroll:
<record id="l10n_bd_rule_parameter_maximum_yearly_exempt" model="hr.rule.parameter">
<field name="name">Bangladesh: Maximum Yearly Exempt</field>
<field name="code">l10n_bd_maximum_yearly_exempt</field>
<field name="country_id" ref="base.bd"/>
</record>
<record id="l10n_bd_rule_parameter_maximum_yearly_exempt_2024" model="hr.rule.parameter.value">
<field name="parameter_value">450000</field>
<field name="rule_parameter_id" ref="l10n_bd_rule_parameter_maximum_yearly_exempt"/>
<field name="date_from" eval="datetime(2024, 1, 1).date()"/>
</record>
Prefix the codes with the localization (l10n_xx_): codes are global to the database. A new
legal year is a new hr.rule.parameter.value record; never modify the value of a past period,
as it would change the result of recomputed payslips.
As for salary rules, a parameter created by the module data and later modified by a user is
flagged modified_by_user, and its XML ids (and those of its values) are set noupdate, so
that module updates no longer overwrite the user's changes.
action_reset_rule_parameter() reverts this: it deletes
the values created by users and reloads the payroll data files of the country (see
Writing a payroll localization). Users cannot delete parameters or values created by the
system; they can archive the parameter instead.
Tip
In tests, TestPayrollBase._add_rule_parameter_value(code, value, date)
(hr_payroll/tests/common.py) creates or updates a value at a date.