Tuesday, September 8, 2026
3 changes · master
Code cleanup and technical improvements
Time off accruals are now calculated more consistently, especially around carryover dates, plan level changes, and accruals granted at the start of a period. This helps employees and HR teams see more accurate leave balances, including future balances shown in the dashboard.
Original PR description
## Issues ### Accrual allocation initialization issue For an accrual allocation, due to `_add_lastcall` initialization method, the first carryover date could be skipped. Indeed this method only…
## Issues
### Accrual allocation initialization issue
For an accrual allocation, due to `_add_lastcall` initialization method, the first carryover date could be skipped. Indeed this method only includes the following accrual "events" in his `nextcall` computation:
- Carryover days expiration date
- Current level next period
- Next level transition
PS: The job of _add_lastcalls was to guess the value of nextcall, lastcall and actual_lastcall after saving the allocation
### Accrual allocation `_process_accrual_plans` issue
For an accrual allocation, to compute the number of days when the "accrued_gain_time" is "start", the code is using a bool field (already_accrued) and was trying to use the same logic as when "accrued_gain_time" is "end", but adding another alternative at the end of the loop. This was a bad idea as it has been proven that it leads to complex, hard to maintain, long, and bug prone code.
Here is the (impossible) challenge of this code:
The function `_process_accrual_plans` tries to update the `number_of_days` according to the accrual "events" (carryover, carryover expiring days, level transition, level period transition-daily-monthly-...). But the problem is that sometimes, it has to process multiple accrual events to compute the `number_of_days` of the allocation in the far future (possible when the user wants to see his number_of_days in the future from the time off dashboard). In this case, when the "accrued_gain_time" is "start" and using 'already_accrued', here's how the function works :
- Run through each accrual event until the nextcall is past the target date (same as when "accrued_gain_time" is "end")
- Run the additionnal alternative
This alternative set 'already_accrued' to True so that the next accrual event in the main loop doesn't accrue the days to the allocation.
But this code also has to take care of each day cron run. In that case, here's how it behaves:
- If the allocation nextcall happens before the target date:
- Run one iteration of the main loop, which probably doesn't add the accrued days as already_accrued is probably True.
- Run the additionnal alternative
This means that all the logic has to be at the same time in the main accrual event loop, and in the alternative, which is really hard, and led to the spaghetti we have today (which still contains a lot of bugs).
To avoid this issue, this PR separates the logic of each case ("accrued_gain_time" "start" or "end"), and removes 'already_accrued'.
## Accrual allocation `_process_accrual_plans` new feature
To make it easier to use, this method now returns a dict containing the accrual values of the allocations on the `target_date`, and do not directly apply the changes on the allocation anymore. For instance, this avoid having to create 'fake_allocation' using `new(origin=self)`.
However, it adds a little bit of complexity from the code, as some function now have to pay attention whether they should read the value from the values in the dict representing the data of the allocation, of the fields themselves (see class description for more explanations).
## Behavior correction
Before this PR, a day belonged to a level only if it was between the start of this level (not included), and the start on the following level (included). As the start of the level was not included, this could lead to some small issues like the days are only accrued on the second days of the level, even when "accrued_gain_time" of the accrual plan is "start".
## Tests
As I spend a lot of time making the tests work, I took this opportunity to make a few changes, mostly to make test simpler to understand, or to correct the tests that were doing wrong assertions.
## Accrual allocation refactoring
- Deleting the property "already_accrued"
- Renaming
- lastcall -> last_accrual : as described in the definition of lastcall, this property contains the "Date of the last accrual allocation"
- actual_lastcall -> lastcall : simpler name
- postpone_max_days -> max_carriedover_duration: clearer name, moreover, the unit of time of this field can be either 'Days' or 'Hours'
- expiring_carryover_days -> previous_carryover_number_of_days: the field expiring_carryover_days contains the number of days the allocation had on the last carryover, so this names fits best
- Adding a few fields to the Form: when creating an allocation with an accrual plan in a Form, everything was running smoothly, and the number_of_days was computed correctly. However, when saving the allocation, as the lastcall, actual_lastcall and nextcall were not saved (no fields matching them in the Form), they needed to be recomputed. So the method _add_lastcall was called to try to approximate what were the values of each of these fields depending on the fields.Date.today().
- Getting out of the infinite compute dependency of `number_of_days`, `number_of_days_display` and `number_of_hours_display`. Those fields were 3 computes fields depending on each other (and the orm was not made to use it that way) -> `number_of_days` is not computed anymore, and the 2 other fields set it using 'inverse' (more standard way of doing things).
task-5977748
[upgrade-8081](https://github.com/odoo/upgrade/pull/8081)The VoIP module was updated as part of the platform migration to Owl 3. This internal cleanup helps keep VoIP flows compatible with the newer web framework without changing day-to-day user behavior.
Original PR description
As part of the Owl 3 migration, replace **onWillUpdateProps** hook with the appropriate Owl 3 alternatives.
The accounting reports code was updated to use the current supported behavior in Odoo's interface framework. This keeps audit balance report screens compatible with the next OWL version while preserving existing tested behavior.
Original PR description
Replaced `useLayoutEffect` with `useEffect` (from `@odoo/owl`) because `useLayoutEffect` is deprecated in OWL3. The useLayoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - TestAccountReportsTours.test_account_reports_audit_tours (account_reports post-install) see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2748320/build/124302666