Monday, April 13, 2026
14 changes · saas-19.2
Resolved issues and error corrections
This update ensures payroll calculations and leave allocations are accurate by restricting work entry types to match the employee's country. A new automated process now converts generic work entry types to localized versions upon installation, resolving potential errors and improving data consistency across the system.
This update resolves an issue where the 'Results Brought Forward' line on the Luxembourg balance sheet displayed incorrect values. The fix adjusts how the balance sheet calculates retained earnings, ensuring accurate reporting after year-end adjustments are made. This improves the reliability of financial reporting for Luxembourg companies.
Original PR description
… sheet Steps to reproduce: - Use a Luxembourg company - Post a P&L result for the year and do the year-end affectation (Dr 142 / Cr 1412) - Open the Luxembourg balance sheet (full or abbreviated)…
… sheet
Steps to reproduce:
- Use a Luxembourg company
- Post a P&L result for the year and do the year-end affectation (Dr 142 / Cr 1412)
- Open the Luxembourg balance sheet (full or abbreviated)
Issue:
Line "V. Profit or loss brought forward" shows incorrect values.
Cause:
The `accounts` expression for that line used `account_codes` engine with formula `-14`, which only sums accounts by code prefix. Account 1412 ("Results brought forward (assigned)") was typed as `equity`, so its balance was carried forward as an initial balance instead of being captured as retained earnings in the formula.
Solution:
- Set account 1412 to `equity_unaffected`, consistent with account 142.
- Change the `accounts` expression of Line V in both the full and abbreviated balance sheet to use the `domain` engine: `['|', ('account_id.code', '=like', '14%'), ('account_id.account_type', '=', 'equity_unaffected')]` with subformula `-sum`. This correctly captures the balance of all 14x accounts and any `equity_unaffected` accounts, which covers the standard year-end affectation workflow.
opw-5883505
Forward-Port-Of: odoo/enterprise#111328This update resolves a memory issue that was impacting the performance of the payroll dashboard. The team optimized the data processing method, switching from a complex union operation to a simpler list appending approach. This change significantly reduces memory usage and improves dashboard responsiveness.
Original PR description
Instead of using union in _group_records_by_schedule and _group_by_warning_and_date we append in a list and browse to avoid memory errors
This fix resolves an issue where sales emails incorrectly displayed invoice amounts as $0.00. The update ensures that the correct invoice amount is sent to the salesperson by using the display name and tax totals amount, addressing a discrepancy in how the invoice data was being processed in draft state.
Original PR description
Steps to produce: --- - Install `Sales` module. - Create a sale order, set a product, and assign Marc Demo as salesperson in the Other Info tab. - Confirm the sale order and create an invoice. Issue:…
Steps to produce: --- - Install `Sales` module. - Create a sale order, set a product, and assign Marc Demo as salesperson in the Other Info tab. - Confirm the sale order and create an invoice. Issue: --- - In the email notification sent to the salesperson, the record reference displays as False and the amount shows as 0.00. Root cause: --- - Here at [1], the record name is False because the invoice is still in draft state. - In [18], _sync_invoice sets amount_currency = line.balance for new lines, but balance is precomputed as 0 before the INSERT because _compute_balance returns 0 for invoice lines. In [17] it read price_subtotal directly, which is always correct. - In 17.0 the same mail fires at the same moment, but _sync_invoice had already set balance = −295 and amount_currency = −295 from price_subtotal, so the email reads the correct 295.00. Solution: --- - Use record.display_name instead of record.name, as display_name is always present regardless of the record state. - Use the tax totals amount instead of amount_total, which is not yet computed on draft invoices. [1]https://github.com/odoo/odoo/blob/0bcc34ec2f92b9b95cde321423d810002bb317ce/addons/account/models/account_move.py#L6478 [18]https://github.com/odoo/odoo/blob/b0a50104a12b205958316d382b4c7b2176395877/addons/account/models/account_move_line.py#L1566-L1610 [17]https://github.com/odoo/odoo/blob/73c076893de79df5a86aa970fde46a7aacbeaf3d/addons/account/models/account_move_line.py#L1536-L1585 Before: --- <img width="400" height="175" alt="image" src="https://github.com/user-attachments/assets/48c2dc03-765a-49c3-bad3-fd0b14405786" /> After: --- <img width="400" height="175" alt="image" src="https://github.com/user-attachments/assets/53682171-155f-46b3-85dd-0c7c98482067" /> opw-6023827 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#258375 Forward-Port-Of: odoo/odoo#254862
This update fixes an issue where product names on invoices weren't always displayed in the correct language when using child contacts. The change ensures that invoice line labels are translated based on the language of the selected invoice contact, regardless of the parent contact's language. This improves the accuracy and consistency of invoices across different languages.
Original PR description
### Issue before this commit: When creating an invoice using the child contact of a parent contact that has a different language with respect to the father, the label of the invoice line was not…
### Issue before this commit: When creating an invoice using the child contact of a parent contact that has a different language with respect to the father, the label of the invoice line was not always displayed in the child contact language but in the father's contact language. ### Steps to reproduce the issue: 1. Activate at least 2 languages (X and Y) 2. Create a product and set the translation for that product in the activated languages 3. Create a Contact with the language X 4. Create a child contact (invoice adress type) for that contact with language Y 5. Create a new invoice setting the customer as the child contact 6. Add the product you created 7. See the label is displayed in the language of the parent contact ### Cause of the issue: The computation of the invoice line name relied on line.partner_id.lang. However, the partner_id of the move line is automatically set to the commercial partner that can be different (can be the father's contact) to the contact used on the invoice. As a result, the product description was translated using the wrong language. ### Reason to introduce the fix: To ensure that invoice line labels are correctly translated according to the language of the selected invoice contact, the computation now uses the language of move_id.partner_id instead of line.partner_id. This guarantees consistent and expected behavior in multilingual environments, especially when using different contacts under the same commercial partner. opw-5955875 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#258458 Forward-Port-Of: odoo/odoo#254833
This update fixes a bug where payments weren't automatically updating to 'paid' status after bills with early payment discounts were fully reconciled. Now, when a payment is reconciled with a fully paid bill, the payment state will accurately reflect the transaction, improving financial reporting accuracy. This primarily impacts users utilizing early payment discounts.
Original PR description
Currently, payments may remain in the 'in_process' state even when the associated vendor bills are fully paid. This occurs primarily when using early payment discounts (EPD) and journals without…
Currently, payments may remain in the 'in_process' state even when the associated vendor bills are fully paid. This occurs primarily when using early payment discounts (EPD) and journals without outstanding accounts. Steps to reproduce: - Create an early payment term. - Create a Vendor Bill with EPD and post it. - Register a payment for this bill (no outstanding account set on journal => no move created). - Create a bank transaction fully paying the bill. - Reconcile the transaction with the bill. Issue: Access the payment of the bill. The payment state remains 'in_process' instead of 'paid'. Analysis: The issue occurs because the reconciliation process misses the trigger to set the payment state to 'paid'. Specifically: - The payment amount does not match the bill total due to the EPD. - The payment compute method does not monitor 'reconciled_bill_ids', causing it to ignore the status of linked vendor bills. This change adds 'reconciled_bill_ids' to the compute dependencies and ensures that if a payment is reconciled with any moves (invoices or bills), their payment_state is considered to determine the final state of the payment. Test in enterprise: https://github.com/odoo/enterprise/pull/112398 opw-5881976 Forward-Port-Of: odoo/odoo#256486
This update ensures payroll calculations and leave allocations are accurate by restricting work entry types to match the employee's country. A new automated process now adapts existing records to use the correct country-specific work entry types, preventing errors and improving data reliability.
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where KPI cards (Billable Hours, etc.) displayed on the Timesheets dashboard were not updating correctly when filters were applied. The problem stemmed from a hardcoded filter limiting data to a single user. Removing this restriction ensures accurate KPI data reflects all timesheet information based on applied filters.
Original PR description
Steps to reproduce: - 1. Go to the dashboard app > Timesheets. 2. Apply any global filter. Issue: - The main KPI cards (Billable Hours, Non-billable Hours, Billable Rate) do not update correctly when any global filter is applied. Filtering by 'Employee' causes the cards to show zero. Other filters like 'Project' or 'Department' show incomplete and incorrect data, reflecting only the timesheets of a single hardcoded user. Cause: - The pivot tables (`pivot 5` and `pivot 6`) that source the data for the KPI cards contained a hardcoded domain `['user_id', '=', 2]`. This condition changes any selection made in the global filter and shows incorrect data. Fix: - The hardcoded `['user_id', '=', 2]` condition has been removed. task-4782213 Forward-Port-Of: odoo/odoo#258412 Forward-Port-Of: odoo/odoo#224810
This update resolves an issue where scrolling or swiping in the mobile inbox triggered incorrect 'longpress' actions, displaying message actions unexpectedly. The fix prevents event propagation, ensuring the system correctly identifies scrolling versus long presses, improving the user experience.
Original PR description
Before this commit, when in inbox mobile and scrolling & swiping on inbox notifications, the message actions was displayed at the same time. Steps to reproduce: - have Admin with "Handle in Odoo"…
Before this commit, when in inbox mobile and scrolling & swiping on inbox notifications, the message actions was displayed at the same time. Steps to reproduce: - have Admin with "Handle in Odoo" Notification preferences - have some messages in Inbox (e.g. receive @ mentions from chatter) - open Inbox in Discuss app in mobile, and scroll up / swipe horizontally on each message => this opens message actions in bottom sheet This happens because when scrolling up/down or swiping left/right on a message, this is triggering a longpress. The longpress has some dedicated code to detect that there's no scrolling or swipe at the same time, however since 1 the action swiper was changed and made this regression. This happens because 1 introduced some `ev.stopPropagation()` on touch event, which are crucial for the hook useLongPress() to determine whether a scroll or swipe is occuring. Because the events have been stopped, the useLongPress() wrongly assumes the user triggers a long press. One could think we could use capture in useLongPress(), which is generally the way to prevent this issue. However, ActionSwiper is stopping propagation at the capture mode, therefore giving no chance for useLongPress() to detect the touch events. Thankfully the capture event listener target is the `ActionSwiper` itself, so one solution is to register in capture mode in a broader scope like `window`. This commit fixes the issue by registering on `capture` of the touch event on `window` for `useLongPress()`. Task-6008171 Scroll up in inbox, Before / After:   Forward-Port-Of: odoo/odoo#258172
This update resolves an issue where COGS wasn't being calculated correctly for sales with multi-step delivery processes. The fix ensures that COGS is accurately determined, even when the delivery involves multiple stages, leading to correct invoicing. This improves the accuracy of cost tracking for sales orders.
Original PR description
**Problem:** cogs is 0 if the delivery is multi steps with only first picking validated. **Steps to reproduce:** - set the warehouse as 2 steps delivery - create a tracked product avco perpetual -…
**Problem:** cogs is 0 if the delivery is multi steps with only first picking validated. **Steps to reproduce:** - set the warehouse as 2 steps delivery - create a tracked product avco perpetual - set a cost of 10$ and a positive quantity - create and confirm a SO for 1 quantity - validate only the first picking - create and confirm the invoice **Current behavior:** there is no cogs lines in the invoice **Expected behavior:** there should be cogs line for a cost of 10$ **Cause of the issue:** to compute the unit price of the cogs we use _get_cogs_value() https://github.com/odoo/odoo/blob/5fd80a1fb8ef33cfa9261967cf14f6f0c421d45a/addons/stock_account/models/account_move.py#L122 Inside _get_cogs_value(), because there is done moves, we use _get_cogs_price_unit() https://github.com/odoo/odoo/blob/5fd80a1fb8ef33cfa9261967cf14f6f0c421d45a/addons/stock_account/models/account_move_line.py#L67-L68 But because there is no valued quantity (because the done moves are internal), the return value will be 0. https://github.com/odoo/odoo/blob/5fd80a1fb8ef33cfa9261967cf14f6f0c421d45a/addons/stock_account/models/stock_move.py#L251-L253 So the cogs will have an amount of 0 and no line will be created https://github.com/odoo/odoo/blob/5fd80a1fb8ef33cfa9261967cf14f6f0c421d45a/addons/stock_account/models/account_move.py#L125-L126 **fix** The fix for consigned products introduced by this PR https://github.com/odoo/odoo/pull/255043 was working for the wrong reasons. _get_valued_consigned_qty() only works if the moves are partially consigned. If the move is fully consigned, _is_consigned_value_line() will return False for every move line. https://github.com/odoo/odoo/blob/5fd80a1fb8ef33cfa9261967cf14f6f0c421d45a/addons/stock_account/models/stock_move.py#L650-L651 That's because if the move is fully consigned, _is_in() and _is_out() will return False. https://github.com/odoo/odoo/blob/5fd80a1fb8ef33cfa9261967cf14f6f0c421d45a/addons/stock_account/models/stock_move_line.py#L72-L74 So it only works if the move is not fully consigned because _is_in() or _is_out() will be True thanks to the non consigned line. https://github.com/odoo/odoo/blob/5fd80a1fb8ef33cfa9261967cf14f6f0c421d45a/addons/stock_account/models/stock_move.py#L511-L519 However, _get_cogs_price_unit() still worked fine for fully consigned moves because if the move is fully consigned, total_qty will be 0 and the return value will be 0 https://github.com/odoo/odoo/blob/5fd80a1fb8ef33cfa9261967cf14f6f0c421d45a/addons/stock_account/models/stock_move.py#L251-L253 But this was hacky and prevented us to address the issue of this PR. The logic should be: If there is no quantity to value (consigned + not consigned) we fallback on the standard price (just as if there is no move). This solves the issue of this PR because no moves were valued moves in our use case. If there is a quantity to value (and we're in a case where we want the average move value), we use the average move value (which will be 0 if all the moves are consigned) opw-6001694 Forward-Port-Of: odoo/odoo#256383
This update resolves an issue where Google Ads cookies were not being blocked correctly within Odoo's website configuration. The fix involves a revised approach to patching script tags, ensuring that Google Ads tracking scripts are effectively prevented from loading. This improves user privacy and aligns with data protection regulations.
Original PR description
# How to reproduce - Go to Website app > Configuration > Websites > Select your website > Custom Code - In the "Custom <head> code" section add the script given at the last section of this PR (with a…
# How to reproduce
- Go to Website app > Configuration > Websites > Select your website > Custom Code
- In the "Custom <head> code" section add the script given at the last section of this PR (with a proper TAG_ID)
- Go to a new Incognito Tab and go to the Website front page
- Refuse the optionnal cookies
- Open the browser's console and go to Application > Storage > Cookies
# The problem
The Google Ads cookies are present (prefixed by _ga)
# Why
This commit introduced the blocking of 3rd party cookies :
https://github.com/odoo/odoo/commit/958b41c4acec7e1700ca4d6e0b25ee0ad2aac9f1
It works by doing 2 things, but none of them works in our case :
First, it edits the view rendering to replace the `src` value with "about:blank" for watched
tags, but this does not work for `website.custom_code_head` (our case) and `website.custom_code_footer` because it is t-out'ed which bypasses this code :
https://github.com/odoo/odoo/commit/958b41c4acec7e1700ca4d6e0b25ee0ad2aac9f1#diff-a27798e1ecfe96676dd48766e0aa9d12fbc0784e328ac1a3ec82b1ce199fc58bR121-R166
Second, it adds a script in the head of the page that patches the setter for the `src`
property of the script tags. If the value that we try to set is a URL to a site that we
block and the cookies are not yet accepted, we replace the `src` value with "about:blank".
https://github.com/odoo/odoo/blob/e906eb23d698061f146ba67aae420eb7bb5e8a68/addons/website/static/src/js/content/cookie_watcher.js#L8
This sadly does not work for parser-inserted scripts that are directly parsed from the HTML.
Indeed, they do not use the setter of `HTMLScriptElement.prototype`.
It is possible to verify this by adding a `MutationObserver` that checks for new script
insertions and adding breakpoints in this observer and in the patched setter. For the
first scripts of the page, the breakpoint in `MutationObserver`is triggerred while the
one in the setter is not.
# Proposed solution
We move this code into new helper functions :
https://github.com/odoo/odoo/blob/95dc247ecd773044ef9c9f1512c7d86d73df836c/addons/website/models/ir_qweb.py#L130-L135
And use these helper functions to create another helper function that allows us to check
an html field for trackers that would need to be removed
We then use this helper function on `website.custom_code_head` and `website.custom_code_footer`
# The script
```html
<!-- Google tag (gtag.js) -->
<script async src="[https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script](https://www.googletagmanager.com/gtag/js?id=TAG_ID%22%3E%3C/script)>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'TAG_ID');
</script>
```
Source : https://developers.google.com/tag-platform/gtagjs
opw-6007810
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#258469
Forward-Port-Of: odoo/odoo#256808This update corrects a bug where the system incorrectly calculated prices for downpayment lines on purchase orders. The change ensures that downpayment lines are treated like section and note lines, preventing unintended price recalculations and ensuring accurate order pricing.
Original PR description
## Issue: When viewing purchase order lines, the system attempts to compute the unit price for downpayment lines. This results in unintended behavior. ## Cause: PR…
## Issue: When viewing purchase order lines, the system attempts to compute the unit price for downpayment lines. This results in unintended behavior. ## Cause: PR https://github.com/odoo/odoo/pull/236669 introduced the `price_unit_product_uom` field along with its compute method `_compute_price_unit_product_uom` to manage PO comparison. Although the compute method correctly skips section and note lines, it does not exclude downpayment lines. Downpayment lines are identified by the `is_downpayment` field, which was introduced earlier in PR https://github.com/odoo/odoo/pull/176137. As a result, the computation is incorrectly applied to downpayment lines. ## With this commit: The UoM price computation is prevented for purchase order lines where is_downpayment is set to True. Downpayment lines are now treated similarly to section and note lines to prevent unintended price recalculations. Steps to reproduce : [Video](https://drive.google.com/file/d/1JrMN8x-i86QjRfMnaeYu-Jac03iFoJs3/view?usp=drive_link) OPW - 5930652 Forward-Port-Of: odoo/odoo#251259 Forward-Port-Of: odoo/odoo#249989
This update resolves an issue where email notifications weren't being sent when users with special characters (&, <, >) in their names were mentioned. The fix translates HTML entities back to their original form, ensuring mentions are correctly identified and emails are sent as expected. This improves notification delivery for all users.
Original PR description
**Description of the issue/feature this PR addresses:** The `Store.getMentionsFromText` method fails to identify mentions for users with special characters (&, <, >) in their names. Because the…
**Description of the issue/feature this PR addresses:** The `Store.getMentionsFromText` method fails to identify mentions for users with special characters (&, <, >) in their names. Because the function processes raw HTML, these characters are encoded as entities, causing them to be [filtered out](https://github.com/odoo/odoo/blob/a2b3a10255dba290ea462b9193ae11c54d8dd5e0/addons/mail/static/src/core/common/store_service.js#L599-L601) In order to resolve this, I translate the entities back into their normal representation, allowing our includes to find them. **Steps to reproduce bug:** 1) Create a user with a name containing &, <, > 2) Set it so they receive emails for notifications 3) Mention them in a long note 4) Observe that no email is sent **Current behavior before PR:** https://drive.google.com/file/d/1itBlz6havFmFi2G3mbOm3qh2_WH6uM76/view?usp=drive_link **Desired behavior after PR is merged:** https://drive.google.com/file/d/1PC2_hjBAhhC6ZSOEzs9SPYjSHrZbaplp/view?usp=drive_link opw-5895188 Forward-Port-Of: odoo/odoo#258499 Forward-Port-Of: odoo/odoo#249350
This update resolves an issue where portal users were encountering access errors when viewing their invoices. The fix utilizes 'sudo' to grant necessary permissions when retrieving reconciled payment information, ensuring portal users can correctly access and display their invoice details. This improves the user experience and prevents disruptions to invoice processing.
Original PR description
Steps to reproduce 1. Create a portal user linked to a partner. 2. Create a customer invoice for that partner and confirm it. 3. Log in as the portal user and visit /my/invoices. 4. The page returns a 403 / raises an access error. Issue When rendering the portal invoice list, the code iterates over `self.reconciled_payment_ids`, which internally reads records on `account.payment`. Portal users have no read access on `account.payment`, so the ORM raises an access error as soon as the field is accessed on any visible invoice, even when no payment is linked. opw-6104847