Daily updates from Odoo
Tuesday, November 4, 2025
26 changes · saas-18.4
Enhancements to existing features
This update refreshes the QR-code URLs sent to Avalara when issuing Brazilian NFC-e invoices. It prevents invoice errors caused by outdated links, helping sales operations continue smoothly in states that changed their official QR-code addresses.
Original PR description
In This PR:
- Several states have updated their NFC-e QR-code URLs, which caused errors when issuing invoices due to invalid or outdated links. This commit updates the 'nfceQrCode' parameter in Avalara requests ('calculate-tax' and 'submit-invoice-goods') to ensure the correct QR-code links are used.
task- 5115845
Forward-Port-Of: odoo/enterprise#95726This change greatly speeds up the process of changing a contract template on a pending job offer. It reduces unnecessary database work so the action completes in milliseconds instead of minutes on large databases, improving responsiveness for HR teams.
Original PR description
Description ----------- - Fix performance regressions due to breaking the prefetcher via `[0]` indexing of `hr.version` and batch `write`. - Evaluate only the current employees contracts in `_get_contract_versions` for an *onchange* context, else the `hr. version` for all employees are fetched and evaluated, leading to significant overhead downstream. - Add missing index for `_remove_work_entries` Benchmark --------- On a database in 19.0, with ~10k employees, ~30k versions and ~5M work-entries, the onchange triggered when changing the contract template on a pending offer for a new lambda employee took: | | Before | After | |-------------|--------|--------| | Query Count | 107k | 349 | | Time | 2.9min | ~300ms | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
This fix makes GST Treatment more accurate when creating or fetching vendor bills through QR scan or IRN import. Instead of defaulting to "regular", Odoo now uses the GST Treatment returned by Partner Autocomplete, which helps reduce manual corrections and improves tax handling consistency.
Original PR description
Before this commit: We used to set `regular` treatment when using QR Vendor Scan or Fetching bill with IRN After this commit: We use the GST Treatment received from Partner Autocomplete to set the GST Treatment task-none --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#234136
This update fixes the way Chilean states are identified in customer addresses. It replaces non-standard numeric codes with the official ISO codes, which helps ensure address data is displayed and handled correctly across the system.
Original PR description
**Steps to reproduce:** 1. Go to Sales > Create and edit a new customer. 2. Select Chile as the country and choose a state. **Issue:** - State codes appear as numbers (e.g., 01, 02, 03...) which are not ISO-compliant. **Cause**: - State codes in the CSV file were defined as simple numbers instead of proper ISO codes. <img width="601" height="146" alt="image" src="https://github.com/user-attachments/assets/a941c200-467b-4ad5-8f79-ca9e8a92d7b4" /> <img width="443" height="131" alt="image" src="https://github.com/user-attachments/assets/dc1df1b0-2267-499f-ad1d-bb5c9381cd66" /> **Solution**: - Updated all state codes to match the official ISO 3166-2:IQ codes (Reference: https://www.iso.org/obp/ui/#iso:code:3166:CL) **opw-5148562** Forward-Port-Of: odoo/odoo#230963
Withholding invoices now include the VAT percentage correctly in the tax totals. This ensures the VAT amount is shown properly in Nilvera PDFs, avoiding missing or incomplete tax information on customer documents.
Original PR description
Before this commit: For withholding invoices, the VAT percentage was not included inside the <cac:TaxTotals> node, due to this, the VAT amount was not displayed in the PDF in Nilvera. After this commit: The VAT amount is shown correctly in the <cbc:Percent> node inside the <cac:TaxTotals> node and percent amount appears correctly in the PDF. task-5225600 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#233929
This update improves how ribbons and status bars look in modal forms. It prevents the ribbon from blending into the status bar and keeps the form layout visually cleaner when users scroll inside a pop-up window.
Original PR description
Previously, `position: static` was added on `.o_form_sheet` in modal forms to fix an issue where the ribbon looked ugly (not pinned to the top right) due to the absence of borders in modals. See…
Previously, `position: static` was added on `.o_form_sheet` in modal forms to fix an issue where the ribbon looked ugly (not pinned to the top right) due to the absence of borders in modals. See commit: https://github.com/odoo/odoo/commit/1ac2ff5b7dd64ccfe1bfb9c3fb7bb8a758e887d7 However, when a statusbar is present, this rule caused the ribbon to merge into the statusbar, making its display worse. In addition, on scrolling in a modal, the statusbar and the form contents were getting merged. This commit refines : - the selector so that `position: static` is only applied when a modal form has a ribbon but no statusbar. When a statusbar exists, the ribbon remains visually separated from the statusbar. - the statusbar background-color logic so that inside modals it uses the proper `$o-view-background-color`, ensuring a clean separation even on scrolling. task-4873636 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232315 Forward-Port-Of: odoo/odoo#226074
This update improves how Swedish bank accounts are identified during export so that several valid account formats are now correctly recognized. As a result, partner bank details are less likely to be mislabeled, which helps avoid errors in payment-related exports.
Original PR description
### Issue: Some valid Swedish account numbers are not recognized as Swedish. ### Steps to reproduce: - Install 'l10n_se_bban' and switch to Swedish company - Create a new partner, under the…
### Issue: Some valid Swedish account numbers are not recognized as Swedish. ### Steps to reproduce: - Install 'l10n_se_bban' and switch to Swedish company - Create a new partner, under the 'Accounting' page create a new bank account 1- 62074-0 2- 678653833066 3- 99603406872188 - In the partner list view select this new partner - Click Actions > Export, select "Banks" and "Bank Type" - Check the file 1- 62074-0 not recognized as Plusgiro 2- 678653833066 not recognized as BBAN 3- 99603406872188 not recognized as BBAN ### Cause: These numbers are not recognized by the checks of Odoo but are valid numbers: 1. Plusgiro account numbers can be 2 to 8 digits long, Odoo accepted only 7 to 8 digits account numbers 2. Old Handelsbanken numbers (6000-6999) can have 8 digits instead of 9, Odoo only accepts 9 digits numbers 3. Only clearing numbers starting with 8 are 5 digits long, Odoo also included ranges 9500-9549 and 9960-9969 ### Sources: 1 and 3: https://www.amcbanking.com/kb/swedish-payments-how-to-configure-sender-and-vendor-bank-accounts-in-fo/ 1 and 3: https://github.com/Tobbe/kontonummer.js/blob/04959502d7d2d52938aabda80b8a3464efddfdd1/kontonummer.js 2: https://github.com/barsoom/banktools-se/commit/b964806d5cad0491ea121419520fd5b5d4478c15 opw-5099867 Forward-Port-Of: odoo/enterprise#98147
This update prevents the appointment information page from showing a 404 error when a staff member is set to limit appointments to work hours but uses flexible hours. It improves reliability for customers and staff by ensuring availability is handled correctly in this case.
Original PR description
This PR fixes the 404 error displayed on the info page of a "Limit to Work Hours" appointment linked to a staff user with flexible hours. The availability of the staff user must not be computed from its work schedules as it has flexible hours. Task-5046134 Forward-Port-Of: odoo/enterprise#95336
This fix ensures upgrade steps are processed in a consistent order every time. It prevents rare cases where the same upgrade could be applied differently depending on how Python happened to store the list, improving reliability during migrations.
Original PR description
When we list the versions to upgrade we go over the values in `self.migrations[pkg.name]`. This object is a mapping of mappings `{script_location: {version: scripts_list}}`. The location could be `module` or `module_upgrades` for local scripts, or `upgrade` for scripts in any of the extra upgrade paths.
The problem is that if we have a minor version that matches a major one in different locations the order is non-deterministic. For example if we have a local upgrade script in `1.2`, and an extra upgrade script in `16.0.1.2`. Both `version` keys (`1.2` and `16.0.1.2`) will resolve to `16.0.1.2` when ordering. But the order they _actually_ appear in the set of versions is non-deterministic --due to the `set` implementation in Python.
The solution is to use a container that keeps the order, in this case a `dict`.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#234124This change fixes an issue in the web test framework where some default field values could be lost when a model was extended. As a result, date-related fields such as creation and update timestamps now behave correctly in tests, making them more reliable.
Original PR description
Before this commit, default values in mock fields defined by functions would be lost when extending a model, because by doing so the fields were JSON-copied and the default functions were lost. To fix this, this commit introduces another way to copy field definitions that preserves functions, allowing default values (typically for the 'create_date' and 'write_date' fields) to be applied correctly. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#234106
This change ensures that emission currency and unit values update correctly when an emission factor is changed. It prevents reports from showing outdated values, improving the accuracy of ESG emissions data.
Original PR description
The `currency` and `unit` fields on emitted emissions are supposed to be related fields on the emission factor. However, due to how the report combining accounting emissions and other emissions is implemented, they are not correctly updated when the factor is modified. This PR makes them computed fields and enable the "store" attribute en them. Despite there being no actual table to store data into, this allows us to do a round trip to the server to fetch the correct values. Forward-Port-Of: odoo/enterprise#98724
This update prevents a ringtone from being restarted after it has been stopped, even if a user presses the play/pause key on their headset or keyboard. It helps avoid confusion after calls end by making sure stopped ringtones stay stopped.
Original PR description
Before this commit, users can resume "stopped" ringtones by pressing the Media Play/Pause key of their keyboard/headphones, even after the call has ended. After this commit, stopping the ringtone clears the audio source, effectively preventing it from being resumed. Task-5222704 opw-5186087 Forward-Port-Of: odoo/enterprise#98660
When users prepare a document for signing, placeholder text for selection fields will now appear correctly. This makes the signing form clearer and helps signers understand what should be entered or selected.
Original PR description
To reproduce: ============= - upload a document to sign and add a selection field on it - set a placeholder for the selection field - open the document to sign -> the placeholder is not displayed Problem: ======== the placeholder is not displayed because there is no option holding the placeholder value. Solution: ========= Add an option at the beginning of the select options to hold the placeholder value. opw-5140676 Forward-Port-Of: odoo/enterprise#97887
This fix ensures that when a barcode is scanned in the product view, Odoo uses the complete barcode instead of only part of it. It prevents incorrect search results and makes barcode-based product lookup more reliable for users.
Original PR description
Issue ----- When scanning a barcode in the product view, the search is made using only part of the barcode. Steps to reproduce ----- - Open the product view - Scan a barcode (eg 1234567890) > The search might only contain 12345678, 123456 or actually the full barcode Cause ----- When scanning a barcode, we receive all of the barcode characters followed by newline. When we receive the newline, we select the first item in the dropdown. The problem is that the search input changed but it hasn't been reflected yet in the items (a rendering is scheduled but hasn't been applied to the DOM yet). ----- Ticket: opw-4874425 Forward-Port-Of: odoo/odoo#233245 Forward-Port-Of: odoo/odoo#232270
This update ensures that component lines removed in the subcontracting wizard are fully deleted, instead of staying behind as hidden records. It prevents confusing leftover inventory entries and keeps production and reporting data accurate.
Original PR description
Issue ----- Removing a line using the subcontracting wizard does not delete the line in DB, there is a "phantom" ML. Steps to reproduce ----- - Create a subcontracted product with 2 components - Add…
Issue ----- Removing a line using the subcontracting wizard does not delete the line in DB, there is a "phantom" ML. Steps to reproduce ----- - Create a subcontracted product with 2 components - Add one of each component in subcontractor's stock - Create a PO for the finished product and confirm it - Go to the production - Open the "Record components" wizard - Set quantity then remove the second line - Confirm production (don't update consumption) - Go to Inventory > Reporting > Moves History and remove the "Done" filter > There is a pending move in the report Cause ----- When saving the wizard's changes, we call a write on the production's `move_line_raw_ids` field to remove delete the line. The field is a simple compute, so we go through its' inverse method https://github.com/odoo/odoo/blob/be3a4283c383d187570f5a73f337030e6ae9d05c/addons/mrp_subcontracting/models/mrp_production.py#L34-L46 The problem is that we populate `line_by_product` using the values present in `move_line_raw_ids` from which we just removed the line. This means that when we do `move.move_line_ids = line_by_product.pop(move.product_id, self.env['stock.move.line'])` we replace the value of `move_line_ids` with only the remaining ones, which means we unlink the move line (*from the move*). Because the inverse field (`move_id` of the SML) is not set as `ondelete='cascade'`, the link is broken but the line remains in db. https://github.com/odoo/odoo/blob/f173c738b1adcf85a80eb641ad307b7cccf17294/odoo/fields.py#L4311-L4322 We cannot change the field to `ondelete='cascade'` as such a change would not be stable. Solution ----- Keep reference of the lines to be removed in order to delete them once `move_line_ids` has been updated. ----- Ticket: opw-4817397 Forward-Port-Of: odoo/odoo#233626 Forward-Port-Of: odoo/odoo#229310
The website loading progress bar now uses the brand primary color instead of black. This makes it easier to see in dark mode and keeps the interface more consistent with the rest of the website design.
Original PR description
This commits changes the website loader progress bar color, from black to `$primary`. This provides a better contrast in dark mode as well as better consistency. task-5170115 | Before | After | |--------|--------| | <img width="1920" height="1186" alt="image" src="https://github.com/user-attachments/assets/cd9525cf-b9d6-40dd-9ffb-ed0027020ab5" /> | <img width="1920" height="1172" alt="image" src="https://github.com/user-attachments/assets/3f7d9a4b-4a3e-4fbd-a1be-826c898466cd" /> | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232875
This change stops users from typing into or moving around decorative page elements like background shapes, filters, and parallax effects. It helps keep page layouts stable and avoids odd visual glitches when editing website content.
Original PR description
WIP
This update fixes an issue where removing a main product image could appear to succeed before the change was fully saved, causing test failures and unreliable behavior. It also simplifies how the test image is loaded, making the process more stable and less prone to delays.
Original PR description
Versions -------- 18.0+ Issue ----- The `test_website_sale_add_and_remove_main_product_image_no_variant` and `test_website_sale_remove_main_product_image_with_variant` tours fail because the main…
Versions -------- 18.0+ Issue ----- The `test_website_sale_add_and_remove_main_product_image_no_variant` and `test_website_sale_remove_main_product_image_with_variant` tours fail because the main product image is not removed as expected after the tour completes. Cause ----- Both tours assume that once the product `<img>` element is removed from the DOM, the action is fully completed. The tour then ends, and the remaining Python code verifies the result. However, this assumption can lead to issues. If the save request takes longer than expected, the Python code may execute prematurely and fail. Solution -------- Add a step at the end of both tours to wait for the `<img>` element to be fully saved and updated in the preview DOM. Additionally, during debugging, it was observed that using an alias URL (i.e., a redirect) to an `ir.attachment` could introduce further issues or slow down the test due to the server fetching the image with a remote call. To address this, this commit replaces the alias URL with a simple binary attachment. opw-5159593 runbot-163025 runbot-163615 Forward-Port-Of: odoo/odoo#233978
This update adjusts the order of steps in the website wishlist test so the wishlist count has time to refresh before the tour continues. It helps prevent random test failures and makes the automated checks more stable.
Original PR description
Modify the steps order to make sure the wishlist quanity has enough time to get updated runbot-229616 Forward-Port-Of: odoo/odoo#233998
Guests who have not been online for the past 12 hours will no longer receive notifications when a call starts. This reduces unnecessary alerts and helps prevent confusion for people who are no longer actively connected.
Original PR description
With this commit, guests who haven't been online in the last 12 hours will not be notified of a call starting. task-5136330 backport of https://github.com/odoo/odoo/pull/230337 Forward-Port-Of: odoo/odoo#233669 Forward-Port-Of: odoo/odoo#233221
This change keeps scrap orders consistent when the product is changed. If the new product does not use a BoM, the system now clears the BoM value instead of leaving an outdated one behind, preventing the scrap quantity from being set to zero by mistake.
Original PR description
Problem: When a user changes the product on a scrap order, the bom_id field does not get updated. If they update the product from a product that has BoM to a product that doesn’t have one, then the…
Problem: When a user changes the product on a scrap order, the bom_id field does not get updated. If they update the product from a product that has BoM to a product that doesn’t have one, then the bom_id field is hidden and remains set. This will cause the scrap quantity to be set to 0 when they validate the scrap. However, the product move actually happens for the correct quantity causing an inconsistency. Purpose: This will either set the bom_id field to False if the new product doesn’t have a valid BoM, or it will update it to the first available BoM. Steps to Reproduce on Runbot: 1. Create a scrap order for a product that has a kit type BoM and set the kit field. 2. Change the product to a product without a kit type BoM. 3. Validate the scrap order. 4. Observe the quantity field is set to 0, but there are product moves for the correct quantity. opw-5122880 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#234050 Forward-Port-Of: odoo/odoo#231937
This change makes uploaded website videos compatible with content sanitization, so pages can still be edited later by users with restricted permissions. It prevents a situation where a video added by an admin could make the page appear uneditable for other users.
Original PR description
Steps to reproduce the current behaviour: - Update the DEMO user to be a website "restricted editor" and sales "admin" who cannot bypass HTML field sanitization. - As ADMIN, add a YouTube video to a…
Steps to reproduce the current behaviour: - Update the DEMO user to be a website "restricted editor" and sales "admin" who cannot bypass HTML field sanitization. - As ADMIN, add a YouTube video to a product page > Save. - As DEMO, try to update the content on the product page > You cannot (a dialog informs you that you cannot edit the content because an admin edited it previously). Explanation: Starting from [1], an HTML field can be flagged as `sanitize_overridable` which allowed users with the `base.group_sanitize_override` group to skip the HTML field sanitize process. If such users added some content that is not considered "sanitize friendly" (e.g. YouTube iframe), a restricted user won't be allowed to add content in the fields, since the sanitizer will remove the original content from the DOM. For this case, the code from [2] added an implementation to consider the field as none editable and warn the user once he tries to update it. Implementation: The goal of this commit it to fix the current limitation for video upload that currently prevents non admin users to edit a website record once an admin adds a video on it... The idea of the fix is the following: - We already have a technical fallback when uploading a video to save the iframe `src` to an attribute: `data-oe-expression`. - The public widget is now destroying the video iframes so they are never saved in the DOM. - A non-lazy code will build the iframes immediately on page load. - The public widget can always create the iframes if they are not already created (for compatibility). [1]: https://github.com/odoo/odoo/commit/cf844e34dd0ce4830eb99fd0fa5b6b9cb58c867c [2]: https://github.com/odoo/odoo/commit/cb80c15d3db49ede3c93171abcaa9064b88822c6 task-3757205 Forward-Port-Of: odoo/odoo#232871 Forward-Port-Of: odoo/odoo#175717
This update helps the system notice broken browser connections much sooner when the network is slow or unstable. As a result, users are less likely to experience long pauses where messages stop arriving without warning.
Original PR description
When a TCP connection is not closed cleanly, it can take minutes to detect a closed WebSocket connection. During this time, no messages are received. This can happen in slow or unstable network conditions. Browsers do not expose WebSocket ping/pong mechanisms. To detect dead connections quickly, periodic application level messages are sent if no messages were either sent or received within a minute. This approach ensures quicker detection compared to relying on the OS TCP timeout, which is typically set to a high value. X-original-commit: d043e12 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#234275
Fixed an issue where checkout could get stuck loading when external tax checks failed during Brazilian sales. Instead of freezing, the system now captures the problem and shows it in the next checkout step so customers can continue or correct the issue.
Original PR description
**Issue** When buying products in the Brazilian localization, certain errors in external tax calculation were not properly caught by the frontend. This caused the checkout to hang indefinitely with…
**Issue** When buying products in the Brazilian localization, certain errors in external tax calculation were not properly caught by the frontend. This caused the checkout to hang indefinitely with infinite loading. Examples include missing NCM codes or IAP service failures due to invalid addresses. **Steps to Reproduce** 1. Install Brazilian localizations (l10n_br, l10n_br_avatax, l10n_br_edi). 2. Configure Avatax Transfer API credentials (API ID and Key). 3. Create a website with a Brazilian company. 4. Add a product to the cart and proceed to checkout. 5. Choose a delivery method and observe that the UI gets stuck loading. **Root Cause** The `_order_summary_values` method in `website_sale_external_tax` called `_get_and_set_external_taxes_on_eligible_records()`, which could raise exceptions (e.g., IAPServerError). These exceptions were not handled, so they propagated to the frontend as generic RPC errors. The frontend has no built-in mechanism to display these exceptions as user-friendly messages, resulting in infinite loading. **Fix** Wrap the external tax calculation in `_order_summary_values` and catch `UserError`. Instead of letting the exception propagate as a generic RPC error, attach the error message to the result dictionary under `external_tax_error`. This prevents the frontend from hanging while still making the underlying problem visible in the next checkout step, where validation errors are properly handled and shown to the user. Opw-5052078 Forward-Port-Of: odoo/enterprise#96213 Forward-Port-Of: odoo/enterprise#95045
The mail system now checks only real emails when looking for repeated sender loops. This avoids incorrectly blocking a customer’s next email when other non-email messages from the same author had already increased the count.
Original PR description
When detecting loops with _detect_loop_sender if the count of these messages exceeds the LOOP_THRESHOLD, the next email from that user is blocked, even if the number of new emails alone hasn't yet crossed the threshold due to mail messages that are not email triggering the loop detection. This happens because it searches for messages in the mail.message model that share the same model name and author irrespective of the message type. To correct this, the function's search criteria must be modified to explicitly filter for messages where the message_type is set to 'email'. opw-5122962 Forward-Port-Of: odoo/odoo#232026
This update corrects a stock-related automated test that previously appeared to pass even though it had hidden issues. It helps ensure future checks are reliable, reducing the risk of carrying forward broken behavior unnoticed.
Original PR description
Due to an issue in the runbot, the test associated with the PR: odoo#229958 passed despite underlying conflicts and the PR was merged. This PR addresses and resolves those issues to ensure the test functions correctly. Impacted versions: - 18.0 - saas-18.2 - saas-18.3 - saas-18.4 19.0 and master are addressed in odoo#230685 to replace `procurement.group` with `stock.rule` --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#230687