Tuesday, November 4, 2025
15 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#95726Resolved 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 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 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 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
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 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
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