Tuesday, August 25, 2026
25 changes · saas-19.2
Enhancements to existing features
Product pages will now include the product's internal reference as the SKU in structured data when one is available. This helps search engines and other services better identify products, which can improve product listing quality and consistency.
Original PR description
Include default_code as the Schema.org sku property in the product structured data when it is set. @Tecnativa TT64220 **Description of the issue/feature this PR addresses:** Product structured data does not expose the product internal reference as a SKU. **Current behavior before PR:** The sku property is absent even when default_code is set. **Desired behavior after PR is merged:** The product structured data includes default_code as the Schema.org sku property when available. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282911
Resolved issues and error corrections
This fixes an HR search issue that could return incorrect results when users without access to private employee data searched certain employee-related fields. It helps keep employee searches reliable while preserving restricted access to sensitive HR information.
Original PR description
The hack to search fields as a user that has no access to private employee data and searching on the `current_version_id` instead of the provided field since we force to wrap searchable fields domains in a Query in odoo/odoo#280373. The hack did not support usage of the 'any!' operator on `current_version_id` leading to a query like: "hr_employee.id in (select id from hr_version ...)". task-6468820 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284271 Forward-Port-Of: odoo/odoo#283811
This fix prevents an error that could occur when sales and marketing tracking records reference models that are not currently available. It improves reliability by safely skipping unavailable references instead of crashing.
Original PR description
Following 6dedae804748, in case `ir.model` models are out-of-sync with the available models in the registry, trying to compute the target selection model will result in a crash (`KeyError`). This commit ensure the target model is available in the registry to avoid that crash. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Product videos in the website shop carousel now load only when their slide is shown, so video previews initialize at the correct size. This prevents blurry video cover images and improves the product page experience for shoppers.
Original PR description
Steps to reproduce: =================== 1. Add a video (e.g. a YouTube URL) to a product from the Sales app. 2. Open the product page on the website. 3. Slide the carousel to the video. => The video…
Steps to reproduce: =================== 1. Add a video (e.g. a YouTube URL) to a product from the Sales app. 2. Open the product page on the website. 3. Slide the carousel to the video. => The video preview cover is blurry. Root cause: =========== The product images are rendered in a carousel (the shop_product_carousel template in ) where only the first slide gets the "active" class; https://github.com/odoo/odoo/blob/af1b3ee2e7ac56a35bff5e030c3a831c27dbcf24/addons/website_sale/views/templates.xml#L3224-L3226 every other slide is "display: none". A product video is rendered as a live <iframe> inside its slide, so when the video is not the first media its iframe loads while its container has no dimensions (0x0). The embedded player then initializes as a small mobile player and loads a low resolution cover thumbnail (120x90), which looks blurry once the slide is shown at full size. Reloading only the iframe while the slide is visible fixes it, a full page reload does not. Fix: ==== Defer loading the video iframes located on hidden slides their src is moved to a data-src attribute on start and restored once the slide becomes visible. The player then initializes at full size and loads a high resolution cover. opw-6349394 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282508 Forward-Port-Of: odoo/odoo#274002
This fix ensures invitation and signup links are created with the required signup purpose, preventing token generation failures. It helps users access shared projects and portal invitations more reliably.
Original PR description
A `signup_type` is required to generate a token. Task-6452339 Forward-Port-Of: odoo/odoo#280891
The stock test now searches for the exact product name instead of a partial word. This prevents the test from accidentally selecting a different product and helps keep stock workflows reliably validated.
Original PR description
When searching for the product created in the test we were only searching for "Serial" but another product with this word in the internal reference was showing up alone. To fix this we now look for the exact product name to avoid finding another product. runbot-242820
Sales documents for Norwegian customers can now be printed even when no VAT number is entered. This prevents an error that blocked quotation printing and improves reliability for users working with Norwegian customer records.
Original PR description
**Steps to reproduce:** - Install the `sale_management` module. - Create a new customer and set the country to `Norway`. - Go to Sales and create a new quotation for the newly created customer. - Click the `Print` button. **Error:** `AttributeError: 'bool' object has no attribute 'startswith'` **Root Cause:** At [1], `startswith()` is called on VAT even when the customer's TIN (VAT) is not set, causing an `error`. Fix: This commit prevents the error and allows users to print the report successfully. [1]: https://github.com/odoo/odoo/blob/5c2d5daa13cf582c40bdb44e245e1359d7c410f0/addons/account_edi_ubl_cii/models/account_edi_ubl.py#L924-L928 opw-6469642
The accounting dashboard now shows the full invoice or bill amount for documents marked “To Check,” rather than only the unpaid balance. This avoids understating the value of documents that still need review after partial payments.
Original PR description
Currently, the "To Check" links on the dashboard display the residual amount of invoices and bills. Since the entire document needs to be checked regardless of partial payments, showing the remaining balance is misleading. This commit updates the `selects` list in `_get_to_check_payment_query` to use `amount_total` instead of `amount_residual`, ensuring the dashboard reflects the full value of the documents. Task-6478415 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284171
This update prevents website editors from using SEO optimization and page settings on link tracking pages, where those tools are not useful for visitors. It reduces confusion by removing irrelevant menu options from that specific page type.
Original PR description
Since [this commit][1] you're able to optimize the link tracker page using "optimize seo." This makes no sense as it contains no useful content for visitors to the website. Access to the action is now disabled when the current page is the link tracking page. The page properties and link tracker menu items have also been removed for similar reasons. [1]: https://github.com/odoo/odoo/commit/ac55f2bb113ecf7c774fe6e96d28e716184a97d1 Task-6288891 Forward-Port-Of: odoo/odoo#283954 Forward-Port-Of: odoo/odoo#278132
This fixes an issue where choosing a Gboard word suggestion on mobile could place the suggested word incorrectly and leave part of the original word behind. The editor now better distinguishes Gboard behavior from a previous SwiftKey workaround, making mobile text entry more reliable.
Original PR description
Before this commit: on mobile, when typing using Gboard and select a word suggestion will only delete the last character and put the new word at the beginning of the word to be replaced. This is because Gboard extends the selection to the text to be corrected, then deletes it, and inserts the corrected text. This flow falls in our previous fix for MS Swiftkey's delete backward, and wrongly uses cached old selection instead of using extended new selection from Gboard. After this commit: We strict the Swiftkey fix further, and only execute it when the cursor is at the beginning of the p element. Related commit: https://github.com/odoo/odoo/commit/822fd4e8fec7e114e6748dd8c9b4969f423fb290 task-6233756 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278266
The overtime rules screen now only shows the related versions button to HR managers, matching the permissions needed to load its data. This prevents HR officers from seeing an access error when opening overtime rules and helps upgrades complete without this permission mismatch.
Original PR description
The button requires the group `hr.group_hr_user`, but the button uses `versions_count`, that in its computation uses fields like `contract_date_start` that require the group `hr.group_hr_manager`. To avoid the mismatch, the button is restricted to only managers. This error was found in upgrades failing. To reproduce: - Install `hr_attendance`. - Assign any employee the Default Ruleset to make the button not invisible. - Change the HR security of your user to Officer. - Go to Attendance->Configuration->Overtime Rulesets and try to see the record. - A message will display the following error: ``` You do not have enough rights to access the field "contract_date_start" on Employee Record (hr.version). Please contact your system administrator. Operation: read User: 2 Groups: allowed for groups 'Employees / Administrator' ```
This fix adjusts how Odoo prepares mail thread data so it only requests information that is relevant for the current user and thread. This helps avoid unnecessary data handling and supports more accurate mail behavior across access and company contexts.
Original PR description
This change cleans up the requested data from `/mail/thread/data` route, ensuring it aligns with what is actually needed depending on the user and thread. part of task-6452761 Forward-Port-Of: odoo/odoo#283622 Forward-Port-Of: odoo/odoo#280713
This update ensures employees assigned as attendance officers also receive the standard internal user access expected for that role. It keeps attendance permissions consistent across supported versions and helps avoid access issues when managing attendance records.
Original PR description
In [this forward port in 19.4](https://github.com/odoo/odoo/pull/281713/changes#diff-4b6f4473332f5e30b7d83acb51946ffa4731af0093c75954f619906010c3f8a8R28), I have changed the `implied_ids` of `group_hr_attendance_officer` as well. This PR reflects the change on other stable versions. The change should not break permissions, as an attendance officer should be a user, and `base.group_user` implies the group `hr_attendance.group_hr_attendance_own_reader` task-6499161
This fixes a filtering issue in Mass Mailing that allowed temporary wizard records to appear as mailing-enabled options. Business users get cleaner, more appropriate mailing model choices and avoid selecting records that are not meant for mail campaigns.
Original PR description
The search function ` _search_is_mailing_enabled` mistakenly used `model.is_transient()` (where the model is the `ir.model` record itself) to filter the transient models, which always returns `False` since `ir.model` is a regular persistent model. As a result, transient models (wizards) were never filtered out. This commit fixes it by using`self.env[model.model].is_transient()` to call `is_transient` on the actual model. Task-6458883 Forward-Port-Of: odoo/odoo#283781 Forward-Port-Of: odoo/odoo#282783
Duplicating multiple projects at once now keeps each copied project’s milestones separate. This prevents copied projects from receiving milestones that belonged to other selected projects, reducing cleanup work and confusion for project teams.
Original PR description
Before this commit, duplicating several projects at once from the list view gave every copy the milestones of all the duplicated projects, because the copy loop assigned the milestones of the whole recordset instead of the ones of the project being copied. Duplicating a single project behaves correctly, which hid the issue. Steps to reproduce: - create two projects with milestones enabled, add a milestone to the first one and two others to the second one - select both projects in the list view and duplicate them Each copy contains the three milestones instead of only the milestones of its original project. Solution: Copy the milestones of the project being duplicated. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278520
The Accounting app now handles payment term lines with non-positive day values without crashing during due-date calculation. Users will see the intended validation error when saving instead of an unexpected system traceback.
Original PR description
Steps to reproduce: - Install `Accounting` module - Payment Terms > Create NEW - Add a new Due Term line with "Days end of month on the" and a negative amount of days(eg: -1) Traceback: `ValueError: day is out of range for month` When `days_next_month` is set to a negative value, it is passed directly to `relativedelta` as the 'day' value. Since a negative value is not a valid day of the month, the due-date computation raises a `ValueError`. Use the end of the month for the calculation when `days_next_month` is non-positive. This prevents the traceback while computing the payment term and allows the proper validation error to be raised when the record is saved. opw-6453640 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283865 Forward-Port-Of: odoo/odoo#281904
Sale order PDF reports now keep section and combo rows aligned when columns such as Taxes or Discount are removed using Studio. This prevents confusing blank spaces in customer-facing documents and preserves a cleaner report layout.
Original PR description
**Steps to reproduce:** 1. Open a Sale Order report in Studio 2. Delete the Taxes column 3. Save 4. Create a sale order with at least one section line and products that have taxes 5. Print the sale…
**Steps to reproduce:** 1. Open a Sale Order report in Studio 2. Delete the Taxes column 3. Save 4. Create a sale order with at least one section line and products that have taxes 5. Print the sale order PDF **Issue:** - A blank column is rendered in the PDF report on section (and combo) rows whenever a column such as Taxes or Discount is removed via Studio. **Why this happens:** - The section row's `colspan` and the combo row's `colspan` were computed using `3 + (1 if display_discount else 0) + (1 if display_taxes else 0)`. - `display_taxes` and `display_discount` are derived from order data (i.e. whether any line has taxes/discounts), not from which columns are actually rendered in the table. - When Studio removes a column it deletes the `<th>` and matching `<td>` elements via XPath, but these Python variables remain `True`. As a result, section/combo rows still accounted for the removed column in their `colspan`, producing one extra cell and a visible blank column. **Fix:** - Introduce a `colspan_count` variable which is incremented inside each `<th>` body - Use that counter for `td_section_name` and `td_combo_name` instead of the previous formula. - Because the increment occurs inside the `<th>` element, it is skipped whenever the element is not rendered, whether because `display_taxes`/`display_discount` is `False` or because Studio's XPath removed the element entirely. opw-6433679 Forward-Port-Of: odoo/odoo#283398 Forward-Port-Of: odoo/odoo#280719
A warning related to lower TCS tax in the Indian localization now correctly shows the link to view the related journal items. This helps users quickly access the records needed to review or resolve the warning.
Original PR description
The `lower_tcs_tax` warning was using the "actions" key instead of "action". As a result, the warning message was displayed correctly, but the "View Journal Item(s)" action link was not shown. Forward-Port-Of: odoo/odoo#284095
A niche issue was fixed where quotation templates containing section or note lines could cause problems when linked to an active planning session. The system now ignores those non-product lines so only valid quotation lines are considered, reducing errors in field service sales workflows.
Original PR description
This commit patches a niche bug involving creating a quotation via a quotation template containing a line section, then connecting it to an active planning session. The current architecture did not filter out `line_section` or `line_note` typed lines. This updated search domain resolves this issue. opw-6351484
Archived projects no longer appear as selectable options in the timesheet systray timer. This prevents users from accidentally logging time against projects that are no longer active, while preserving access to historical timesheet data.
Original PR description
Steps to reproduce: ---------------------------------- 1. Install the `timesheet_grid` module. 2. Create a project and add any timesheet to it. 3. Archive the project. 5. From the systray timer,…
Steps to reproduce:
----------------------------------
1. Install the `timesheet_grid` module.
2. Create a project and add any timesheet to it.
3. Archive the project.
5. From the systray timer, click on the Project field.
Observation:
----------------------------------
The archived project is visible in the dropdown.
Issue:
----------------------------------
In Odoo, standard search views and `name_search` calls on `project.project` automatically respect `active_test=True`. When you open the timer, the frontend passes `{'timesheet_timer_search': True}` in the context to `name_search` with an empty query string. `name_search` overrides standard searching to retrieve recently used projects first by querying `account.analytic.line` via `_get_recently_used_records ('project_id', ...)`. `account.analytic.line` stores past timesheet logs. Even after a project is archived, historical timesheet records for that project still exist in `account.analytic.line`. Because `_get_recently_used_records` runs a `_read_group` query on `account.analytic.line` (which has no active field of its own), it fetched the `project_id` from historical timesheet entries without checking if the referenced project was active.
Solution:
----------------------------------
In `name_search`, explicitly append `[('active', '=', True)]` to the `project_domain` used when querying `_get_recently_used_records`. Standard form/list views using `_domain_project_id` already benefit from Odoo's default ORM `active_test=True` mechanism during standard `project.project` searches.
Note:
----------------------------------
Another solution was to add `active = true` in `getTimesheetTimerFieldInfo` https://github.com/odoo/enterprise/blob/22eb84cdc94ba334d42bad32fb491d35c8147c94/timesheet_grid/static/src/services/static_timesheet_timer_service.js#L322-L328
Fixing it in Python ensures that any call passing `timesheet_timer_search` in context (e.g. mobile widgets, custom RPCs, or python wizards) will benefit from the fix, rather than only patching a single OWL JS service.
opw-6445528Users can now open links shared in spreadsheet cell comments with a regular click, instead of needing Ctrl+click or Cmd+click. This removes a frustrating interaction issue and makes collaboration through spreadsheet comments smoother.
Original PR description
Current behavior before PR: - Clicking a link in a cell comment did not work. A left click was blocked, while Ctrl+click (or Cmd+click) opened the link in a new tab. - This was caused by `t-on-click.prevent` on the comment thread and popover. It was originally added because the scroller service used the URL hash to scroll to anchors, which was removed in https://github.com/odoo/odoo/commit/711e9c9f24818714129f55283e2df64503d93605 Desired behavior after PR is merged: - `t-on-click.prevent` is removed and links in cell comments can be opened normally with both left click and Ctrl+click (Cmd+click on macOS). Task: [6448651](https://www.odoo.com/odoo/project/2328/tasks/6448651) Forward-Port-Of: odoo/enterprise#128746 Forward-Port-Of: odoo/enterprise#127473
This fix prevents a rare crash in Belgian Intrastat reporting when company data is accessed in unusual permission scenarios. It mainly protects future customizations or edge cases, as the issue is not reachable through the standard user interface.
Original PR description
Due to some trouble with tests, we found that in some cases, this function is called on the root company, and if the user does not have the access rights to read data from the company (users with system rights have them by default), it will cause a crash. This situation is not possible with the standard UI, but we fix it in case it becomes possible in a future version or customization. Forward-Port-Of: odoo/enterprise#128212
Tax returns can now be submitted without being blocked by incomplete setup on tax groups that have no activity. This prevents unnecessary interruptions when closing taxes and keeps validation focused on groups that actually affect the return.
Original PR description
…ax closing Steps to reproduce: - Remove the tax payable and receivable accounts of a tax group for which no move exists. - Open the tax returns view, set the opening date and submit the tax return -> Odoo prevents going further because the tax group configuration isn't fully done, but it's useless to ensure that for tax groups that aren't used. Forward-Port-Of: odoo/enterprise#128197
The website builder now shows the correct preview image for the AI live chat snippet when it is not yet installed. This fixes a missing visual preview, making it easier for users to recognize and add the live chat feature while building a website.
Original PR description
Problem: 1) The preview image of the livechat snippet was removed in this [commit][1] and wasn't replaced with another image. As a result, the uninstalled livechat snippet doesn't display properly in the website builder. Solutions: 1) An image has been added `ai_livechat.png` which is shown on preview Note: This fix will change in master to be up to date with current website snippet previews. The location will be moved to `snippet_previews` and the file type will be changed to `.webp` [1]: https://github.com/odoo/enterprise/commit/df05441e469157890253b5550b5f8735723b28fb Task-5248712 Forward-Port-Of: odoo/enterprise#126361
A permissions issue in Documents has been fixed so users assigned as editor members can update shared folder access as intended. This prevents authorized editors from being incorrectly blocked when changing internal user access settings.
Original PR description
1. Create a non-company root folder 2. Edit rights as follows: * add Marc Demo as editor member * access for internal users and link to None 3. As Marc Demo, try updating Internal users access to "editor" ⮕ You can't. Task-6410610 Forward-Port-Of: odoo/enterprise#125191