Daily updates from Odoo
Wednesday, August 27, 2025
16 changes · 18.0
Enhancements to existing features
This change avoids extra processing when new records include HTML or rich text fields, reducing duplicate cleanup work. It should noticeably speed up bulk operations such as marketing email campaigns and lower memory usage during long-running batch jobs, with minimal impact unless the same rich text is read immediately after creation.
Original PR description
Description ----------- When creating records with `vals` for HTML fields, there are two 'sanitization' operations happening: 1) Once in `convert_to_column`, when converting the `vals` for *database*…
Description ----------- When creating records with `vals` for HTML fields, there are two 'sanitization' operations happening: 1) Once in `convert_to_column`, when converting the `vals` for *database* insertion 2) Once post-insert in `convert_to_cache`, when converting the `vals` for insertion in the *cache* for the newly created records. This redundancy has a negative performance impact when creating many records where new HTML fields are set, e.g., mass-mailing, as potentially large HTML documents are parsed and validated, often with external libraries. To address this issue, this commit removes the insertion into *cache* of the HTML values for the newly created records. This removes the overhead of the second sanitization, speeding up the creation, and also helps with overall memory pressure, as we're not inserting large HTML fields into cache. The latter is particularly noticeable for long-running batch creation processes that do *not* commit intermediate results. The downside of this patch is the potential *cache-miss* (and therefore the subsequent *query*) if the HTML field of the newly created records is read. This is unlikely in business code because intrinsically, an HTML field is often just a data 'blob' that has no logical usage. In the rare case where it needs to be read after creation, since the value in the database is already sanitized, re-sanitization is not necessary for insertion in the cache. Given these considerations, the trade-off seems reasonable to make. Benchmark --------- In a scenario for a marketing campaign with 1000 recipients, using a *mid-sized* email template and emulating a typical campaign, the results were: | Method | Before | After | Speed up | |-------------------------------|----------|-----------|----------| | `_process_mass_mailing_queue` | 2.84 min | 1.55 min | 1.8x | | `create` | 2.11 min | 50.23 sec | 2.5x | This represents roughly a *2x* performance improvement in processing an email campaign. * more detailed benchmarks are available in the task's description Reference --------- task-4962646 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update improves Romanian electronic stock document handling in Odoo. It is intended to make localization workflows more reliable for businesses operating in Romania, although the provided PR details do not specify the exact user-facing behavior changed.
Original PR description
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
Pricer labels now receive additional product details such as pre-tax prices, tax names, supplier references, supplier product codes, and units of measure. Updates to related supplier or tax information will also refresh affected Pricer tags, helping keep shelf labels accurate with less manual intervention.
Original PR description
We are currently missing some fields which must be sent to Pricer for some basic use-case scenarios This PR adds - Price before taxes - Taxes name (ex: 21%) - Supplier product code - Supplier reference - Units of measure of the product The PR also triggers the update of the pricer tags when the models indirectly related to Pricer are modified (taxes name / supplier reference / supplier product code) + cleans up the code a bit task-4506260
Resolved issues and error corrections
Manufacturing orders created from sales for products with an empty bill of materials now stay in draft instead of being automatically confirmed. This prevents users from ending up with confirmed orders that have nothing to produce or track, giving them time to add any needed details first.
Original PR description
Issue Before This Commit: ============================ Currently, if a BOM has `no components or operations` and is triggered via `MTSO`, the generated Manufacturing Order (MO) is automatically set to a `confirmed` state. This behaviour is inconsistent and not meaningful, as there's nothing to produce or track. Steps to Reproduce: ============================ - Install the `mrp and sale` module. - Enable MTSO route. - Create a product with a BOM that has `no components or operations`. - Create a sale order for that product. MO is created in a `confirmed` state. With This Commit: ============================ This commit ensures that MOs triggered via `MTO(Already worked) or MTSO` are created in draft state if their BOM has no components and no operations. This allows the user to manually add required details before confirming the MO. supporting custom use cases. TaskID:- 4920195
Fixes form save warnings so they can open the intended follow-up action with the correct extra information. This helps users resolve save-blocking issues directly from the warning instead of being left in a broken or incomplete flow.
Original PR description
Have a web_save that raises a RedirectWarning which has the ID of an action and an additional context in its parameters. Trigger the warning in the form view by clicking on the save button in the form view. Before this commit, this feature did not work like at all. - The additional context was not taken into account - the path taken by clicking on the form's save button was not able to handle interacting with the main form view - The error dialog did not handle going into an action in target other than new After this commit, all this is fixed and the whole flow, that allow an error to be enriched such that the user could do the correct action to correct the error now works. opw-4742952 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#223198
Fixed an issue in Point of Sale restaurants where combo items could lose their link to the main combo product after table synchronization. This helps ensure orders remain accurate and easier for staff to manage when customers or order details are updated.
Original PR description
When one of the combo line is marked as "Dirty", it would be synched but it would remove it's link to the combo parent. Steps to reproduce: ------------------- * Create a combo product * Open a PoS restaurant * Open a table, and add the combo product * Leave the table to synchronize the order with the backend * Go back on the table and select a partner * This will mark the combo line as "dirty" * Leave the table again to synchronize the order with the backend * Go back on the table > Observation: The combo now appears as a normal product, not linked to the combo parent. Why the fix: ------------ When marking a line as "dirty", we now make sure to also mark it's combo parent as "dirty" so that it will be synchronized correctly. And keep the link to the combo parent. opw-4950262
Fixes an error that could interrupt users editing a sales order when multiple linked invoices are shown on the form. This makes the sales order editing experience more reliable for customers using Studio customizations with invoice information.
Original PR description
**Step to reproduce** - create a SO - link 2+ invoices to it - using studio, add invoice_ids to the SO Form - trigger a onchange (ex. change the product from SOL) - we receive a traceback…
**Step to reproduce** - create a SO - link 2+ invoices to it - using studio, add invoice_ids to the SO Form - trigger a onchange (ex. change the product from SOL) - we receive a traceback **Traceback:** ```ValueError: Expected singleton: account.move(<NewId origin=35>, <NewId origin=31>, <NewId origin=32>, <NewId origin=33>, <NewId origin=34>)``` **Issue:** - from `onchange` triggers chain,`_compute_duplicated_ref_ids` is invoked calling `_fetch_duplicate_reference` for the related moves (invoice_ids) such that as they are in create/edit mode - at this time `convert_to_write(moves[field_name], moves)` fails as moves has more than 1 record and `recordset[field]` is not valid syntax in such case https://github.com/odoo/odoo/blob/3966753eb5a8534c8b5b8a16e626f5250c9013cf/addons/account/models/account_move.py#L1868-L1884 - hence, we receive valueError, expecting a singleton **Fix;** - we adapt the method to accept multiple moves which may be in create/edit mode opw-4959528 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where older point-of-sale refunds that combined items from multiple original orders could fail after upgrading. Businesses can now view those refund orders and complete upgrades without this data compatibility error blocking the process.
Original PR description
In saas~17.1, the field `refunded_order_id` was changed from a Many2Many to a Many2One, as refunding lines from different orders with the same order was no longer possible. The problem is that there were no changes applied to the existing data to account for this, so databases with those kind of refunds will trigger an error when the field is computed: ``` ValueError: Wrong value for pos.order.refunded_order_id ``` This behaviour can also break upgrades if the error happens during the mock crawl test after the upgrade. To reproduce: - In 17, create an order refunding products from different orders. - Upgrade to 18. - Try to view the refunding order. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Submitting a website “Send Email” form without a recipient email now avoids an error that previously blocked the form. This makes website forms more reliable for users configuring email actions through the website editor.
Original PR description
Currently, an error occurs when submitting the 'Send Email' form. **Steps to Reproduce:** - Install the `website` and `web_studio` modules. - Go to `website` > Click on `Edit` > `Drag and drop form`.…
Currently, an error occurs when submitting the 'Send Email' form. **Steps to Reproduce:** - Install the `website` and `web_studio` modules. - Go to `website` > Click on `Edit` > `Drag and drop form`. - Click the `form` and in `Actions` select the `more models`, and select `outgoing mails(mail.mail)` model and `save`. - Fill out the form and `Submit`. **Error:** `KeyError: 'website_form_signature'` **Cause:** This error occurs after [this commit](https://github.com/odoo/odoo/commit/70fa5af872524ea271113851c050297ef50efa45), when submitting the "Send Email" form from the website. If the form is saved without entering the recipient's email (email_to). As a result, the `email_to` field is not present in the form. The `website_form_signature` is added from [1], but due to the condition at [2], the code at [1] is not executed. And when it is accessed at [3], KeyError is raised. [1]: https://github.com/odoo/odoo/blob/82639728f2bcb4e7786f120de2aeba3f5fbab209/addons/website/tools.py#L252 [2]: https://github.com/odoo/odoo/blob/82639728f2bcb4e7786f120de2aeba3f5fbab209/addons/website/tools.py#L236 [3]: https://github.com/odoo/odoo/blob/82639728f2bcb4e7786f120de2aeba3f5fbab209/addons/website/controllers/form.py#L88 **Fix:** This commit ensures that 'website_form_signature' is used if it is available in kwargs. sentry-6746753251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The debug Data view no longer crashes when a record includes custom property fields. This helps administrators and support teams inspect record information reliably during troubleshooting, including in CRM forms with added property fields.
Original PR description
Example Steps: - Install `crm` - Add a random field properties in a random form view - Enable debug mode - Open debug menu - Select Data - Traceback ```py raise ValueError(f"Invalid field…
Example Steps:
- Install `crm`
- Add a random field properties in a random form view
- Enable debug mode
- Open debug menu
- Select Data
- Traceback
```py
raise ValueError(f"Invalid field {field_name!r} on model {self._name!r}")
ValueError: Invalid field 'properties.xyz' on model 'x.y'
```
There are two causes for this problem.
First, we use orm.read to retrieve data from records, which does not directly handle sub-field properties. We only need to use `definition_property` (which contains the overall schema of the JSON field).
Second, when displaying the data, we use JSON.stringify with `replacer`:
```js
get content() {
const record = this.props.record;
return JSON.stringify(record, Object.keys(record).sort(), 2);
}
```
In this case, replace contains all the keys present in record, sorted. The problem is that the properties fields are themselves objects that contain the keys: `name`, `string`, `type`, `default`, `value`.
And giving an array to replace in `JSON.stringify` will filter the keys and keep only those that are whitelisted in it.
```js
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
const foo = {
foundation: “Mozilla”,
model: “box”,
week: 45,
transport: “car”,
month: 7,
};
JSON.stringify(foo, [“week”, “month”]);
// ‘{“week”:45,“month”:7}’, only keep ‘week’ and “month” properties
```
This will ignore the keys of the properties fields.
The fix is therefore to sort the object before stringifying it, without using replace.
Thanks to these two fixes, the data is displayed as expected, regardless of whether there are field properties or not.
opw-5017425This fix prevents errors and unwanted visual effects when website blocks use both gradient and image backgrounds. Users can now switch image display modes such as repeat pattern or parallax without causing console errors or making gradients repeat incorrectly.
Original PR description
*=website Target: 17.0 to saas-18.3 Issue: This issue applies to any block where multiple backgrounds are present (gradient + image). Steps to Reproduce: 1. Drop a masonry snippet onto the page. 2.…
*=website Target: 17.0 to saas-18.3 Issue: This issue applies to any block where multiple backgrounds are present (gradient + image). Steps to Reproduce: 1. Drop a masonry snippet onto the page. 2. Select a block and change the background color to the gradient. 3. Add background image. 3. Change the image position from "Cover" to "Repeat Pattern." 4. Observe the traceback in the console. Reason: The issue occurred due to incorrect parsing of CSS background values when multiple background layers were applied (e.g., a gradient + image). When both are set, the element ends up with multiple background-related properties. Previously, In setValue method, Inside MultiUserValueWidget when value = "100px, 100px", the resulting values array was ['100px,', '100px'], which included an extra comma. This has now been corrected to properly handle such cases. Other edge cases fixed: 1. Gradient was repeating along with the image. 2. Switching to parallax after repeat-pattern causes gradient to repeat. 3. Removing image kept repeat class, causing gradient to repeat. Fix Summary: 1. We updated `selectStyle` and _computeWidgetState to correctly handle multi-layer background-size and repeat styles. In selectStyle, we set the height and width values from options and apply them only to the image layer (not gradient), keeping the gradient layer unchanged. In `_computeWidgetState`, we fetch the background-size from the target and, if multiple layers are present, return only the first one (image layer), since height and width options apply only to that. Now, setValue receives only single-layer values like `100px 50px`, ensuring correct behavior. Set background-size 'cover' to gradient which ensures only the image repeats while the gradient remains fixed. 2. Remove `o_bg_img_opt_repeat` and reset background-size when - Image is removed. - Switching to parallax. task-4577864 Forward-Port-Of: odoo/odoo#207757
Stopping a timesheet timer now uses the user's local date instead of UTC when matching entries. This prevents time from being added to the previous or next day for users working across time zones.
Original PR description
Before this commit, if you were to log time on a timesheet using the timer start and stop buttons, you could potentially log time for the previous day's or the upcoming day's timesheet entry. This is because we were searching for previously-created timesheet entries based on the UTC Date of the timer's "stop" time. This fix uses the client's local time to get the Date of the timer stop. With this, we'll only find timesheet entries with the `date` field matching the client's local Date. opw-4967487 Forward-Port-Of: odoo/enterprise#93010 Forward-Port-Of: odoo/enterprise#92569
Planning notification emails now send portal users to the correct planning page instead of the general portal dashboard. This helps external users access their published shifts directly from email without confusion or extra navigation.
Original PR description
### Steps to reproduce: - Install Planning app - Create a portal user and an employee for this user - Create a shift for this user and Publish it - Go to the email that has been sent and click on…
### Steps to reproduce: - Install Planning app - Create a portal user and an employee for this user - Create a shift for this user and Publish it - Go to the email that has been sent and click on View Your planning - Notice you are redirected to the portal dashboard home ### Cause: Since this commit diff we removed the check if the user is having planning group https://github.com/odoo-dev/enterprise/commit/72afe1e14703f0a3eafd0cfaec10c67462db73ce#diff-293bc9f44292d19793981abbafbe2a55642d170bda5e3bf17d7654f7bffcbedaL62-L64 When getting the planning url that will be share in the email we don't check if the user is portal or not so we set the url with /odoo path and if a portal user is accessing a /odoo path it will redirect him to /my https://github.com/odoo/odoo/blob/1acf4b2ce2bdad27e7d32d1227698968148a5935/addons/portal/controllers/web.py#L25-L26 ### Fix: We check if the user is portal we set the url with /planning path which will redirect the portal user to the correct planning view opw-5045746
Rental orders settled through Point of Sale now keep the delivered quantity accurate when items are returned. This prevents returned rental products from being counted as delivered more than once, improving order accuracy and reducing manual corrections.
Original PR description
**Issue:** Before this commit, the qty_delivered was wrong when using the Return button when a Picking was made in PoS **Cause:** The `_compute_qty_delivered` method in `pos_sale` adds `pos_line.qty`…
**Issue:** Before this commit, the qty_delivered was wrong when using the Return button when a Picking was made in PoS **Cause:** The `_compute_qty_delivered` method in `pos_sale` adds `pos_line.qty` to the related `sale_line` each time it runs When there is no PoS order, the method add 0 to the line, so the expected behavior work But when you have a PoS Picking, a quantity was added to `qty_delivered` each time the `rental.order.wizard` is used The issue also occured earlier when the `flush_all()` is called in `_process_order()` **Fix:** There is already a `_compute_qty_delivered` method in `pos_sale_stock_renting` that override the `qty_delivered` But it's restricted by `_are_rental_pickings_enabled()` That's not necessary because we don't use any `stock.picking` in the `_compute_qty_delivered` function, only `stock.move` so we removed that verification To make the code working, we also need to extend the _get_outgoing_incoming_moves() results Because there were also block by a `_are_rental_pickings_enabled()` condition even if there is only moves here We need all the moves to calculate `qty_delivered` properly **Steps to reproduce:** - Create a New Product "Rental PoS" that Can be Rented - Create and confirm a New Rental Order, with any customer and your product - Open a PoS Session - Click on Quotation/Order - Choose the last Order and Settle the order - Click on Yes (to confirm import to PoS) - Click on Payment, select Cash and Pay - Go in the Backend, and to your RO - Click Return and Validate - Before the fix, the Delivered should be 2.0 opw-4877019 Forward-Port-Of: odoo/enterprise#90510
Refreshing a document that was sent for signature no longer causes an error. The signing page now keeps the needed document state in the URL so users can reload the page without losing access or interrupting their workflow.
Original PR description
Version: - 18.0 Steps to reproduce: - Open document which is send for signature. - Refresh the browser. Before: - Refreshing the page caused a traceback error. - The requestItemStates value was loaded from the context, which is only available when navigating from go_to_document. - On refresh, the context was lost, leading to the error. After: - Added requestItemStates to the URL query string. - On page refresh, the data is retrieved from the URL as a fallback instead of relying on the context. Impact: - Fixes the error that occurred on page refresh. - Ensures a smoother and more stable user experience when viewing documents. task-4805166
Brazilian invoices using Avalara no longer add exempt ICMS taxes as extra journal item amounts when Avalara marks them as not accounting-relevant. This prevents invoice totals from being overstated while still keeping a visible record of the ignored tax in the invoice chatter.
Original PR description
### Steps to reproduce:
- Install l10n_br_edi, switch to Brazilian company
- Set up Avalara
- Create an invoice with the tax "ICMS Exemption Incl." which is included in price
- Click "Generate taxes" to compute the taxes with Avalara
- In "Journal Items" we can see a line for "ICMS Exemption Incl.", its value appear as excluded
### Cause:
The result from Avalara included a value for this tax:
```
'tax': 1.44,
'taxImpact': {
'accounting': 'none',
'impactOnFinalPrice': 'Included',
'impactOnNetAmount': 'Included',
},
```
But the untaxed amount is computed without this tax. Odoo keeps the untaxed amount from the response and add a line for the tax. As a result the tax is added to the amounts like an excluded tax would.
### Solution:
In the response from Avalara, we don't want to create a line for the tax `icmsDeson` when there is `'accounting': 'none'`.
We also log this tax in the chatter to keep a trace of it.
opw-4964315