Tuesday, August 25, 2026
7 changes · 17.0
Resolved issues and error corrections
Bulk leave allocations for a company, department, or employee category now correctly include accrued days from past periods when the plan start date is in the past. This prevents employees from missing earned time off compared with allocations created one employee at a time.
Original PR description
**Problem:** Creating an accrual allocation for a whole company, a department or an employee category, with a plan that started in the past, does not grant the employees the days they should already…
**Problem:** Creating an accrual allocation for a whole company, a department or an employee category, with a plan that started in the past, does not grant the employees the days they should already have accrued. Doing the same allocation employee by employee works. **Steps to reproduce:** 1. Create a monthly accrual plan (e.g. 2 days, gained at the end of the period) 2. Create an accrual allocation for a whole company/department with a start date a few months in the past, and validate it 3. Observe each employee only gets the current period **Current behavior:** The child allocations only get the current period; the backlog between the start date and today is lost. **Expected behavior:** Each employee is back-filled for every elapsed period, exactly like a single-employee allocation. **Cause of the issue:** The single-employee flow runs `_onchange_date_from`, which resets `lastcall` to the allocation start date so `_process_accrual_plans` back-fills every elapsed period. That onchange returns early when there is no `employee_id`, which is always the case for company/department/category allocations, so the parent's `number_of_days` preview stays 0. The per-employee children are then created through `create`, where `_add_lastcalls` sets `lastcall` to the current period; the subsequent accrual run therefore only grants the current period and drops the whole backlog. **Fix:** Restart the child accrual from the allocation's start date before processing it, the same way the single-employee onchange does, so the plan is evaluated period by period for every employee. This is scoped to company/department/ category modes because employee-mode multi allocations already carry the value computed on the parent and must keep it. opw-6308064
Fixed an issue where text entered with a phone or virtual keyboard could be lost when saving an HTML note field immediately after typing. This ensures notes and similar rich-text content are reliably saved, improving mobile data entry reliability.
Original PR description
On a virtual keyboard the editor handles typing as a composition and only commits its history step on a later interaction. The html field marks itself dirty from that step, so right after typing the…
On a virtual keyboard the editor handles typing as a composition and only commits its history step on a later interaction. The html field marks itself dirty from that step, so right after typing the field is not dirty. On save the form calls commitChanges, but it only writes the value when the field is dirty, or on an urgent or inline-style save. None of those hold for a plain sanitized html field, so the typed content is not written to the record. Finalize the pending composition in commitChanges by calling the editor _compositionStep() before that check. commitChanges is the single point every save path goes through, so committing the pending step there marks the field dirty and the content is saved. It does nothing on a physical keyboard, where the composition flag is cleared after each keystroke. Steps to reproduce: 1. Open the Sales app and a quotation. 2. In the chatter, click Activities then Schedule Activity. 3. On a phone, or a browser with a virtual keyboard, fill Summary, tap the note field and type a note. 4. Tap Schedule while the note field still has focus. 5. Open the created activity. => the note is empty Ticket [link](https://www.odoo.com/odoo/project.task/6331719) opw-6331719
This fixes an issue where changing the first occurrence of a recurring Outlook meeting and then syncing could cause Odoo to recreate the full series incorrectly. Individual changes, such as adding an attendee to one occurrence, now stay limited to that occurrence instead of being copied to every event in the series.
Original PR description
The stored rrule of a recurrence embeds a DTSTART line based on the recurrence dtstart (the smallest start among its events). When the first occurrence is moved in Outlook, the Odoo dtstart no longer…
The stored rrule of a recurrence embeds a DTSTART line based on the recurrence dtstart (the smallest start among its events). When the first occurrence is moved in Outlook, the Odoo dtstart no longer matches that DTSTART, but the stored rrule is not recomputed at that point (it only depends on the pattern fields). On a later sync touching the seriesMaster (e.g. after adding an attendee to the moved occurrence), the recurrence values are written again and the rrule is reserialized with a DTSTART based on the moved occurrence. _write_from_microsoft() took this new rrule string as a pattern change and reapplied the recurrence: all occurrences were deleted and recreated as copies of the moved one, spreading its specific data (e.g. the newly added attendee) to the whole series. Ignore the DTSTART line when comparing the rrule before and after the write: a DTSTART-only difference does not reflect any pattern change in Outlook. An actual pattern change (FREQ, UNTIL, INTERVAL, ...) still reapplies the recurrence as before. Steps to reproduce: 1. In Outlook, create a recurring event 2. In Odoo, run the calendar sync 3. In Outlook, move the first occurrence of the recurrence (shift its start and stop time by 30 minutes) 4. In Odoo, run the sync 5. In Outlook, add an attendee to that same first occurrence 6. In Odoo, run the sync All the occurrences are deleted and recreated as copies of the first one, and the attendee ends up on every occurrence instead of one. opw-5129848
This fix ensures Odoo correctly refreshes whether taxes are marked as used when related accounting, sales, purchase, expenses, or point of sale records change. This helps users see accurate tax status information and avoids stale details in accounting workflows.
Original PR description
Currently, `is_used` is computed using queries on `account.move.line`, `account.reconcile.model.line`, etc. As a result, it has no depends and is not automatically updated when records in either model are created, modified, or deleted. This commit reverse M2M fields for respective models and use it as dependency to `_compute_is_used`. It also adds a missing dependency of `is_used` to `_compute_repartition_lines_str`.
Stripe express checkout now stops and refreshes the cart if the billing address changes the applicable tax rules. This prevents customers from being charged based on outdated tax calculations and helps ensure invoices use the correct VAT amount.
Original PR description
Issue: process_express_checkout assigns partner_id directly on an anonymous cart (removing pricelist_id from the fields to recompute, to keep the pricelist stable), so the address update is never…
Issue: process_express_checkout assigns partner_id directly on an anonymous cart (removing pricelist_id from the fields to recompute, to keep the pricelist stable), so the address update is never called. The order fiscal_position_id still refreshes via its stored compute, but the line tax_id stays with the previous mapping: _compute_tax_id does not depend on fiscal_position_id, so it is never re-triggered. The invoice is then posted with the wrong VAT. Fix: When the billing address resolves to a different fiscal position than the one used to quote the displayed amount, recompute the taxes and abort the payment: the endpoint returns False and sets a shop_warning, and the Stripe express checkout form reloads the page so the customer sees (and re-accepts) the refreshed prices before retrying. _recompute_taxes is wrapped in a try/except UserError to avoid blocking the flow if an external tax computation (e.g. Avatax) fails. Steps to reproduce: - Configure the company with two auto-applied fiscal positions, e.g. a domestic one (Luxembourg, 3% sale tax) and an "Extra-Community" one that maps the domestic tax to 0% EC for non-EU countries. - Configure Stripe with an express payment method (Apple Pay, Google Pay or Link). - Log out and browse the shop with a geoip pointing to a non-EU country so the cart picks up the "Extra-Community" fiscal position. - Add a product to the cart. - Observe: the cart line has the 0% EC tax. - Trigger the express payment button and pay using a billing address located in the domestic country (Luxembourg). - Observe on the confirmed order: fiscal_position_id is the domestic one but the line tax_id still holds the 0% EC tax. The invoice is posted with 0% VAT instead of the expected 3%. opw-6213195 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Express checkout now stops the payment when a customer's billing address changes the applicable tax rules, refreshes the cart totals, and asks the customer to confirm again. This prevents orders and invoices from being created with incorrect VAT while ensuring customers are not charged more than the amount they approved.
Original PR description
Issue: process_express_checkout assigns partner_id directly on an anonymous cart (inside a request.env.protecting block, to keep the pricelist stable), so _update_address is never called.…
Issue: process_express_checkout assigns partner_id directly on an anonymous cart (inside a request.env.protecting block, to keep the pricelist stable), so _update_address is never called. fiscal_position_id still refreshes via its stored compute, but the line tax_ids stay with the previous mapping. Fix: Recompute the line tax_ids when the fiscal position changed. We do not call _recompute_taxes because it also resets unit prices via the pricelist, and the customer already accepted the displayed unit prices. Steps to reproduce: - Configure the company with two auto-applied fiscal positions, e.g. a domestic one (Luxembourg, 3% sale tax) and an "Extra-Community" one that maps the domestic tax to 0% EC for non-EU countries. - Configure Stripe with an express payment method (Apple Pay, Google Pay or Link). - Log out and browse the shop with a geoip pointing to a non-EU country so the cart picks up the "Extra-Community" fiscal position. - Add a product to the cart. - Observe: the cart line has the 0% EC tax. - Trigger the express payment button and pay using a billing address located in the domestic country (Luxembourg). - Observe on the confirmed order: fiscal_position_id is the domestic one but the line tax_ids still hold the 0% EC tax. The invoice is posted with 0% VAT instead of the expected 3%. opw-6213195 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Fixed an accounting asset issue where manually selecting both a vendor bill line and its related non-deductible tax line caused the asset value to be overstated. Asset values now match the correct bill amount, helping avoid inflated depreciation bases and accounting discrepancies.
Original PR description
### Issue before this commit: When manually selecting both a bill's base line and its own non-deductible tax line in an asset's "Bills" tab, the resulting asset's original_value double-counted the…
### Issue before this commit: When manually selecting both a bill's base line and its own non-deductible tax line in an asset's "Bills" tab, the resulting asset's original_value double-counted the tax amount. ### Steps to reproduce the issue: 1. Download Accounting and l10n_be (just because it's easier since taxes needed already created, but possible to reproduce it in every country) 2. Go to Charts of Accounts > account 24100 > tab Automation > be sure it's set on No automation 3. Go to Vendor Bills and create a new one setting the account as 24000 as account, price for example 10000 and 21% D50 tax 4. After confirmation go to Assets and create a new one, then switch to Bills tab and add the 2 lines of the bill you just created with balanca 10000 and 1050 (that is the tax) 5. Go back to Asset tab and see that the original amount reported is 12100 instead of 11050 as it should be N.B. If instead you go back to chart of accounts and you set Draft as automation method, then create the bill and follow the smart button that appears you see the asset will be created with the correct original amount of 11050 ### Cause of the issue: https://github.com/odoo/enterprise/blob/c8cf04b59c8fb8ea141725c4a3ffd3d3fe46c0d7/account_asset/models/account_asset.py#L325-L334 This function adds non_deductible_tax_value for every base line in original_move_line_ids, regardless of whether the corresponding tax move line was also manually included in the selection. When it was, its amount was already counted once via related_purchase_value, so adding non_deductible_tax_value on top counted it a second time. ### Reason to introduce the fix: The fix skips adding non_deductible_tax_value whenever a tax line is present among the selected original_move_line_ids, since in that case the non-deductible amount is already included through the selected lines themselves. This restores the correct original_value in the manual-selection flow that aligns with the automatic flow. opw-6414085