Monday, November 10, 2025
6 changes · saas-18.2
Enhancements to existing features
This update introduces a clearer way for Odoo’s automated tests to find exact text matches on screen. It is an internal improvement that makes test scripts easier to read and maintain, helping reduce future development friction without changing user-facing behavior.
Original PR description
This commit adds the ':text()' pseudo-class to the list of supported pseudo-classes in Hoot selectors. Its purpose is the same as ':contains()', with the specificity of being an *exact* match instead of a *partial* one. It effectively replaces ':contains(/^<expression>$/)' by ':text(<expression>)', improving the readability and making the developer experience a bit nicer. Enterprise: https://github.com/odoo/enterprise/pull/98772 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#234331
Resolved issues and error corrections
The update prevents an error when Odoo saves a default setting and duplicate matching default records already exist. This improves reliability for configuration changes by allowing the system to proceed instead of crashing.
Original PR description
There’s no constraint preventing duplicate `ir.default` records. When setting a default using `self.env['ir.default'].set()`, it searches for an existing one, but if more than one match is found,…
There’s no constraint preventing duplicate `ir.default` records. When setting a default using `self.env['ir.default'].set()`, it searches for an existing one, but if more than one match is found, accessing `default.json_value` raises a singleton error.
This fix makes sure the search only picks one record, avoiding that crash.
Before fix:
```py
self: res.users(1,)
>>> company = self.company_id
>>> company
res.company(1,)
>>> self.env['ir.default'].create({'field_id': 4540, 'company_id': company.id, 'json_value': 7})
ir.default(9,)
>>> self.env['ir.default'].set('res.partner', 'property_account_receivable_id', 7, company_id=company.id)
Traceback (most recent call last):
File "/home/odoo/odoo/odoo/odoo/orm/models.py", line 5630, in ensure_one
_id, = self._ids
^^^^
ValueError: too many values to unpack (expected 1)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/odoo/odoo/odoo/odoo/addons/base/models/ir_default.py", line 107, in set
if default.json_value != json_value:
^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/odoo/odoo/orm/fields.py", line 1670, in __get__
record.ensure_one()
File "/home/odoo/odoo/odoo/odoo/orm/models.py", line 5633, in ensure_one
raise ValueError("Expected singleton: %s" % self)
ValueError: Expected singleton: ir.default(4, 9)
```
After fix:
```py
self: res.users(1,)
>>> company = self.company_id
>>> company
res.company(1,)
>>> self.env['ir.default'].create({'field_id': 4540, 'company_id': company.id, 'json_value': 7})
ir.default(10,)
>>> self.env['ir.default'].set('res.partner', 'property_account_receivable_id', 7, company_id=company.id)
True
```
opw-5228419
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#234944
Forward-Port-Of: odoo/odoo#234893Code cleanup and technical improvements
The update replaces older text-matching selectors with a newer, more precise option in the affected test code. This helps keep automated tests reliable and easier to maintain without changing business functionality.
Original PR description
This commit replaces all found occurrences where ':contains' (with an exact match regular expression) could be replaced by ':text'. Community: https://github.com/odoo/odoo/pull/234331 Forward-Port-Of: odoo/enterprise#98772
Product price data used by search engines now follows the website's tax display setting. This prevents a mismatch where customers saw tax-included prices on product pages while structured product data still showed tax-excluded prices.
Original PR description
## Version
18.2+
SEO Schema refactoring from task-3866937
## Issue
The markup always contains the price without taxes, no matter the website settings for pricing display (with or without taxes).
## Steps to reproduce
- Go to Website settings:
- Choose "Taxes Included" for "Display Product Prices".
- Got to the shop and select any product on which taxes apply (e.g. Customizable Desk):
- Open console and execute `JSON.parse(document.querySelectorAll('[type="application/ld+json"]')[1].innerHTML)[0]['hasVariant'][0]['offers']['price']`;
- The found price and the displayed price (visible on the page) are different
## Fix
Allow tax inclusion based on parameter to mimic template's behavior on variants too depending on the website.
https://github.com/odoo/odoo/blob/52a6d88a188d5456262428847aed229f117da8ed/addons/website_sale/models/product_template.py#L377-L430
opw-4923780This fix prevents duplicate Argentina withholding tax records from being created when demo data is installed. It keeps tax configuration lists cleaner and avoids confusion for users testing or setting up Argentinian withholding flows.
Original PR description
**Description of the issue/feature this PR addresses**: This pr is to avoid duplicated taxes when the demo data is installed. **Steps to reproduce**: 1. Install l10n_ar_withholding module with demo…
**Description of the issue/feature this PR addresses**: This pr is to avoid duplicated taxes when the demo data is installed. **Steps to reproduce**: 1. Install l10n_ar_withholding module with demo data. 2. Take position in "(AR) Responsable Inscripto" company. 3. Check the taxes created on "Invoicing > Configuration > Accounting > Taxes". 4. Delete the filter "Sale or Purchase". 5. Add custom filter: Argentina Withholding Payment Tax type (l10n_ar_withholding_payment_type) is in ["supplier", "customer"]. 6. You will see that there are duplicated taxes (duplicated names) with suffix (Copy). **Current behavior before PR**: Duplicated taxes are created when demo data is installed. <img width="1597" height="795" alt="image" src="https://github.com/user-attachments/assets/51b65037-bb89-4ec7-8adf-21636b68e405" /> **Desired behavior after PR is merged**: No duplicated taxes are created when demo data is installed. _Task latam side_: 1360. _Task Adhoc side_: 57627. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#226992
When a pivot table is sorted by a date or date-time field in the web view, inserting it into a spreadsheet now keeps the same sort order. This fixes an issue where the date values were not normalized correctly, which could make the spreadsheet version appear unsorted.
Original PR description
If on the web pivot view we create a pivot with a date/dateTime field in the columns, and sort on one of these columns, the resulting pivot when inserted in a spreadsheet isn't sorted. This was because we didn't normalize the date values in the pivot `sortedColumn`, and we had UTC timestamps `2023-01-01 00:00:00` instead of normalized values `01/2023`. Task: [3575465](https://www.odoo.com/web#id=3575465&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form)