Wednesday, September 3, 2025
18 changes · saas-18.4
Enhancements to existing features
Creating records with HTML content now avoids repeating an expensive cleanup step, which can significantly speed up batch operations such as mass mailing. This also reduces memory use during long-running processes, with a small trade-off that reading the same HTML immediately after creation may require an extra database lookup.
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 Forward-Port-Of: odoo/odoo#224794 Forward-Port-Of: odoo/odoo#223875
The IoT app now includes a test button for the fiscal data module, allowing users to check the blackbox status and see the result immediately in a notification. This helps businesses verify fiscal device connectivity more easily and reduces false connection failures by allowing a slightly longer response time.
Original PR description
This PR adds a "test" button for the fiscal data module in the IoT app. When used it will send a status request to the blackbox and display the result in a notification. It also removes "response_size" supposed to specify how many characters to read in blackbox response which was unused since this PR: https://github.com/odoo/enterprise/pull/87988 task-5055029
Financial reports grouped by account code now also show the matching account name for the current company. This makes consolidated reporting easier to read when multiple accounts from another company are mapped to the same account code.
Original PR description
In the current consolidation, you can make multi-company accounts and assign a code for each company. But a code must be unique inside each company. So it is not designed to map multiple accounts from a second company into one account of a first company. It is actually possible to achieve that effect by not making the accounts of the second company belong to the first company, and still make the code mapping. So you can make several accounts from the second company, map to the same code for the first company. Thus grouping by account codes become interesting for the accounting reports, in order to get a view of that consolidation. In order to make this reporting more clear, the name of the account corresponding to the account code (in the current company) is now shown when grouping by account code. task-4801891 Forward-Port-Of: odoo/enterprise#86403
Resolved issues and error corrections
This fix prevents subcontracting manufacturing orders from being fully cancelled when a receipt quantity is reduced to zero. Keeping one open order lets users adjust the receipt later without getting stuck or needing manual recovery.
Original PR description
Steps to reproduce:
- Unarchive subcontracting operation type
- Create a storable product P1 with a BoM:
- BoM type: Subcontracting
- Subcontractor: Azure Interior
- Component C1 (route: Resupply Subcontractor on Order)
- Create a purchase order:
- Vendor: Azure Interior
- 10 units of P1
- Confirm the PO → 2 pickings are created:
- Resupply of 10 units of C1
- Receipt of 10 units of P1
- Confirm and validate the resupply of C1
- Components are reserved in the subcontracting MO
- Validate the consumption of 10 units in the receipt
- The MO is updated to 10
- Update the quantity of P1 to 0 in the receipt
Issue:
The manufacturing order is cancelled. As a result, subsequent updates on the receipt cannot recreate MOs.
Fix:
When reducing the receipt quantity, cancel only the extra MOs, but always keep at least one open MO if a subcontracting move is still ongoing.
opw-4792379
Forward-Port-Of: odoo/odoo#223858Unbuild operations no longer force costs to match the original manufacturing order when product costs have changed. Any difference is now handled with a corrective accounting entry, keeping inventory valuation and average costs accurate for manufacturers.
Original PR description
**Current behavior:** Since https://github.com/odoo/odoo/commit/84dda968146d2f3743ab7fc516300e50780725e3, we valuate an unbuild operation by attempting to match the ensuing OUT layer with the IN…
**Current behavior:** Since https://github.com/odoo/odoo/commit/84dda968146d2f3743ab7fc516300e50780725e3, we valuate an unbuild operation by attempting to match the ensuing OUT layer with the IN layer from the original MO. The point being to eliminate a potential valuation imbalance for the manufactured product (might affect cost, etc.). **New behavior** Don't attempt to match an unbuild valuation layer with the original MO valuation layer. If there is some cost difference between build time and unbuild time, make a corrective journal entry for it. **Issue with current behavior** The following sequence: 1. Create Product A with average costing, real-time valuation 2. Create 2 components, avg costing, real-time val 3. Create a BoM for Product A with the components 4. Manufacture 3 units of Product A with different component quantities (can set flexible consumption on BoM) 5. Unbuild the first manufactured unit Results in Product A's cost not matching the expected average cost according to the valuation layers. **Cause of the issue:** Unbuilding the first MO created an out move at the original "build time" cost, but since we've built 2 additional qty, that original cost is not the current average cost- thus the "theoretically current" standard price of the product (sum of layers value divided by remaining qty) is no longer the value we see on the product form. **Fix:** Don't try and match the valuation layers. Aside from issues such as the one described above, it might not actually make functional sense to do so (e.g., FIFO isn't actually adhering to first-in-first-out if we're preferring the original IN layer for an unbuild valuation). Instead we make a journal entry with any excess cost of production (it was actually a solution proposed in the discussion on https://github.com/odoo/odoo/commit/84dda968146d2f3743ab7fc516300e50780725e3 in the first place). Additionally, now that we aren't doing this mapping, we can revert the non-test difference of https://github.com/odoo/odoo/commit/3a69456a291da593748475c86e7efc6234019e47, as this commit was fixing an issue introduced by the change which added the mapping. opw-[4877597](https://www.odoo.com/web#id=4877597&view_type=form&model=project.task) Forward-Port-Of: odoo/odoo#222014 Forward-Port-Of: odoo/odoo#221718
This fixes an issue where changes typed into a form could be overwritten when background loading finished. Users can now start editing cached forms immediately without losing their input, while unchanged fields still refresh with the latest data.
Original PR description
Before this commit, when opening an already cached form view (i.e. creating or opening a record) would display the cached information. If a user changed a field before the RPC returned, these changes would be lost as the form view would update with the data from the RPC result. Now, the changes made by the user are kept when the RPC returns and only the non-changed fields are updated.
This fix ensures analytic plan hierarchies are processed in the correct order when installing the Project app. It prevents installation failures for customers who have parent and child analytic plans already configured.
Original PR description
When installing the `project` module, `_sync_plan_column(self, model)` is called for all existing analytic plans. The method iterates through `self` in arbitrary order, which means a child plan can…
When installing the `project` module, `_sync_plan_column(self, model)` is called for all existing analytic plans. The method iterates through `self` in arbitrary order, which means a child plan can be processed before its parent. In such a case, the code tries to create a related field pointing to a parent-level column that does not yet exist, leading to errors like: `Field name "x_plan26_id" unknown for related field "x_plan26_id.plan_id"` This happened because `self` was iterated without guaranteeing that parents are processed first. As a result, the related field chain (`.plan_id.parent_id...`) could reference missing intermediate fields. The fix is ordering the recordset by `parent_path`. Steps to reproduce: 1. In Odoo Inspector, search for model `account.analytic.plan`. and go to records. 2. Create a first plan. 3. Create a second plan and set the first plan as its parent. 4. Install the `project` app (triggers `_sync_plan_column`). 5. Observe the crash due to an unknown related field. OPW-5006494 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#224509
Italian electronic invoice exports now omit payment details where they should not appear for self-billing documents. Supplier invoice references are also placed in the correct linked-invoice fields, helping businesses stay aligned with Italian tax authority requirements and avoid rejected or incorrect submissions.
Original PR description
1- `<DatiPagamento>` shouldn't be included in autofatture. 2- The supplier's original invoice number and date must be placed in the `<DatiFattureCollegate>`, using `<IdDocumento>` and `<DataDocumento>` fields respectively. Currently `<IdDocumento>` is added to the `<DatiOrdineAcquisto>`. A fix is made to add `<IdDocumento>` and `<DataDocumento>` to `<DatiFattureCollegate>`. references: https://www.agenziaentrate.gov.it/portale/documents/d/guest/guida_compilazione-fe-esterometro-v1-10_aprile_2025 opw-4810326 Forward-Port-Of: odoo/odoo#212989
Fixed an issue where vendor bills created from consolidated inter-company invoices were not connected to the matching purchase orders. This helps users keep bills and purchase records aligned when multiple sales orders are combined into one invoice.
Original PR description
## Issue: In a multi-company setup with Inter-Company Transactions set to Sales Orders and Purchase Orders, after creating two Sales Orders from one company to the other, then generate a Consolidated…
## Issue: In a multi-company setup with Inter-Company Transactions set to Sales Orders and Purchase Orders, after creating two Sales Orders from one company to the other, then generate a Consolidated Invoice for both SO, and import it as Vendor Bill in the client Company, the bill isn't linked to the matching Purchase Order ## Cause: The `invoice_origin` is used to get the references, but it doesn't split causing the purchase's name to search in `_match_purchase_orders()` to be ["P00001, P00002"] instead of ["P00001", "P00002"] https://github.com/odoo/odoo/blob/2718aaa7397e38be0fcd64fe6b5ef5c0be66cfe2/addons/purchase/models/account_invoice.py#L373-L374 ## Steps to reproduce: - Enable Inter-Company Transactions for Sales Orders and Purchase Orders in two Companies - Create and Confirm two Sales Orders from one company to the other one - Create a Consolidated Bill for both S0 - Send the Invoice (Download) - Switch to the second Company - In Purchase, Confirm both RFQ - In Accounting > Vendor > Bills, Upload the downloaded bill - The Smart Button isn't linked to the PO Ticket [link](https://www.odoo.com/odoo/project/967/tasks/4690707) opw-4690707 Forward-Port-Of: odoo/odoo#223398
This fixes a crash that could happen when users grouped records by date or date-time custom properties, opened a group, and navigated back. Grouped list views now reopen reliably when date-based properties are involved, improving stability for users working with custom fields.
Original PR description
Steps: - Install a random module with properties (example: crm) - Add a properties to the form view (date or datetime) - Set the field to today - Make sure you have another record with the new properties field unset - Go to list view - Group by -> properties -> year - Open a group which is not False - Via the breadcrumb navigate back to the list view - Traceback When opening_info is set to unfold with datetime properties, web_read_group returns no records, which crashes the web client. To resolve this, we modify the `formatter_property_datetime` to return the date(time) object as a string. This should match the behavior of normal date(time) fields, ensuring the `_open_groups` algorithm can correctly identify and match the appropriate group(s). opw-5016891 Co-authored-by: @ryv-odoo
Corrects the positioning of table menu controls when editing PDF Quote reports in Studio. This prevents the menu button from appearing over the wrong table cell after report layout options are shown or hidden, making report editing more reliable.
Original PR description
Problem: Open "PDF Quote" report in Studio and observe when hovering on the first table cell: the table menu button is always on top of the first cell (with a small offset difference). Cause: In…
Problem: Open "PDF Quote" report in Studio and observe when hovering on the first table cell: the table menu button is always on top of the first cell (with a small offset difference). Cause: In `OverlayPlugin` we get the container on which we later calculate the overlay position during setup. `QWebPlugin` may show/hide elements in reports (CSS `display` controlled by attributes like `data-oe-t-group-active`). The issue: Before commit https://github.com/odoo/odoo/commit/27a85d650dee8345a4ec701bf7456eec07851718 we used to find the scrollable starting from the `iframe`. This always returned the same scrollable outside the `iframe`, even when its content was scrollable. Now, since `QWebPlugin.applyGroupQwebBranching` can change the `iframe` content, the scrollable may differ. Solution: `getScrollContainer` should check the scrollable starting from the `iframe` before `this.editable`. Steps to reproduce: 1. Open "PDF Quote" report in Studio. 2. Hover on the table headers. 3. Observe the menu button is always positioned on top of the first cell. opw-5046779 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix prevents missing website link values from being turned into empty links when a CDN is active. It avoids a checkout address page issue where submitting the form could trigger an unwanted refresh and disrupt the order flow.
Original PR description
In QWeb, when using `t-att-href='None'`, the attribute is omitted from the DOM. However, when a CDN is used, `None` is converted to an empty string (`''`) by `get_cdn_url`. This is a follow-up to commit 3e9c953. This fix addresses an issue on the `/shop/address` page where the "Submit" button had `href=''`, causing JavaScript event handling to break due to a race condition triggered by a page refresh during form submission (POST). Forward-Port-Of: odoo/odoo#223252 Forward-Port-Of: odoo/odoo#220166
This fixes a website theme issue where duplicate color palette names could prevent the Theme tab from appearing in the editor. Users can now edit themes such as Anelusia even when a theme reuses a palette name already present in the website module.
Original PR description
This fix prevents duplicate palette names in `t-foreach` by using an object to store palettes by name, which otherwise made theme editing impossible. Steps to reproduce: - Create a website with theme "Anelusia" - Try to change the theme in the editor - The "Theme" tab will not appear This issue occurs because the Anelusia theme from Design-Themes introduces a palette named "default-25", which is already defined in the website module. The same conflict can also arise with other themes. opw-5020952 opw-5040694
This fix restores support for custom rules that let certain users edit only specific website pages, which is important for Odoo.com publishing workflows. A previous change caused those partial editing permissions to stop working in some cases, so the logic was rolled back while the related test is kept disabled for future follow-up.
Original PR description
*: test_website This reverts commit [1]. Indeed, while it fixed the bug as intended while keeping the `_check_user_can_modify` feature, it apparently did not keep that one working in all cases: having partial view edition rights for some website.page (see uses in our Odoo.com customizations). While searching for a solution allowing to keep the fix of [1] and the whole purpose of `_check_user_can_modify`, the logic part of [1] is reverted, keeping the test but disabled. [1]: https://github.com/odoo/odoo/commit/8c41c147a4c6a415e7c5bfdde9297edbf40b4239 Forward-Port-Of: odoo/odoo#225160
Cog menu actions in form, list, and kanban views now use the most current screen context instead of older startup data. This prevents actions from running on outdated record versions, helping users get the expected result after changing options such as an employee version.
Original PR description
In form, list and kanban views, cog menu actions were executed with the context received in props. However, that context may change afterwards, especially with js customizations (js_class, widgets...). As a matter of fact, it is the case in the employee form view, as clicking on the status bar, which represents the versions, adds a key in the context to encode the current version. Before this commit, executing a cog menu action after changing the version of an employee was still executing it on the last version of that employee. With this commit, the correct (up to date) context is correctly given to the action. Needed for task~4997195
Tax lookup now works with partial or approximate names instead of requiring an exact match. This helps users find the right tax faster, such as matching entries like "21% S" when typing a shorter shortcut like "21s".
Original PR description
Issue: - Searching for a tax by its name is not flexible. - Users have to type the exact name of a tax to find it. Fix: - Allow using the shortcut feature with both `name` and `display_name`. The field `name_searchable` is deprecated as it can be implemented without that field now. Impact: - Improves user experience by allowing tax searches using partial or approximate name inputs. - For example, typing '21s' will return all relevant results like '21% S' and similar matches. Task: 5046098 Forward-Port-Of: odoo/odoo#224618
The Malaysia Statement of Account PDF now applies the proper currency conversion when invoices use a currency different from the company's main currency. This prevents customer balances from showing the right currency symbol with an unconverted amount, improving accuracy in financial reporting.
Original PR description
## Short functional explanation of the error When we create an invoice with a different currency than the main one, the Statement of Account PDF report in aged receivable has an error. The amount for…
## Short functional explanation of the error When we create an invoice with a different currency than the main one, the Statement of Account PDF report in aged receivable has an error. The amount for each line is displayed as the main currency, but the conversion isn't done. For instance, if we create an invoice line of 3.5$ but our main currency is the Euro, in the report, it will show 3.5€ instead of 2.99€ ## Reproduction Steps 1. In a db without demo data, Download the app l10n_my. 2. In the general settings, click on Currencies. Activate a second currency and set its currency rate (relative to the main currency of the company) different of 1. 3. In accounting > settings, click on -> Currencies. Activate this second currency. 4. Click on configuration > journals and activate the debug mode. In the Journal Entries tab, as Currency, select a different currency than your main one (set in the general settings). 5. Create an invoice. Set a customer and select the journal for which you set an additional currency. Select this additional currency. Finally, add a product and click confirm. 6. Click on Reporting > Aged Receivable. Then, click on the line corresponding to your partner on Statement of Account. A PDF should download. ### Expected behavior The lines under Balance should be displayed as the main currency of the company, with the correct currency rates applying. ### Unexpected behavior The lines under Balance are displayed as the main currency of the company but the currency rates are not applying. ## Origin of the issue In the code, the currency rate isn't used to generate this line of the report: https://github.com/odoo/enterprise/blob/79c1ba68d48e7e068104d867e186610dd5110cc4/l10n_my_reports/report/statement_account_templates.xml#L52 __ opw-4975540 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#93096
Restaurant table bookings linked to appointment resources are now loaded correctly in the Point of Sale when restaurant mode is enabled. This helps staff see relevant reservations on the floor plan and improves reliability of appointment labels in related tests.
Original PR description
Issue: The calendar envents that have a restaurant table ressource are not loaded in the pos if the config is in restaurant mode. Fix: If the config is a restaurant the calendar_event pos domain will return a domain containing the appointment_ressources linked to the config restaurant tables. This commit also fixes the test that checks for the appointment-label on the floor plan. Task-id: 4970986 Forward-Port-Of: odoo/enterprise#90809