Friday, August 28, 2026
30 changes · saas-19.4
Enhancements to existing features
The chat bubble styling logic was moved to a more flexible place in the mail module. This makes it easier and safer for future customizations to adjust chat appearance without changing core templates.
Original PR description
Move the ChatHub bubbles attribute class computation from the template to a JavaScript getter. This allows other modules to extend or override the class list without replacing the template attribute, making customizations safer and easier. task-6412411
Deleting accounting accounts is made more efficient by adding database indexes used during dependency checks. This reduces delays when cleaning up or reorganizing accounts, especially in larger databases with many payments or analytic entries.
Original PR description
Without these indexes, the foreign key check when deleting an account can take a long time. Forward-Port-Of: odoo/odoo#284780
Mail test checks now retry more regularly instead of waiting up to 10 seconds for certain updates to be detected. This reduces wasted time in the automated test suite while keeping the same overall timeout and does not change customer-facing behavior.
Original PR description
Before this commit, a contains that does not match right away runs again only when its MutationObserver fires, and once more at the 10 seconds timeout. The problem is that the observer reports neither a text node updated in place nor an input value or checked property, so a check waiting for one of those sleeps 10 seconds and then passes: "Delete starred message decrements starred counter once" spends 10.2s of the 183s @mail suite waiting for a counter to go from "Starred3" to "Starred2". This commit turns that single timeout into a 500ms tick up to the same deadline, so that such a check costs 500ms. The tick uses the unmocked timer to stay out of the timer graph a test drives with runAllTimers, and only 32 of the suite's 4239 contains calls stay pending long enough to tick once. Forward-Port-Of: odoo/odoo#285129 Forward-Port-Of: odoo/odoo#284944
This change improves performance when deleting accounts used with German reporting. It adds supporting database indexes so background validation can complete faster, reducing delays for users managing account records.
Original PR description
Without these indexes, the foreign key check when deleting an account can take a long time. Forward-Port-Of: odoo/enterprise#129403
Resolved issues and error corrections
This fixes an error that prevented users from printing sales timesheet reports when using German. The report now identifies the Description column in a language-independent way, so translated labels no longer break printing.
Original PR description
Currently a traceback is occurring when the user tries to print a sale timesheet report in the German language. **<h3>To reproduce the issue:</h3>** 1) Install the `sale_timesheet` module. 2) Create…
Currently a traceback is occurring when the user tries to print a sale timesheet report in the German language. **<h3>To reproduce the issue:</h3>** 1) Install the `sale_timesheet` module. 2) Create a `service` product configured to create a `project and task` on the order. 3) Create a confirmed SO with that product 4) Add a timesheet line to the SO from the `Recorded` stat button 5) Switch to the German language 6) Print `Timesheet(Zeiterfassung)` report 7) A traceback occurs **<h3>Error:</h3>** ``` ValueError: Element „<xpath expr="//th/span[text()='Description']">“ kann nicht in der übergeordneten Ansicht lokalisiert werden ``` **<h3>Cause:</h3>** The xpath relies on the plain text `Description` to identify the `<th>` element. https://github.com/odoo/odoo/blob/5f63fb1af418cc75ff2e382b0455002e7a798071/addons/sale_timesheet/report/report_timesheet_templates.xml#L3-L4 The xpath cannot find the Description header when the language is changed because the text is translated in the base template. As a result, the xpath fails due to the missing target. **<h3>Fix:</h3>** Use a language-independent `name` attribute as the `xpath` anchor. So the `Description` column can be reliably matched regardless of the active language. **<h3> Note:</h3>** This fix requires both modules update, which is generally risky in stable branches. However, this template was recently introduced in [saas-19.4](https://github.com/odoo/odoo/pull/191969/changes#diff-9f4f0d28ffb3aa9fcc4a5f1037bdf532e1e71c4e9703e13b6856ddfd79e15e69R4). So there should be no existing customers using it yet, except saas customers coming from a new database. Therefore, applying this fix in 19.4 is less risky. opw- 6475623
This update fixes an internal mail test that could fail unpredictably when checking mention suggestions. It makes the test focus only on the relevant suggestion list, improving confidence in automated checks without changing user-facing behavior.
Original PR description
Before this commit, the test "select @ mention from the suggestion list being filtered" could fail on runbot, on the check that follows the first "@": Failed to find 2 of ".o-mail-Composer-suggestion" (Timeout of 10 seconds). Found 0 instead. This happens because the test holds a render open on ImStatus, a component the member list renders as well as the composer. The composer tells the server that the user is typing, the bus sends the status back, and the member list re-renders its ImStatus with another class. The hold catches that render, the one that also brings the suggestions on screen. This commit gives the children of NavigableList an inNavigableList environment flag, and holds the render only on an ImStatus that has it. https://runbot.odoo.com/odoo/error/946282 Forward-Port-Of: odoo/odoo#285093 Forward-Port-Of: odoo/odoo#284484
Fixes a display issue in the website appointment editor where a selection button could appear squeezed and a loading indicator could remain visible. This makes appointment page editing clearer and more consistent for website administrators.
Original PR description
Introduced in [1], and in a series of related changes, the time selection page has been reworked to be managed more from the JS, using the Interaction benefits. The entity selection is now a custom dropdown, handled in the JS. When editing the page with the website editor, the button is squashed, because no content is rendered inside. This is not the case for other ones as either a select element, either have a t-out dynamic content that will still instanciate some content at loading. Therefore, instead of meddling with a complex JS, add some simple styling to make sure the element has a consistent height. Also, hide the loader when editing the page in a similar way. [1] odoo/enterprise@a5712d284a87af7530f186ecad765d2cfaf1f9d2 Task-6482389
The Real Margin report now keeps the expected list views when users drill down from the pivot table. This prevents users from being sent to the timesheet list by mistake and makes margin details easier to review from projects.
Original PR description
**Steps to reproduce:** 1. Open a project. 2. Click on the Real Margin stat button or top menu action. 3. The pivot view opens by default. 4. Click on a cell in the pivot view to drill down into the list view. **Issue:** The system opens the timesheet list view instead of the standard analytic entries list view. **Cause:** Overwriting action['views'] erased the default list view, causing to fall back to the timesheet view during drill-down. **Fix:** Used a list comprehension to inject the custom pivot view while preserving the original view types. Added all view options to the Real Margin top bar. task-6192267 Forward-Port-Of: odoo/odoo#270494
The project profitability grid view has been corrected so the real margin information in the top bar displays as intended. This helps users review project financial performance more clearly and consistently.
Original PR description
- update the grid view in project real margin top bar task-6192267 Forward-Port-Of: odoo/enterprise#122586
French VAT report submissions now automatically split account holder names that exceed the official XML-EDI length limit. This helps prevent rejected electronic VAT filings when company or account holder names are longer than allowed.
Original PR description
The XSD for XML-EDI does not allow strings longer than 35 for TitulaireDesignation This commit splits the holder name in 2 parts when it is more than 35 characters task-6476440 Forward-Port-Of: odoo/enterprise#129411 Forward-Port-Of: odoo/enterprise#128239
The project form settings layout has been corrected so related section headers line up consistently. Setting descriptions now use the available horizontal space better, making the page easier to scan and reducing unnecessary line wrapping.
Original PR description
In the project form settings: - The sections that sit on the same horizontal level should have their header aligned. - Settings description should use all the horizontal space available before wrapping to the next line Task-6360046
Self-order preparation receipts now include the customer name when it was provided with the order. This helps restaurant staff identify orders more easily and reduces confusion during preparation and handoff.
Original PR description
The customer name is written in `floating_order_name` which is never passed to the preparation receipt in self order. This commit fixes it. Forward-Port-Of: odoo/odoo#284454
Payment XML files for SEPA and ISO 20022 now use uppercase encoding names to satisfy stricter bank validation checks. This reduces the risk of warnings or rejected payment files from providers such as SIX in Switzerland.
Original PR description
The W3C recommendations for XML state that the encoding defined for an XML document should not be case-sensitive. However, some banking providers (SIX for Switzerland) are stricter and may throw warnings or errors if upper-case is not used. https://www.w3.org/TR/2008/REC-xml-20081126/#NT-EncodingDecl opw-4948708 Forward-Port-Of: odoo/enterprise#128517 Forward-Port-Of: odoo/enterprise#125807
This update prevents an internal social CRM test from failing because of duplicate demo customer names. It uses a unique test customer name so results no longer depend on which demo data or modules are installed first.
Original PR description
The social CRM conversion test creates a partner named "John Doe" and expects the post-to-lead wizard to automatically match it. This relies on "John Doe" being unique in the database. Since `pos_restaurant.customer_1` is also named "John Doe", the wizard's `name_search()` can return multiple partners depending on the modules already installed when the test is run. In that case, the wizard correctly considers the match ambiguous and leaves `partner_id` empty, causing the test to fail. This commit uses a test-specific author name instead, ensuring that the test actually provides the single matching partner described by its docstring and does not depend on unrelated demo data or module installation order. [error-243065](https://runbot.odoo.com/odoo/error/243065) Forward-Port-Of: odoo/enterprise#128119
The inventory report now prints location grouping rows with the correct number of columns. This prevents missing gridlines and broken borders in the PDF, making printed inventory counts easier to read and use.
Original PR description
When new columns were added to the stock inventory report, the location grouping row was not updated. This results in mismatched column counts, causing missing gridlines and broken borders in the PDF output Fixed by ensuring the location row's column count matches the header <img width="603" height="200" alt="image" src="https://github.com/user-attachments/assets/86872bee-f315-4bdd-b3f2-a525e3bb5fe0" /> ### Steps to reproduce: - Ensure warehouses are activated in the settings - Go to Barcode -> Count Inventory - Add a Product - Select the gear Icon then "Print Inventory" - You will notice that the location row has missing gridlines opw-6307728 Forward-Port-Of: odoo/odoo#275918
Fixes an issue in the website editor where changing a custom button's text color could remove its gradient background. This helps users keep their intended button styling while making design changes, reducing rework and visual inconsistencies on website pages.
Original PR description
Steps to Reproduce : 1. Go to Website → Edit Mode 2. Add a snippet with button 3. Click on button and change its type to : " Custom" 4. Apply the gradient type color in fill color option 5. Apply any…
Steps to Reproduce : 1. Go to Website → Edit Mode 2. Add a snippet with button 3. Click on button and change its type to : " Custom" 4. Apply the gradient type color in fill color option 5. Apply any color in text color option 6. You will notice that the gradient type color in fill color option is removed. Problem: Since [this commit][1] new button style options have been added to the sidebar. If one changes the style of a button to custom, changes the background to gradient, and tries to change the text color, the background gradient is removed. Cause: Whenever a gradient is added either to text or as a background, it is applied as a background image. In the case of a text gradient, an additional class, `text-gradient`, is applied for correct styling. Once a change to either color or background/fill is applied that is not a gradient color change, the background image of the element would be reset to nothing. This is the result of [this line][2] from a [previous commit][3]. In the case of a button, this meant changing the font color would reset the background. That is not the desired outcome. The flaw was only discovered once new options were added to change non-text/font elements' backgrounds to gradient. Solution: An additional check has been added to see if the element being edited is text. If so, and it's a gradient style being changed, we remove the background image. Otherwise it is kept so that the button case from above is resolved. [1]: https://github.com/odoo/odoo/commit/2bf1db001b195480b963b338583c170aa1c009a3 [2]: https://github.com/odoo/odoo/blob/8e0845712f462ecfafd2176406dcbafc869a5564/addons/html_editor/static/src/main/font/color_plugin.js#L575 [3]: https://github.com/odoo/odoo/commit/8e0845712f462ecfafd2176406dcbafc869a5564 task-6247134 Forward-Port-Of: odoo/odoo#284788 Forward-Port-Of: odoo/odoo#279070
Copying an image that is already attached to another record now reuses the existing file instead of leaving an unnecessary duplicate. This helps keep stored media cleaner and avoids redundant attachments without changing the user workflow.
Original PR description
Copying an image attachment already linked to another record could leave a redundant duplicate behind instead of reusing the existing one. opw-6463012 Forward-Port-Of: odoo/odoo#284610 Forward-Port-Of: odoo/odoo#282287
Employee planning notification emails now show action buttons with a visible background, so links like "View your planning" can be read and clicked. This prevents confusion when employees receive published shifts or schedules.
Original PR description
Before this change: When publishing a shift or schedule, the buttons "Assign me this shift", "I am unavailable", and "View your planning" inside the notification email sent to the employee appears invisible. The button text is rendered in white on a white background, making the link unreadable and difficult to click. To reproduce: 1. Open the Planning app and create a shift with today's date in the time range. 2. Click "Publish". 3. Go to Settings > Technical > Email > Emails. 4. Open the email that was just sent. 5. Inspect the email body and observe that the "View your planning" button text is not visible. After this change: A default purple background is applied to the button, ensuring the white text is properly visible and legible across email clients. opw-6483147
The accounting report for invoiced items not yet delivered now excludes delivery fee lines, since those charges are not physical items to deliver. This prevents misleading report entries and helps accounting teams focus only on products that still require delivery follow-up.
Original PR description
Issue: --- Delivery lines are included in `invoiced not delivered` report, which is wrong as delivery lines are not deliverable. Steps: 1- Create a SO with a good product and add a delivery line. Set the product line as delivered and create an invoice. 2- Open accounting, and from review tab, open `Invoiced not Delivered`. As you see, delivery lines are included in the report. Fix: --- On stable we could fix it inside `_get_accrual_domain` by checking if `delivery` is installed. On master we need to implement a solution to be able to differentiate the lines that won't be delivered. opw-6360894 Forward-Port-Of: odoo/enterprise#123517
This change makes an automated CRM forecast check wait until an opportunity is fully marked as won before moving on. It reduces random test failures in the validation environment, helping keep releases and quality checks more stable without changing user-facing CRM behavior.
Original PR description
The crm_forecast tour is red randomly on runbot on the Won banner step. We click the won button and go back directly, so the kanban can be loaded before the lead is won. Now we wait for the ribbon first. runbot-242139 Forward-Port-Of: odoo/odoo#284721
This update fixes an automated Knowledge app test that was failing when entering calendar information. It helps keep quality checks reliable without changing the user-facing behavior of the app.
Original PR description
[Related PR 1] modified `editSelectMenuInput` to use the standard 'edit' action instead of a custom action, and moved several tours off of the helper function, but missed the knowledge calendar tour. In combination with [Related PR 2] which changed the conditions of editing a select input to not include the intial 'click' action, causes this tour to now fail to properly input the text value. This commit fixes this issue by using the new standard approach with the 'edit' action. Since there are no tours which make use of `editSelectMenuInput`, it is also deprecated and to be removed in master. Related PR 1: https://github.com/odoo/odoo/pull/264913 Related PR 2: https://github.com/odoo/odoo/pull/266912 runbot-941336
This fixes a broken automated tour step in Knowledge where calendar-related text input could fail after recent changes. It also marks an unused helper as deprecated, reducing reliance on outdated testing utilities without affecting normal users.
Original PR description
[Related PR 1] modified `editSelectMenuInput` to use the standard 'edit' action instead of a custom action, and moved several tours off of the helper function, but missed the knowledge calendar tour. In combination with [Related PR 2] which changed the conditions of editing a select input to not include the intial 'click' action, causes this tour to now fail to properly input the text value. This commit fixes this issue by using the new standard approach with the 'edit' action. Since there are no tours which make use of `editSelectMenuInput`, it is also deprecated and to be removed in master. Related PR 1: https://github.com/odoo/odoo/pull/264913 Related PR 2: https://github.com/odoo/odoo/pull/266912 runbot-941336
This fix prevents an unexpected error from appearing when Odoo handles certain report actions. It improves reliability by using the correct record context, helping users avoid interruptions during normal workflows.
Original PR description
opw-6360013 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 Forward-Port-Of: odoo/odoo#274977
Invalid VAT warning messages now preserve and display the full VAT number entered by the user, such as a Swiss VAT number with its country prefix. This reduces confusion by showing the exact value that failed validation, making it easier for users to correct contact tax details.
Original PR description
Before this change: When entering or importing a VAT number (e.g., CHE-115.391.649), an invalid VAT warning displays a string missing its country_id (e.g., E-115.391.649). This confuses users and masks the actual input string that triggered the validation failure. To reproduce: 1. Open any contact record and set the Country to Switzerland. 2. Enter an invalid or manually formatted Swiss VAT number like `CHE-115.391.649`. 3. Save or trigger the VAT validation check. 4. Observe the warning banner showing `E-115.391.649` instead of `CHE-115.391.649`. After this change: The validation warning logic preserves the original user input when constructing the alert message, ensuring error notifications accurately display VAT number. Issue introduced by: * https://github.com/odoo/odoo/commit/ac95d2d6d80a368dfb190d0ac21da2af479a8488 * https://github.com/odoo/odoo/commit/a2afe3292e1cd0a4f339dc47707e469653d13ea0 opw-6474217 Forward-Port-Of: odoo/odoo#284305
The French PDP registration wizard no longer shows an unnecessary “Production” label when users are already in production mode. This removes confusing wording and makes the registration screen clearer for business users.
Original PR description
It makes no sense to mention (Production) on pdp registration wizard when you are in prod mode Forward-Port-Of: odoo/odoo#280501 Forward-Port-Of: odoo/odoo#280360
This fixes an internal test issue in the Appraisals module that could fail when run around midnight. It helps keep automated checks stable without changing how employees or managers use the appraisal features.
Original PR description
### Explanation When `test_hr_appraisal` is run at, for example, 23:59:59, the line `self.hr_employee2.next_appraisal_date = date.today()` is executed after midnight, on the following day. As a result, a validation error is raised: `odoo.exceptions.ValidationError: You cannot set 'Next Appraisal Date' in the past.`
This fix prevents duplicate emails from being sent when employees submit expenses across multiple companies. It helps keep expense approval communications clearer and avoids unnecessary repeated notifications.
Original PR description
Fix a small issue resulting in mail duplication when submitting expenses from multiple companies that appeared in the infamous 704a5a19 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 Forward-Port-Of: odoo/odoo#284861 Forward-Port-Of: odoo/odoo#283013
Appointment invitation emails now generate public calendar links correctly by using the proper permission level for calendar access tokens. This prevents invitation emails from failing to render, helping customers and attendees receive appointment details without interruption.
Original PR description
Since calendar attendee access tokens are restricted to system users, appointment mail templates must sudo token reads when generating public calendar links. This follows the same pattern as the calendar mail templates and avoids an AccessError when rendering attendee invitation emails. ref: https://github.com/odoo/enterprise/commit/88a3cca752a5f726cd0260b485fc93f65a268cf8 Task-4711415 Forward-Port-Of: odoo/enterprise#129511
Attendance officer access is now aligned so these employees are also treated as regular internal users. This keeps attendance permissions consistent across supported versions and avoids access issues without changing expected business workflows.
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 Forward-Port-Of: odoo/odoo#284414 Forward-Port-Of: odoo/odoo#284191
This fixes an automated barcode manufacturing flow where a scrap quantity could be lost while the form was still updating after product selection. The change helps ensure scrap operations are recorded with the intended positive quantity instead of failing with an error.
Original PR description
Selecting the product in the scrap form triggers a `stock.move` onchange. The quantity step only waited for the input to exist, not for that onchange to be applied, so the value could be written while it was still in flight and be reset to 0 by its response. It was also assigned directly on the input, without any event, so the field was never flagged as dirty. The scrap was then recorded with a quantity of 0 and `action_scrap` rejected it with "You can only enter positive quantities.". Wait for the quantity input to hold its post-onchange value before typing, and dispatch an input event, like the other scrap tours already do. error-238911 Forward-Port-Of: odoo/enterprise#129410 Forward-Port-Of: odoo/enterprise#128931