Friday, December 12, 2025
7 changes · 18.0
Resolved issues and error corrections
This update resolves a recursion error that occurred when updating Point of Sale configuration settings, specifically related to fiscal positions. The fix prevents an infinite loop caused by archiving fiscal positions, ensuring smoother configuration updates.
Original PR description
**Steps To Reproduce:-** 1. Install point_of_sale in 17.0 2. Activate flexible taxes setting 3. set default fiscal position and after that archived that fiscal position. 4. try edit and save the POS…
**Steps To Reproduce:-**
1. Install point_of_sale in 17.0
2. Activate flexible taxes setting
3. set default fiscal position and after that archived that fiscal position.
4. try edit and save the POS config any operation below mentioned recursion error will come.
**Issue :-**
Due to archived record of fiscal postion is keep updating due to not satisfying this condition [config.default_fiscal_position_id.id not in config.fiscal_position_ids.ids](https://github.com/odoo/odoo/blob/62652ba3a7a90699e7aa8ff98e2d4980f1b43694/addons/point_of_sale/models/pos_config.py#L529) here ``config.fiscal_position_ids`` on this active filter is applying and it coming empty and going to update many2many field this process goes infinite due to archive fiscal position record
**FIX:-**
adding the check of active record fiscal position
```
File "/data/build/odoo/addons/point_of_sale/models/pos_config.py", line 442, in _set_fiscal_position
config.fiscal_position_ids = [(4, config.default_fiscal_position_id.id)]
File "/data/build/odoo/odoo/fields.py", line 1337, in __set__
records.write({self.name: write_value})
File "/data/build/odoo/addons/pos_restaurant/models/pos_config.py", line 52, in write
return super(PosConfig, self).write(vals)
File "/data/build/odoo/addons/point_of_sale/models/pos_config.py", line 420, in write
self.sudo()._set_fiscal_position()
File "/data/build/odoo/addons/point_of_sale/models/pos_config.py", line 442, in _set_fiscal_position
config.fiscal_position_ids = [(4, config.default_fiscal_position_id.id)]
File "/data/build/odoo/odoo/fields.py", line 1337, in __set__
records.write({self.name: write_value})
File "/data/build/odoo/addons/pos_restaurant/models/pos_config.py", line 52, in write
return super(PosConfig, self).write(vals)
File "/data/build/odoo/addons/point_of_sale/models/pos_config.py", line 420, in write
self.sudo()._set_fiscal_position()
File "/data/build/odoo/addons/point_of_sale/models/pos_config.py", line 442, in _set_fiscal_position
config.fiscal_position_ids = [(4, config.default_fiscal_position_id.id)]
File "/data/build/odoo/odoo/fields.py", line 1337, in __set__
records.write({self.name: write_value})
File "/data/build/odoo/addons/pos_restaurant/models/pos_config.py", line 52, in write
return super(PosConfig, self).write(vals)
File "/data/build/odoo/addons/point_of_sale/models/pos_config.py", line 420, in write
self.sudo()._set_fiscal_position()
File "/data/build/odoo/addons/point_of_sale/models/pos_config.py", line 442, in _set_fiscal_position
config.fiscal_position_ids = [(4, config.default_fiscal_position_id.id)]
File "/data/build/odoo/odoo/fields.py", line 1337, in __set__
records.write({self.name: write_value})
File "/data/build/odoo/addons/pos_restaurant/models/pos_config.py", line 52, in write
return super(PosConfig, self).write(vals)
File "/data/build/odoo/addons/point_of_sale/models/pos_config.py", line 418, in write
result = super(PosConfig, self).write(vals)
File "/data/build/odoo/odoo/models.py", line 3820, in write
field.write(self, value)
File "/data/build/odoo/odoo/fields.py", line 4287, in write
return self.write_batch([(records, value)])
File "/data/build/odoo/odoo/fields.py", line 4308, in write_batch
return self.write_real(records_commands_list, create)
File "/data/build/odoo/odoo/fields.py", line 4835, in write_real
old_relation = {record.id: set(record[self.name]._ids) for record in records}
File "/data/build/odoo/odoo/fields.py", line 4835, in <dictcomp>
old_relation = {record.id: set(record[self.name]._ids) for record in records}
File "/data/build/odoo/odoo/models.py", line 6007, in __getitem__
return self._fields[key].__get__(self, self.env.registry[self._name])
File "/data/build/odoo/odoo/fields.py", line 2824, in __get__
return super().__get__(records, owner)
File "/data/build/odoo/odoo/fields.py", line 1270, in __get__
return self.convert_to_record(value, record)
File "/data/build/odoo/odoo/fields.py", line 4199, in convert_to_record
corecords = corecords.filtered(Comodel._active_name).with_prefetch(prefetch_ids)
File "/data/build/odoo/odoo/models.py", line 5496, in filtered
return self.browse([rec.id for rec in self if func(rec)])
File "/data/build/odoo/odoo/models.py", line 5496, in <listcomp>
return self.browse([rec.id for rec in self if func(rec)])
File "/data/build/odoo/odoo/models.py", line 5493, in <lambda>
func = lambda rec: any(rec.mapped(name))
File "/data/build/odoo/odoo/models.py", line 5470, in mapped
recs = recs._fields[name].mapped(recs)
File "/data/build/odoo/odoo/fields.py", line 1299, in mapped
return self.convert_to_record_multi(vals, records)
File "/data/build/odoo/odoo/fields.py", line 942, in convert_to_record_multi
return [convert(value, record) for value, record in zip(values, records)]
File "/data/build/odoo/odoo/fields.py", line 942, in <listcomp>
return [convert(value, record) for value, record in zip(values, records)]
File "/data/build/odoo/odoo/models.py", line 5844, in __iter__
yield self.__class__(self.env, (id_,), self._prefetch_ids)
RecursionError: maximum recursion depth exceeded
```
**OPW** - 5208462
**UPG** - 3248441
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#233358This update corrects a bug where accrual plans were incorrectly blocking leave accrual, even with remaining balances below the cap. The fix ensures that leave accruals continue as expected, preventing users from missing out on earned time off. It addresses an issue with how future leave calculations were being handled.
Original PR description
Accrual plan for leave days gets blocked, even when the remaining leave balance is below the cap. As a result, no additional leaves are accrued beyond a certain point, even though they should be. #…
Accrual plan for leave days gets blocked, even when the remaining leave balance is below the cap. As a result, no additional leaves are accrued beyond a certain point, even though they should be.
# Steps to reproduce:
Go to time off app
* Create a new leave type.
* Create a new accrual plan with:
- one milestone :
- 2 days accrued per month
- Cap: 10 days
- start accruing 1 days after
- No expiration
- Carry over: All
* Create and validate a leave allocation
- 1 year ago
- new leave type
- new accrual plan
* Take the maximum number of leaves available.
* Advance the computer calendar by 1 year.
* Again, take the maximum number of leaves.
* Advance the computer calendar by another year.
* Try to take a future leave.
-> Issue: It’s not possible to take a future leave, the number of accrued days has stopped increasing. The accrual plan appears blocked.
Objective : The accrual plan should continue to allocate leave days even if leaves have been consumed regularly, as long as the remaining leaves are under the cap.
## Issue
Before going further: the property `leaves_taken` of the `hr.leave.allocation` is supposed to contain the number of leaves this allocation cover until "today".
In the `_test_get_allocation_future_leaves1` added test, in the last line of the test :
`assert_virtual_leaves_equal(self, leave_type_day, 2, self.employee_emp, date='2023-02-01')`
When calling `get_allocation_data` with a `target_date` set in the future, the result is wrong. Here is how it works :
`get_allocation_data`
...
.....`_get_consumed_leaves` (1)
...........`_get_future_leaves_on` (2)
...............`_process_accrual_plans` (3)
....................`_compute_leaves` (4)
.........................`_get_consumed_leaves` (5)
..............................`get_future_leaves_on` (6)
...................................`process_accrual_plans` (7)
**A)** The method **(2)** try to calculate the added number of days each allocation will have on `target_date`. So it creates a copy of the allocation in memory using the 'new' method:
`fake_allocation = self.env['hr.leave.allocation'].with_context(default_date_from=accrual_date).new(origin=self)`
It will then update it to `target_date` using `_process_accrual_plans` and will return the difference of days between the
updated `fake_allocation` and the current allocation (`self`)
**B)** Before iterating over each accrual date, the `_process_accrual_plans` **(3)** will get the `leaves_taken` property which is a computed field. It will trigger `_compute_leaves`.
**C)** The method **(4)** will call `_get_consumed_leaves`, and so the nightmare begins.
**D)** The method **(6)** will create a second `fake_allocation` based on the origin of the first `fake_allocation` (see **A)**).
**E)** This time, `_process_accrual_plans` **(7)** will also look at the `leaves_taken`, but won't trigger the `_compute_leaves` probably because the current allocation is a `fake_allocation` of a `fake_allocation`, and one property of the `new` method is that `Two new records with the same origin record are considered equal.`. Therefore, the `leaves_taken` is considered to be already computed (but it's not).
So `_process_accrual_plans` read the `leaves_taken` which is 0 (probably the default value of `leaves_taken`), but it should be 20 !
**F)** As the value of `leaves_taken` is wrong, the fake_allocation n°2 is also wrong, and its `number_of_day` is 10 but the `number_of_days` of the origin allocation is 20. So `get_future_leaves_on` **(6)** will return -10 which makes no sense, and all the previous calls computations will be wrong. And the final `virtual_remaining_leaves` value will be 0 instead of 2.
## Source of the issue
In the `_process_accrual_plans` method, for each allocation, `leaves_taken` is only computed once at the start of the loop over the allocation "important" dates (see `nextcall` property of `hr.leave.allocation`). At this moment, the method calculates the `leaves_taken` the allocation will have on the `accrual_date` parameter. Yet, this property can change depending on the date the allocation is on (`nextcall` property) which leads to some issues in the computation of the `allocation.number_of_days`.
## Solution
For each allocation, compute the `leaves_taken` at every iteration trough the values of `nextcall`. BUT, this can trigger an infinite loop as computing `leaves_taken` calls `_get_consumed_leaves` which calls `_get_future_leaves_on`, which calls `_process_accrual_plans` ... To avoid this, this PR add the context variable `precomputed_allocations` (will be converted into a function parameter in master) which will prevent `_get_consumed_leaves` from calling `_get_future_leaves_on` for the allocations already up to date (contained by this very `precomputed_allocations` context variable).
opw-4934391This update optimizes how Odoo calculates potential free products in loyalty programs. Previously, the system unnecessarily checked all reward products, leading to slow performance. This change improves the speed and efficiency of the loyalty reward calculation process, particularly when multiple rewards are involved.
Original PR description
Before this commit, the computation of potential free product quantities looped through all reward products even after finding a valid one. This led to unnecessary calculations and performance degradation, especially when multiple reward products were involved. opw-5268991 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Users were experiencing a bug in the eCommerce checkout process where they couldn't save their delivery address, causing the flow to stall. This PR resolves the issue by adding a missing field, preventing the checkout from failing. The fix ensures a smooth and functional checkout experience for customers.
Original PR description
Description of the issue/feature this PR addresses: In eCommerce checkout, users cannot proceed past the delivery step (/shop/address). When clicking on the "Save Address" button, nothing happens and the flow gets stuck. The issue is due to the missing field l10n_latam_identification_type_id in the address form. This is the same root cause addressed in [PR #185914](https://github.com/odoo/odoo/pull/185914) Desired behavior after PR is merged: Checkout flow continues normally after clicking "Save Address". --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where downpayment lines were incorrectly duplicated on sales orders when a 'Preparation Display' was active in the POS system. The fix ensures that downpayment lines are created only once, streamlining the sales process and preventing data inconsistencies. This improves order accuracy and reduces potential errors.
Original PR description
With a Preparation Display active. When doing a Downpayment for an SO in POS. The Downpaymentline was doubled in the SO Steps to reproduce: ------------------- * Create a SO * Setup Preparation Display * In POS, Settle a Downpayment for that SO * Validate and pay the order > Observation: The Downpayement line is doubled on the SO Why the fix: ------------ `sale_order_line_id` is set after creating the line. This verification prevent double creating when multiple sync are done. opw-5076001
This update fixes an issue where public holidays were incorrectly counted as excess days in leave calculations. The change ensures leave durations are accurately calculated before confirmation, resolving a discrepancy caused by how attendance was previously processed. This prevents overreporting of leave time.
Original PR description
### Steps to reproduce: - Install Time off apps - Create two consecutive allocations (e.g. one for 2025 and one for 2026) - Create a leave that overlap with the two allocation (e.g. from 8th Dec to…
### Steps to reproduce: - Install Time off apps - Create two consecutive allocations (e.g. one for 2025 and one for 2026) - Create a leave that overlap with the two allocation (e.g. from 8th Dec to 3rd Jan) - Create a public holiday at the beginning of the second allocation (e.g. on 1st Jan 2026) ### Cause: When we are checking the leave duration after having a public holiday the will return the attendance without the public holidays duration so when subtracting the attendance duration from the leave duration we will have a remaining amout equals to the public holiday duration and it will be considered as excess days. https://github.com/odoo/odoo/blob/06e47d8601ba56b1650eeaeef71ebd7a4af39b8b/addons/hr_holidays/models/hr_employee_base.py#L228-L230 https://github.com/odoo/odoo/blob/06e47d8601ba56b1650eeaeef71ebd7a4af39b8b/addons/hr_holidays/models/hr_employee_base.py#L246-L254 ### Fix: We compute the leave duration before confirming it instead of computed them after opw-5006119
This update resolves an issue where work orders were occasionally displaying incorrect states due to how their status was being evaluated. By adjusting the evaluation timing to the 'button_mark_done' stage, the system now accurately reflects the correct work order state. This ensures data consistency and reliable reporting.
Original PR description
Previous fix was not sufficient (https://github.com/odoo/odoo/pull/238832) In some cases, evaluating state and reservation_state within _post_inventory's override in mrp_account leads to incorrect workorders state. By evaluating them at end of button_mark_done, the workorders states are correct. task: 5247116 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr