Wednesday, July 8, 2026
24 changes · saas-19.2
Enhancements to existing features
When users resize tables, the horizontal scrollbar now appears on the table itself instead of affecting the whole editor area. Existing resized tables are also updated automatically when the editor loads, so the behavior is consistent for old and new content.
Original PR description
#### Description of the issue this PR addresses: - Resized tables stored their width on the `table` element. When such tables became wider than the editable area, a horizontal scrollbar appeared on the main editable. #### Desired behavior after PR is merged: - Width handling is now moved to `tbody` so the scrollbar stays on the table itself instead of the editable. - This PR also updates already resized tables when loading the editor to ensure they follow the same behavior. task-5123011 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272977
The Azerbaijani Manat (AZN) now uses its official symbol, ₼, in Odoo. This improves accuracy and consistency when displaying prices and financial reports for users working with this currency.
Original PR description
This commit updates the base currency symbol for the Azerbaijani Manat (AZN) to its official Unicode character '₼'. Related Upgrade PR: https://github.com/odoo/upgrade/pull/10107 task-6112867 Forward-Port-Of: odoo/odoo#262471
Resolved issues and error corrections
Pasting document links into an empty message no longer adds an unnecessary blank line at the start. This keeps shared document messages cleaner while still separating links from any existing text when needed.
Original PR description
Before this commit, adding document links always prepended a line break before the generated links. When the composer was empty, this resulted in messages starting with an unnecessary blank line. This commit only inserts a line break when the composer already contains text, avoiding the extra spacing while preserving the separation between existing content and pasted links. task-[5947683](https://www.odoo.com/odoo/project/1519/tasks/5947683) Forward-Port-Of: odoo/enterprise#120952
The AI module tests now skip markdown rendering checks when the optional markdown component is not installed. This prevents unnecessary test failures in environments that do not include that optional dependency, improving reliability for releases and maintenance.
Original PR description
markdown2 is an optional dependency, so `markdown_format` can fail to process markdown, in which case all the markdown tests fail. Skip the markdown rendering test if there's no markdown rendering to test.
This fix prevents delivery tracking from failing when EasyPost returns an empty tracker value. Users can continue processing shipments without encountering an unexpected error while viewing or generating tracking links.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400Restored and updated automated checks for rental and Kenyan stock valuation flows after earlier accounting valuation changes. This helps ensure stock receipts and vendor bill amounts stay aligned, reducing the risk of incorrect valuation-related behavior in future updates.
Original PR description
*: sale_stock_renting, l10n_ke_edi_oscu_stock Re-enable and adapt the tests skipped to fast merge the valuation refactoring made in 08b62a4bbcc6f9a391b2cc00a621ef4c76100229. The stock IO now values the receipt from the vendor bill, so the shared purchase fixtures `l10n_ke_edi_oscu` need to match the values provided in `l10n_ke_edi_oscu_stock` see for instance: https://github.com/odoo/enterprise/blob/ce68644f97ac28568b9497a18079a4ad5ce4a125/l10n_ke_edi_oscu/tests/expected_requests/save_purchase_2.json#L11-L13 Forward-Port-Of: odoo/enterprise#122857
The website now shows the exact discount percentage configured for subscription products when prices are displayed with tax included. This avoids confusing customers and merchants with rounded-down discounts, such as showing 4% instead of the intended 5%.
Original PR description
Steps to reproduce: 1. Install eCommerce and Subscriptions. 2. Create a 21% Excluded tax. 3. Create a subscription product with a price of 45 with 21% tax and enable "Accept One-Time" in the…
Steps to reproduce: 1. Install eCommerce and Subscriptions. 2. Create a 21% Excluded tax. 3. Create a subscription product with a price of 45 with 21% tax and enable "Accept One-Time" in the Recurring Prices tab. 4. Publish the product on the website under the Sales tab. 5. Create a pricelist for 6 months recurring with two lines: - If min quantity is 0, then 0% discount - If min quantity is 2, then 5% discount 6. Set "Display Product Prices" to "Tax Included" in the Settings. 7. Open the product on the website, select the 6-month plan, and increase quantity to 2. Issue: The discount percentage displayed on the website shows 4% instead of the configured 5%. Why this happens: In `_get_additionnal_combination_info`, the discount is reverse-calculated from the tax-included price vs the tax-included sales price. When the 21% tax is included to both prices, it introduces a floating-point precision loss (4.9954..%), which floor() then truncates to 4%. Fix: When the pricelist rule uses 'percentage' discount, read `percent_price` directly from the pricing rule instead of reverse-calculating from tax-adjusted prices, as it represents the exact discount percentage the merchant configured with no floating-point involvement. opw-6224735 Forward-Port-Of: odoo/enterprise#121654
Popovers in dark mode now display buttons and embedded forms with clearer, more consistent styling. This makes actions easier to identify and prevents form areas from visually clashing with the popover background.
Original PR description
Before this commit, content like form & secondary button rendered inside popovers had inconsistent styling in dark mode: - secondary buttons did not stand out properly from the popover background, making them look like plain text blocks rather than actionable buttons; - forms rendered inside popovers (such as the multi-create popover) kept their default background, which visually clashed with the popover background. This commit fixes these issues by: - adding dedicated secondary button background colors for popovers, including hover state; - aligning form backgrounds inside popovers with the popover background. task-6249985 Forward-Port-Of: odoo/enterprise#121631
Marketing Automation now shows the correct reason when a participant is removed from a campaign. If a record still exists but no longer matches the campaign filter, users will see that it was filtered out instead of incorrectly being told the record was deleted.
Original PR description
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The…
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The removed bucket also contains records that still exist but no longer match the campaign filter, so the cancelled trace dialog shows "Record deleted" even when the record was only filtered out. In `sync_participants`, the to_remove participants are split between those whose record still exists in the database (filtered out by the campaign domain) and those whose record was actually deleted. `action_set_unlink` accepts an optional `trace_message` argument, defaulting to "Record deleted", and the filtered-out batch passes "Record no longer matches campaign filter" so the cancelled trace dialog reflects the real cause. Steps to reproduce: 1. Install Marketing Automation and CRM. 2. Open Marketing Automation, create a campaign on Lead with filter Stage = New. 3. Add a begin activity to the workflow. 4. Open CRM, create a Lead in the New stage. 5. Back in the campaign, click Generate Participants. 6. In the CRM pipeline, drag the Lead from New to Qualified. 7. Back in the campaign, click Generate Participants again. 8. Open the Participants smart button, click the participant for the moved Lead. 9. Click the cancelled activity in the workflow timeline. => The activity dialog shows "Error message: Record deleted" although the Lead still exists. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6251264) opw-6251264 Forward-Port-Of: odoo/enterprise#118692
This fix preserves the expected behavior of Knowledge file navigation when using newer Chrome versions. It prevents an underlying browser change from altering how scroll actions complete, helping avoid small interaction glitches for users.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
Pakistan’s currency symbol now appears before the amount instead of after it. This brings the display in line with local market practice and makes currency formatting more familiar for users in Pakistan.
Original PR description
This commit updates the symbol position of Pakistan's currency (PKR) to `before amount`, as previously it was displayed `after amount`, which is not the market practice; as shown over [here](https://drive.google.com/file/d/14pcqXTZSR0BygBXGvgQ6oCLRW0-4dYUh/view?usp=drive_link). This is a backport of [PR](https://github.com/odoo/odoo/pull/269204) task-6236452 Forward-Port-Of: odoo/odoo#271499
This change prevents a crash when users try to split a transfer that has already been completed. Since there is nothing left to split in that situation, the system now safely exits instead of showing an error.
Original PR description
Issue before this commit: ========================= When splitting a done picking that contains at least one stock move whose done quantity is less than the demanded quantity (product_uom_qty), an…
Issue before this commit: ========================= When splitting a done picking that contains at least one stock move whose done quantity is less than the demanded quantity (product_uom_qty), an expected singleton traceback occurs. Steps to Reproduce: ========================= - Install the stock module with demo data. - Create a delivery picking for any product with a demand of 5. - Set the done quantity to 2. - Validate the picking without creating a backorder. - Try to split the validated/done picking. - An expected singleton traceback is raised. Cause of the issue: ========================= Previously, attempting to split a done picking simply returned because there was nothing left to split. After this [PR](https://github.com/odoo/odoo/pull/224952), the split action calls **message_post()** to post a note on the original picking of the generated backorder. However, no backorder is created when splitting a done picking since there is no remaining quantity to split. As a result, message_post() is called on an empty recordset, leading to an expected singleton traceback. With This Commit: ========================= Splitting a done picking has no functional purpose, as there is nothing left to split. In this case, simply return without performing any action. This preserves the previous behaviour and prevents the traceback. Forward-Port-Of: odoo/odoo#274382
This change corrects an unreliable automated test in the Mail app so it matches how the product really works. It improves test stability and reduces false failures during development and continuous integration, without changing the user experience.
Original PR description
The `bus subscription is refreshed when channel is joined` test is sometimes failing. This test doesn't make sense: it opens the command palette and wait for a subscription to be made. However, a subscription is only done when needed (opening the thread or being a member of the channel). The step was satisfied by luck. This commit fixes the test to reflect production code: the subscription is made once the channel is opened. runbot-941462 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#274741
The print button on customer invoices has been returned to its previous placement and emphasis. This removes a confusing change and keeps the button less prominent unless the invoice has been sent, which better matches how users work with invoices.
Original PR description
In task-6269645, the print button on customer invoices was set to secondary instead of primary. This is a mistake and it's confusing, so it's being reverted in this commit because it only needs to be secondary if the move is sent. task-6357618 Forward-Port-Of: odoo/odoo#273953
This update resolves a bug that caused the activity counter in the avatar card tour to fail due to timezone discrepancies. By scheduling activities with a fixed, past deadline, the counter now accurately reflects activity states regardless of user or server timezones. This ensures consistent and reliable reporting.
Original PR description
The avatar card tour asserts the systray activity counter, which only counts activities whose state is today or overdue. The test scheduled its activities without an explicit deadline, so…
The avatar card tour asserts the systray activity counter, which only counts activities whose state is today or overdue. The test scheduled its activities without an explicit deadline, so activity_schedule fell back to context_today on the class environment, whose superuser has tz Europe/Brussels with demo data. When the test runs between 22:00 and 00:00 UTC, that deadline is tomorrow from a UTC point of view. The state of an activity is however computed in the timezone of its assigned user, and hr_user is created without one, falling back to the server date (UTC). Its activities were therefore planned instead of today, the counter stayed empty and the tour timed out. The admin iteration kept passing because demo data gives admin the same Brussels timezone as the environment that computed the deadline, which is why only half the runs failed (both occurrences at 23:56 and 23:31 UTC). Schedule the activities with a deadline one week in the past instead: an old deadline is overdue in every timezone, whatever timezone the scheduling environment or the assigned user has, making the counter deterministic at any time of the day. https://runbot.odoo.com/odoo/error/941407 Forward-Port-Of: odoo/odoo#274679
This update resolves an issue preventing users from easily editing the alignment of text within the website's title form. The previous design used a utility class that blocked the web editor's functionality. This change ensures text alignment can now be adjusted through the standard web editor interface, improving user customization options.
Original PR description
`s_title_form` comes with the `text-center` utility class which forbids edition through the web_editor, it needs to use inline-style instead. task-6149380 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#263334
This update ensures the Account EDI Proxy Client is configured for the demo environment, rather than the test environment. This change aligns with existing settings in the related account_peppol module and prevents issues related to incorrect user configurations. It’s a minor fix to improve stability.
Original PR description
The system parameter is already brought to demo in account_peppol module. But the current users are not for pdp. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272462
This update resolves a problem where users couldn't delete expenses that had attached files. The fix ensures that expenses with attachments can now be successfully deleted, preventing data loss and improving the usability of the expense tracking system. This change was made as part of our ongoing commitment to stability and reliability.
Original PR description
To reproduce: - Create an expense - Add an attachment - Try to delete the expense --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274710
This update resolves an issue preventing users from successfully uploading files or dragging images into scheduled messages. The fix ensures that attachments work correctly and enables the drag-and-drop functionality, streamlining the process of adding content to scheduled communications.
Original PR description
Steps to reproduce: 1. Create a log note or send a message on any record and open the full composer. 2. Set a date in the future to schedule the message for later and click schedule. 3. Click on the…
Steps to reproduce: 1. Create a log note or send a message on any record and open the full composer. 2. Set a date in the future to schedule the message for later and click schedule. 3. Click on the "Edit" button of the newly scheduled message. 4. Try dragging and dropping an image into the body, or add a file as an attachment using the button. Issue: - Dragging and dropping an image into the form does nothing. - Trying to add a file as an attachment using the button triggers a traceback: `TypeError: Cannot read properties of undefined (reading 'resId')` Why this happens: - The failure when adding explicit file attachments occurs because the `model` and `res_id` fields were omitted from the `mail.scheduled.message` form view layout in the commit 3b985d2. Without these field declarations, the `mail_composer_attachment_selector` widget cannot determine the record metadata parameters, causing the upload to crash. - The failure of the drag-and-drop mechanism occurs because the scheduled message edit view uses the default `FormController` class instead of `MailComposerFormController` which is used in the `mail_compose_message` view. Consequently, the underlying `useCustomDropzone` is never instantiated on the view, leaving drop events unhandled. Fix: 1. Specify `js_class="mail_composer_form"` to the scheduled message form view definition tag to handle drag and drop, as well as adding the missing fields 2. Assign the `resIds` variable based on the message type since it is defined as `res_id` instead of `res_ids` in `mail.scheduled.message`. opw-6273260 Forward-Port-Of: odoo/odoo#268515
This update fixes a potential error that could occur when users attempted to access certain features within the MRP Subcontracting module. The change ensures smoother operation and prevents disruptions to the production process. This resolves an internal issue identified and addressed by the development team.
Original PR description
opw-6316136 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#271739
This update resolves an issue where the counted inventory quantity was incorrectly resetting to zero after manual input in the Physical Inventory screen. The previous code automatically cleared the count when the user moved to a different line. This fix ensures the quantity is only reset after the user has manually entered a value.
Original PR description
Versions -------- - 19.0+ Steps ----- 1. Open Physical Inventory; 2. click on a line; 3. click on a different line. Issue ----- Counted quantity automatically gets set to 0. Cause ----- Commit 3187030 changed the counted quantity widget to enable mutli-line edit. Part of this was done by ignoring the `onInput` hook, and always updating the counted quantity `onBlur`, making it so that the value is set to zero when clicking away, regardless of manual input. Solution -------- Use a `hasInput` state which gets set to `true` on user input. If not `true`, don't update the counted quantity on blur. opw-6365084 Forward-Port-Of: odoo/odoo#274364
This update resolves an issue where deleting a field in a model triggered an access error, even if the field wasn't directly linked to the website. The fix ensures the search for used fields is performed with elevated permissions, preventing the error and allowing field deletion to proceed smoothly.
Original PR description
# How to reproduce - Install the Website module - Install another module that has atleast one model with one html field, sanitize=Flase or sanitize_form=False and groups - Remove the field's group…
# How to reproduce - Install the Website module - Install another module that has atleast one model with one html field, sanitize=Flase or sanitize_form=False and groups - Remove the field's group from the current user - Enable dev mode - Go to Settings > Technical > Database Structure > Models - Pick any model (e.g. sale.order.line) - Add a field to that model & Save - Delete the added field & Save > Note : Significantly harder to reproduce since : https://github.com/odoo/odoo/commit/9a336bbb94b0a4266d84f7554c024c3abd2d1e7c I am not sure a field as mentionned in the steps exists # The problem An access error is raised for the module wich access rights were removed, even if the module is not linked in any way with the picked model # Cause of the issue Deleting the field will endup calling the `unlink()` method of `BaseModel` on the `ir.model.fields` record. This function triggers all `@api.delete` methods defined on the model : https://github.com/odoo/odoo/blob/5538132d9d14c4cc5031fc50ac0388ad2ab0fc92/odoo/models.py#L4548-L4552 This will call the this method : https://github.com/odoo/odoo/blob/5538132d9d14c4cc5031fc50ac0388ad2ab0fc92/addons/website/models/website_form.py#L153-L154 That was introduced by : https://github.com/odoo/odoo/commit/c0a827519844ec43537e4487f6abe358bb82ba9a Which prevents a field from being deleted if it is actively used in any website form. But this method does a search on every model return by `_get_html_fields` which may contains models that are not accessible by the user, so we get an access error. # Proposed solution Since `_check_if_used_in_website_form` should perform the same independently from the user, we can do the search in sudo opw-6231951 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274332 Forward-Port-Of: odoo/odoo#265781
This update streamlines the self-ordering process in Odoo by removing redundant state assignments within the `_check_pos_order` function. This optimization prevents unnecessary delays and improves the overall responsiveness of the point-of-sale system. The change ensures a smoother user experience for customers placing self-orders.
Original PR description
Remove useless assignation of state from frontend in `_check_pos_order` because its overrided just after in the process. Forward-Port-Of: odoo/odoo#272469 Forward-Port-Of: odoo/odoo#272176
This update corrects a bug in the Odoo accounting module's journal entry preview. Previously, omitting currency information resulted in incorrect display of credit amounts. Now, the preview accurately reflects the credit value, ensuring consistent and reliable reporting for financial data.
Original PR description
In _move_dict_to_preview_vals(), when no currency is provided, the credit column falls back to the line's debit value, so any caller omitting currency_id would show the debit amount in both columns of the journal entry preview. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274594 Forward-Port-Of: odoo/odoo#269335