Daily updates from Odoo
Wednesday, May 20, 2026
14 changes · saas-18.3
Resolved issues and error corrections
This update fixes an issue where URLs with mixed or uppercase letters weren't automatically converted to clickable links within the HTML editor. The change ensures that all URLs, including single-character domains like 'x.com', are correctly recognized and linked. This improves the user experience by making it easier to share and navigate to online resources.
Original PR description
### Description of the issue/feature this PR addresses: - URL_REGEX was constructed with the "i" flag, but passing a RegExp object to new RegExp(regex, "g") silently drops the original flags, leaving only "g". This caused uppercase (ODOO.COM) and mixed-case (Odoo.Com) URLs to not be converted to links when pressing space. ### Desired behavior after PR is merged: - URL_REGEX.source with explicit "gi" flags to preserve case-insensitive matching in `prepareConvertToLink`. - Allow automatic URL detection for single-character domains such as `x.com`, `t.co`, and `a.io` by relaxing the minimum domain label length in the URL regex from 2 to 1 characters. task-6199269 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#263255
This update resolves a minor error in the Mexican accounting module (l10n_mx) related to a typo in the account group data file. The correction ensures accurate reporting and compliance with Mexican tax regulations. This change was prompted by a document from the Mexican tax authority (SAT).
Original PR description
Source: https://www.sat.gob.mx/minisitio/NormatividadRMFyRGCE/documentos2026/rgce/anexos/Anexo24delasRGCEpara2026.pdf opw-6174385 Forward-Port-Of: odoo/odoo#262549
This update fixes an error in the Luxembourg Annual VAT Declaration report that resulted in incorrect calculations for Appendix E 1a. The fix ensures that all relevant tax data is included accurately, improving the reliability of the report and its compliance with Luxembourg regulations. This resolves a discrepancy in the reported VAT totals.
Original PR description
### Issue: The formula `L10N_LU_TAX_163` in the Luxembourg Annual VAT Declaration was incorrect: - `L10N_LU_TAX_791.year_start` was added twice - `L10N_LU_TAX_993.year_start` was missing As a result, the computed total in Appendix E 1a was incorrect ### Steps to reproduce: - Install `l10n_lu_reports` - Open the `Report: Annual VAT Declaration (LU)` - Go to `Appendix E` - Use the `Start of Financial year` pencil icons to manually set values for fields `791` and `993` - Check the computed value of field `163` After the fix, both values are included exactly once in the formula opw-6158950 Forward-Port-Of: odoo/enterprise#117214
This update fixes an issue where vendor bills were incorrectly using Swiss tax rates when the invoice originated from a Belgian company. The change ensures that the correct tax rate, based on the company's fiscal localization, is applied during the import process. This prevents errors and ensures accurate tax calculations for invoices.
Original PR description
**Steps to reproduce:** - Create a company in Belgium and set the fiscal localisation accordingly. - In the same company, create a fiscal position in Switzerland, set the foreign tax ID and then…
**Steps to reproduce:** - Create a company in Belgium and set the fiscal localisation accordingly. - In the same company, create a fiscal position in Switzerland, set the foreign tax ID and then generate the taxes for it. - Install the module account_edi_ubl_cii. - Create and invoice for a belgian customer, with one product line having a 0% tax. - Export the invoice as XML. - Go to taxes, filter by purchase, and make sure that the 0% switzerland tax has a higher sequence than the belgian 0% tax. - Import the previous invoice XML as a vendor bill. **Issue:** After importing the bill, the switzerland tax is used even though the fiscal localisation is belgian, which is wrong as it violates the constraint _validate_taxes_country **Solution:** Added a more selective domain to _import_fill_invoice_line_taxes opw-5467936 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#263560 Forward-Port-Of: odoo/odoo#255848
This update resolves an error that prevented users from initiating replenishment when no suitable routes were configured for a product. The fix ensures the system handles cases where routes aren't defined correctly, preventing a crash and allowing replenishment to proceed smoothly. This improves the reliability of the stock management process.
Original PR description
## Steps to Reproduce: 1. Install the stock module. 2. Activate "Multi-Step Routes" from settings. 3. Activate the "My Company (Chicago)" company. 4. Create a route for the Chicago company. 5. Create a new product and enable the created route on it. 6. Click on the "Replenish" button. ## Error: `IndexError - tuple index out of range` ## Cause: At [1], when none of the product routes belong to the current company or are shared routes, the filtering returns an empty recordset. As a result, trying to access the first route from the empty result raises an index error. ## Fix: This commit only assigns `route_id` when a route matches the given condition. Otherwise, it keeps the value as `False`. [1] - https://github.com/odoo/odoo/blob/13c0e082c260381a332fe1425fe2ba83a1c0c579/addons/stock/wizard/product_replenish.py#L78 sentry-7488075413 Forward-Port-Of: odoo/odoo#265179
This update resolves an issue where UBL invoices would fail to import due to extra spaces in the 'EndpointID' field. The change automatically removes these spaces, ensuring invoices are correctly processed and imported, improving data accuracy.
Original PR description
**PROBLEM** When importing a ubl that, for some reason, have trailing space on the text of the EndpointID node, we refuse it. This PR strips the trailing spaces on the import. **STEP TO REPRODUCE** 1. Import a ubl as a bill, with a trailing space in the EndpointID of the other party. 2. Notice the import fail, with the error: The Peppol endpoint (50238597645 ) is not valid. It should contain only letters and digit. opw-6227395
This update ensures that event tickets are correctly created when selling event tickets through the POS system while offline. Previously, a page reload would cause the system to lose the ticket information. Now, the system retains event registration details until the order is fully synced with the server, guaranteeing accurate ticket generation.
Original PR description
When selling event tickets in POS while offline, the order could be synced later but without creating event registrations (tickets) after a page reload. Steps to reproduce: ------------------- * Open…
When selling event tickets in POS while offline, the order could be synced later but without creating event registrations (tickets) after a page reload. Steps to reproduce: ------------------- * Open a POS session with `pos_event` * Sell an event ticket * Switch to offline mode * Validate payment while offline (order becomes paid but unsynced) * Reload/close and reopen POS, then reconnect * Let the order sync > Observation: The `pos.order` is created on the backend, but `event.registration` and `event.registration.answer` are missing so tickets are not generated. Why the fix: ------------ `pos_event` used `order.finalized` as IndexedDB cleanup condition for `event.registration` and `event.registration.answer`. For paid-but-unsynced orders, `finalized` is already true, so those records can be removed from IndexedDB too early. After reload, the order is restored/synced but without its event registration payload. Implementation: --------------- Use `order.canBeRemovedFromIndexedDB` instead of `order.finalized` for `event.registration` and `event.registration.answer` retention rules, so records are kept locally until the order is truly synced (server id assigned) or canceled. Test Note: --------------- Use case is hard to simulate exactly. Add a basic unit test to assert both registration models are kept for paid unsynced orders and only removable once synced. opw-6056079 Forward-Port-Of: odoo/odoo#263912 Forward-Port-Of: odoo/odoo#256615
This update resolves an issue where the Point of Sale system incorrectly applied AvaTax fiscal positions even when AvaTax wasn't activated in the POS. The fix ensures that AvaTax fiscal positions are only used when AvaTax is enabled, preventing incorrect tax calculations for customers. This improves the accuracy of sales tax processing.
Original PR description
**Steps to reproduce:** - Install Accounting and Point of Sale - In Accounting settings, activate "AvaTax" - Configure the AvaTax fiscal position and activate "Detect Automatically" option - Make…
**Steps to reproduce:** - Install Accounting and Point of Sale - In Accounting settings, activate "AvaTax" - Configure the AvaTax fiscal position and activate "Detect Automatically" option - Make sure that the other fiscal positions don't have that option set or that they are ordered after the AvaTax one - Go to the settings of a point of Sale - Activate "Flexible Taxes" and configure "Default" and "Allowed" - Make sure that AvaTax fiscal position is not allowed - Do not activate "AvaTax PoS Integration" - Open a POS session - Select a customer with an address in the US and without fiscal position - Check the fiscal position **Issue:** The selected fiscal position is the AvaTax one even though AvaTax is not activated in the POS. **Cause:** We force the use of a fiscal position if it is configured on a customer. In this case, as no fiscal position is configured on the customer, we try to retrieve one that matches the condition and the AvaTax one is selected. **Solution:** When searching for the fiscal position of a customer, if AvaTax is not configured in the POS and if its fiscal positions are not allowed in POS, we ignore the fiscal positions using AvaTax. opw-6154089 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update corrects a bug where the POS system incorrectly defaulted to using AvaTax fiscal positions, even when AvaTax wasn't activated in the POS. The fix ensures that the POS only uses AvaTax fiscal positions if AvaTax is enabled in the accounting settings, aligning with user preferences and improving data accuracy.
Original PR description
**Steps to reproduce:** - Install Accounting and Point of Sale - In Accounting settings, activate "AvaTax" - Configure the AvaTax fiscal position and activate "Detect Automatically" option - Make…
**Steps to reproduce:** - Install Accounting and Point of Sale - In Accounting settings, activate "AvaTax" - Configure the AvaTax fiscal position and activate "Detect Automatically" option - Make sure that the other fiscal positions don't have that option set or that they are ordered after the AvaTax one - Go to the settings of a point of Sale - Activate "Flexible Taxes" and configure "Default" and "Allowed" - Make sure that AvaTax fiscal position is not allowed - Do not activate "AvaTax PoS Integration" - Open a POS session - Select a customer with an address in the US and without fiscal position - Check the fiscal position **Issue:** The selected fiscal position is the AvaTax one even though AvaTax is not activated in the POS. **Cause:** We force the use of a fiscal position if it is configured on a customer. In this case, as no fiscal position is configured on the customer, we try to retrieve one that matches the condition and the AvaTax one is selected. **Solution:** When searching for the fiscal position of a customer, if AvaTax is not configured in the POS and if its fiscal positions are not allowed in POS, we ignore the fiscal positions using AvaTax. opw-6154089
This update fixes a bug that caused duplicate partner creation during EDI import of Swiss VAT documents. The change adds logic to correctly match both formatted and unformatted Swiss VAT numbers, ensuring accurate partner identification and preventing import errors. This improves data integrity and streamlines the import process.
Original PR description
### Issue: When importing EDI documents such as Peppol files, Swiss VAT numbers are often provided in a flat format (e.g., CHE530781296TVA), while existing Odoo partners usually store them in the…
### Issue: When importing EDI documents such as Peppol files, Swiss VAT numbers are often provided in a flat format (e.g., CHE530781296TVA), while existing Odoo partners usually store them in the official formatted version (e.g., CHE-530.781.296 TVA) This mismatch prevents proper partner matching and may create duplicate partners during import ### Cause: `_retrieve_partner` lacks Swiss-specific VAT normalization logic in `_import_retrieve_customer_from_vat()` As a result, the matching process fails to: - match formatted and unformatted Swiss VAT numbers - properly handle language suffixes such as `TVA`, `MWST`, or `IVA` If `base_vat` is installed, and the imported XML VAT is `CHE530781296TVA`, a new partner will be created with the structure format `CHE-530.781.296 TVA` As the match won't be made new partner will be created at each import ### Steps to reproduce: - Install `account` - Create a Vendor (Name: Test CH Vendor, Country: Switzerland, Tax ID: CHE-530.781.296 TVA) - Import the bill [CH_bill_to_import.xml](https://github.com/user-attachments/files/27202997/CH_bill_to_import.xml) from the ticket Before the fix, the existing partner is not matched and a duplicate partner is created opw-6072239
This update corrects a bug where certain quality control test types were incorrectly visible to users. The change ensures these test types are only accessible during manufacturing operations, aligning with the intended functionality. This prevents users from selecting inappropriate test types, improving data accuracy.
Original PR description
### Issue: The `Print Label`, `Register Production`, `Register By-products`and `Register Consumed Materials` are all available in the test types at control point creation. ### Expected behavior:…
### Issue:
The `Print Label`, `Register Production`, `Register By-products`and `Register Consumed Materials` are all available in the test types at control point creation.
### Expected behavior:
These test types are only meant for manufacturing operations and are supposed to be hidden by the field domain:
https://github.com/odoo/enterprise/blob/f56aa85b4ad32c5d9ad5593df1366d72e88da0e4/mrp_workorder/models/quality.py#L102-L104 https://github.com/odoo/enterprise/blob/00d6cccd75c402378698a6fd11ee2692f2361c7f/mrp_workorder/models/quality.py#L20-L24
### Cause of the issue:
Since saas-18.1: 5ef007a2116e528b796ebe80fb291ba5f1a94c8f domains are optimised into equivalents SQL clause with better sql performances. This optimization results in the following match for boolean fields:
`('field', '=', True)` -> `('field', 'in', OrderedSet([True]))`
`('field', '=', False)` -> `('field', ' not in', OrderedSet([True]))`
Because of these:
https://github.com/odoo/odoo/blob/82b16e8feb3d60a9a3855e3adb3164ae5a6c041d/odoo/orm/domains.py#L1058-L1079 https://github.com/odoo/odoo/blob/82b16e8feb3d60a9a3855e3adb3164ae5a6c041d/odoo/orm/domains.py#L1215-L1236
Now the issue is that the specific `search_method` of the `allow_registration` field is then called with this optimized domain: https://github.com/odoo/odoo/blob/82b16e8feb3d60a9a3855e3adb3164ae5a6c041d/odoo/orm/domains.py#L860-L866 https://github.com/odoo/enterprise/blob/00d6cccd75c402378698a6fd11ee2692f2361c7f/mrp_workorder/models/quality.py#L20-L24
And since `value` is defined as a non empty ordered set in both cases it the search method returns a True leaf as search domain.
opw-5915197This update fixes a technical problem caused by a recent change in Odoo's Python environment. Specifically, it resolved a circular import issue related to a new library, preventing errors during startup. The change also cleaned up an unused import statement.
Original PR description
In Python 3.14, the introduction of `annotationlib` changes the standard library's internal import graph. When `inspect` imports `annotationlib`, it subsequently imports `ast`. Odoo's custom module…
In Python 3.14, the introduction of `annotationlib` changes the standard library's internal import graph. When `inspect` imports `annotationlib`, it subsequently imports `ast`.
Odoo's custom module loader intercepts this `ast` import to execute `odoo._monkeypatches.ast`. Previously, this monkeypatch had a top-level `import logging`. Loading `logging` triggers an import chain (`traceback` -> `_colorize` -> `dataclasses`) that ultimately attempts to call `annotationlib.get_annotations`. Because `annotationlib` is still in the middle of its initial load, this attribute does not exist yet, resulting in an AttributeError.
This commit defers the `logging` import inside the `ast` monkeypatch to the local scope, breaking the circular import chain and allowing Python 3.14 to finish initializing its core modules properly.
Also it cleans up a blocking and unused `logging` import in `_monkeypatches/num2words.py`.
runbot-938481
<hr>
For information, the actual traceback:
```
'Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/data/src/odoo/odoo/api/__init__.py", line 4, in <module>
from odoo.orm.identifiers import NewId
File "/data/src/odoo/odoo/orm/__init__.py", line 20, in <module>
import odoo.init # noqa: F401
File "/data/src/odoo/odoo/init.py", line 23, in <module>
from .orm.utils import SUPERUSER_ID
File "/data/src/odoo/odoo/orm/utils.py", line 8, in <module>
from odoo.tools import SQL
File "/data/src/odoo/odoo/tools/__init__.py", line 7, in <module>
from .cache import ormcache, ormcache_context
File "/data/src/odoo/odoo/tools/cache.py", line 7, in <module>
from decorator import decorator
File "/usr/lib/python3/dist-packages/decorator.py", line 37, in <module>
import inspect
File "/usr/lib/python3.14/inspect.py", line 146, in <module>
from annotationlib import Format, ForwardRef
File "/usr/lib/python3.14/annotationlib.py", line 3, in <module>
import ast
File "<frozen importlib._bootstrap>", line 1371, in _find_and_load
File "<frozen importlib._bootstrap>", line 1342, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 938, in _load_unlocked
File "/data/src/odoo/odoo/_monkeypatches/__init__.py", line 46, in exec_module
hook()
File "/data/src/odoo/odoo/_monkeypatches/__init__.py", line 70, in patch_module
module = importlib.import_module(f\'.{name}\', __name__)
File "/usr/lib/python3.14/importlib/__init__.py", line 88, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "/data/src/odoo/odoo/_monkeypatches/ast.py", line 4, in <module>
import logging
File "/usr/lib/python3.14/logging/__init__.py", line 26, in <module>
import sys, os, time, io, re, traceback, warnings, weakref, collections.abc
File "/usr/lib/python3.14/traceback.py", line 12, in <module>
import _colorize
File "/usr/lib/python3.14/_colorize.py", line 157, in <module>
@dataclass(frozen=True, kw_only=True)
File "/usr/lib/python3.14/dataclasses.py", line 1432, in wrap
return _process_class(cls, init, repr, eq, order, unsafe_hash,
File "/usr/lib/python3.14/dataclasses.py", line 1041, in _process_class
cls_annotations = annotationlib.get_annotations(
AttributeError: partially initialized module \'annotationlib\' from \'/usr/lib/python3.14/annotationlib.py\' has no attribute \'get_annotations\' (most likely due to a circular import)
'
```This update corrects an issue where reducing the purchase order quantity after a partial receipt incorrectly increased the backorder quantity in multi-step receipt warehouses. The fix ensures that the backorder demand is calculated accurately based on the current quantity of moves, resolving a discrepancy in quantity calculations.
Original PR description
**Issue** Reducing the PO quantity after performing a partial receipt, in multi-step receipts warehouse can incorrectly update the remaining receipt quantity. **Steps to reproduce** - Setup 2-route…
**Issue** Reducing the PO quantity after performing a partial receipt, in multi-step receipts warehouse can incorrectly update the remaining receipt quantity. **Steps to reproduce** - Setup 2-route receipt warehouse (Inventory > Configuration > Warehouse Management > Warehouses) - Create a PO for 35 units and confirm it - Click on receive products, set received quantity to 10 and create a backorder - Validate the next transfer - Go back to the PO and change the quantity to 20 - Check the receipt demand -> The backorder picking demand become 35 instead of 10 **Cause** Updating the quantity of a purchase order line, also updates the related picking: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L120 It updates the picking associated to the backorder since the other one is done: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L185-L187 https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L197 This ultimately calls: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L228 To compute the new demand for the picking, it retrieves the `move_dest`: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L240 To compute `qty_to_push`: https://github.com/odoo/odoo/blob/5fc1e34d174f7f61d692d086d0ff65fbfc72b013/addons/purchase_stock/models/purchase_order_line.py#L247-L249 However, since we are in a 2-route receipt setup, `move_dest` is the move from Input to stock for the done picking. Thus, `qty_to_push` is `20 - 10 = 10` instead of `20 - 35 = -15` **Solution** The previous logic assumes a pull flow, where downstream (move_dest_ids) quantities are always up-to-date and can be used as the source of truth to recompute demand. In push flows (e.g., multi-step receipts), this assumption does not hold. To fix this, we instead base the computation on the quantity of the current moves (qty) if nothing has to be attached. **Additional information** Known limitation: this does not address inconsistencies in return flows. When there're returns, units define in the pol and the one define in the sum of the picking can diverge, thus this pr won't fix that. opw-5512172 Forward-Port-Of: odoo/odoo#263294 Forward-Port-Of: odoo/odoo#248626
This update resolves a problem where Odoo failed to authenticate certain foreign KSeF certificates, causing authentication errors. The fix automatically detects the correct identifier type for the certificates, ensuring seamless integration with the Polish tax authority's KSeF system. This improves the reliability of tax reporting for users in Poland.
Original PR description
### Description of the issue/feature this PR addresses: **Issue**: During KSeF authentication, some foreign qualified certificates causes a crash with error _"Failed to authenticate with XAdES: 400…
### Description of the issue/feature this PR addresses: **Issue**: During KSeF authentication, some foreign qualified certificates causes a crash with error _"Failed to authenticate with XAdES: 400 Client Error: Bad Request for url: https://api.ksef.mf.gov.pl/v2/auth/xades-signature"_ This is due to Odoo not handling different `SubjectIdentifierType` **Solution**: Implement a try/except block to safely check for the NIP in the certificate's subject string, defaulting the identifier type to `certificateFingerprint` when the NIP is missing or a ValueError is caught. ### Current behavior before PR: The `SubjectIdentifierType` is hardcoded as `certificateSubject`, and does not handle `certificateFingerprint` at all. This causes there to be an error when trying to authenticate with the KSeF server using XAdES signature. ### Desired behavior after PR is merged: The sign_authentication_challenge method will now safely evaluate the subject string. It assigns `certificateSubject` only if the NIP is verified to be in the subject string. If the NIP is absent or a ValueError occurs during parsing, the system safely falls back to using `certificateFingerprint`. This prevents tracebacks and ensures the correct XML payload is sent to the KSeF server. opw-6125243 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#265390