Skip to content

[19.0][ADD] payroll_rule_parameter: date-versioned parameters for salary rules - #283

Open
neoand wants to merge 1 commit into
OCA:19.0from
neoand:19.0-add-payroll_rule_parameter
Open

[19.0][ADD] payroll_rule_parameter: date-versioned parameters for salary rules#283
neoand wants to merge 1 commit into
OCA:19.0from
neoand:19.0-add-payroll_rule_parameter

Conversation

@neoand

@neoand neoand commented Aug 8, 2026

Copy link
Copy Markdown

New module: date-versioned parameters for salary rules.

Why

Tax brackets, contribution rates and legal thresholds are data, not code. With nowhere to put them they end up hard-coded inside amount_python_compute, and two things follow:

  • every legal update means editing every rule that happens to use the figure;
  • recomputing an old payslip silently applies today's rates to a period they never applied to.

This is not hypothetical. Localisations that keep their tax tables inside amount_python_compute end up carrying thousands of lines of Python as rule data, where a single mistyped literal is invisible to review and to any linter. The same localisation expressed with versioned parameters needs a fraction of that, and each legal change becomes one new dated value.

What it adds

  • hr.rule.parameter — a named parameter with a unique code
  • hr.rule.parameter.value — the value it takes from a given date onwards
  • hr.rule.parameter._get_parameter_from_code(code, date) — resolution by date
  • payslip.rule_parameter(code) — usable from a salary rule, resolved on the payslip's own date_to

A value may be a plain number:

0.0192

or a structure, such as a list of brackets:

[(0.0, 0.0, 0.0192), (7735.0, 148.51, 0.064), (65651.07, 3866.42, 0.1088)]

Read from a rule:

brackets = payslip.rule_parameter("income_tax_brackets")
base = categories.GROSS
for lower_limit, fixed_fee, rate in reversed(brackets):
    if base > lower_limit:
        result = -(fixed_fee + (base - lower_limit) * rate)
        break

Values are read with safe_eval, and an unevaluable value raises an error naming the parameter and the date rather than failing deep inside a rule.

Testing

0 failed, 0 errors of 9 tests on odoo:19.0 Community, on a database without demo data.

Coverage: resolution by date, inclusive date_from boundary, structured values, unknown code, date before the first value, raise_if_not_found=False, duplicate code rejected, unevaluable value reports its code, and — the one that matters most — a rule computing a 2025 payslip gets the 2025 rate while the same rule on a 2026 payslip gets the 2026 one.

Fixtures are built in setUpClass; the module ships no demo data.

Notes

The API name _get_parameter_from_code deliberately matches the one developers coming from Odoo Enterprise already know, so existing rules can be reused unchanged. The implementation is independent.

Two Odoo 19 details worth flagging for other modules in this repo:

  • _sql_constraints as a list of tuples is silently ignored in 19.0; constraints have to be declared as models.Constraint(...) attributes. My unique constraint simply never reached the database until I switched, and only a test caught it.
  • In search views, <group expand="0" string="Group By"> no longer validates — 19.0 wants a bare <group> with domain="[]" on the filters.

Assisted-by: Claude Opus 4.8

Disclosed per the OCA Generative AI / LLM Policy.
Developed and verified under my direction and review; I take responsibility for the contribution.

@OCA-git-bot OCA-git-bot added series:19.0 mod:payroll_rule_parameter Module payroll_rule_parameter labels Aug 8, 2026
@neoand
neoand force-pushed the 19.0-add-payroll_rule_parameter branch 2 times, most recently from a3ddeec to 0dfbc75 Compare August 8, 2026 16:36

@CristianoMafraJunior CristianoMafraJunior left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…ary rules

Tax brackets, contribution rates and legal thresholds are data, not code.
With nowhere to put them they end up hard-coded inside amount_python_compute,
so every legal update means editing every rule that uses them — and
recomputing an old payslip silently applies today's rates to a period they
never applied to.

This module adds hr.rule.parameter / hr.rule.parameter.value, whose value is
versioned by the date it comes into force, and exposes it to salary rules as
payslip.rule_parameter(code), resolved on the payslip's own date_to.

A value can be a plain number or a structure, e.g. a list of tax brackets
[(lower_limit, fixed_fee, rate), ...], evaluated with safe_eval.

Tests cover date resolution, inclusive boundaries, structured values, unknown
codes, dates before the first value, duplicate codes, unevaluable values, and
that a rule computing a 2025 payslip gets the 2025 rate rather than today's.
Fixtures are built in setUpClass: no demo data required.

Assisted-by: Claude Opus 4.8
@neoand
neoand force-pushed the 19.0-add-payroll_rule_parameter branch from 0dfbc75 to 705d0fd Compare August 11, 2026 10:30
@neoand

neoand commented Aug 11, 2026

Copy link
Copy Markdown
Author

Thanks for pointing me to the policy — that one's on me, and it's fixed now.

The commit was using Co-authored-by: for the AI tool, which the policy rules out. I've amended it
to use the Assisted-by: trailer instead and added the disclosure to the description.

Happy to answer anything about the implementation directly — I'd much rather work through review
comments than regenerate the patch. Thanks for taking the time to look at it.

@hitrosol

Copy link
Copy Markdown

Hi @neoand, have you considered payroll_rule_time_parameter (14.0/15.0) as the basis of this module?

This is tagged [ADD], but the feature isn't new here — hr.rule.parameter / hr.rule.parameter.value were moved out of the base payroll module into payroll_rule_time_parameter in #87, maintained by @nimarosa and @appstogrow since #31. It simply never got migrated past 15.0.

I've just migrated its dependency to 18.0: OCA/server-tools#3700. Reviews welcome — and if it looks right to you, carrying it on to 19.0 would give this module the same base to depend on. Worth noting that base_time_parameter already handles typed values including JSON, so bracket tables are covered without evaluating a text column.

My suggestion would be to land this as a migration of the existing module rather than a new one, so 19.0 continues 15.0 instead of starting over beside it — same module name, history and original authors carried forward.

I'm planning to port payroll_rule_time_parameter itself to 18.0, and I'd like the two series to stay consistent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mod:payroll_rule_parameter Module payroll_rule_parameter series:19.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants