Tuesday, September 1, 2026
9 changes · saas-18.4
Enhancements to existing features
Large Italian electronic invoices now import much faster by processing invoice lines more efficiently and reducing repeated checks. This shortens waiting times for accounting teams, especially when handling invoices with many lines.
Original PR description
### Description: When importing a large invoice, the process can take a lot of time. This is caused by how `l10n_it_edi` handles the creation and writing of each line of the bill. To improve performance, most of the process is now performed in memory and record creation is deferred to a single batch at the end. Additionally, the check related to `account_accountant` is cached to avoid superfluous calls. ### Benchmark: **For `history.limit`[^1] of 50 (= 21002 `account.move.line`):** | Invoice lines | Before | After | Speedup | |---------------|----------|---------|---------| | 33 | 4.75s | 2.23s | 2.1× | | 172 | 2.3min | 45.1s | 3.1× | | 1,934 | 44.4min | 6.8min | 6.6× | [^1]: System parameter `account.bill.predict.history.limit` ### Reference: opw-5937519 Forward-Port-Of: odoo/odoo#282880
Invoice field prediction has been optimized for databases with many accounting entries. This should reduce waiting time when matching invoice lines to products, accounts, or taxes, especially in Peppol-heavy workflows.
Original PR description
### Description: Predicting fields can be slow when the database has a large amount of move lines (AML). This is caused by the fact that `_predicted_field` will search on all these AMLs to find the…
### Description: Predicting fields can be slow when the database has a large amount of move lines (AML). This is caused by the fact that `_predicted_field` will search on all these AMLs to find the ones related to the searched fields. It can be an issue when using Peppol since it is used a lot in most localizations to match each line to its product/account/tax. To speed up the queries, the move IDs have been inlined in `_build_predictive_query` to avoid suboptimal execution plans caused by LIMIT and ORDER BY clauses. Additionally, materialization of the `account_move_line` CTE has been removed so the planner can inline filters and stream rows directly, which improves performance in most use cases. ### Benchmark: **For a `history.limit`[^1] of 100:** | Nb of invoice line | Before | After | AMLs scanned | |--------------------|-----------|---------|--------------| | 33 | 7s | 4s | 232 | | 172 | 11.39min | 5min | 99859 | | 1934 | 3h+ [^2] | 1h40min | 102503 | **For a `history.limit`[^1] of 50:** | Nb of invoice line | Before | After | AMLs scanned | |--------------------|---------|---------|--------------| | 33 | 6s | 4s | 187 | | 172 | 2.52min | 1.27min | 21002 | | 1934 | 40min | 20min | 21002 | [^1]: System parameter `account.bill.predict.history.limit` [^2]: Stopped manually after 3h; full runtime not measured ### Reference: opw-5937519 Forward-Port-Of: odoo/enterprise#128172
Resolved issues and error corrections
Fixes a problem where choosing a website theme could leave key design elements, such as the header and footer, unchanged. This ensures newly selected themes are fully applied during setup, giving users the expected website appearance.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283174
The Guatemala electronic invoicing localization now uses the updated tax calculation for regular gasoline containing 10% alcohol. This matters because, from August 22, only 90% of the gallons are taxable, keeping new customer accounting templates aligned with government rules.
Original PR description
Starting August 22nd Regular Gasoline is changing to a version that contains 10% alcohol. Because of this, the government is only taxing 90% of the gallons since the 10% alcohol portion is exempt. This will update COA for new customers, any current dbs who need to use the new formula can manually update theirs to include the * 0.9 portion. task-6483303 Forward-Port-Of: odoo/enterprise#129483 Forward-Port-Of: odoo/enterprise#129412
This fixes an inventory issue where packaged delivery quantities could be assigned to the wrong order line when processing whole packages. Businesses avoid unnecessary backorders and stuck transfers after the shipment has already been handled.
Original PR description
### Steps to Reproduce: 1. Make sure that the Sale and Inventory modules are installed 2. Enable Multi-Step Routes and Packages in Inventory Configurations 3. Warehouse configuration > Outgoing…
### Steps to Reproduce: 1. Make sure that the Sale and Inventory modules are installed 2. Enable Multi-Step Routes and Packages in Inventory Configurations 3. Warehouse configuration > Outgoing shipments > Select Pick then Deliver (2 steps) 4. Routes > Deliver in 2 steps (pick + ship) > Pull From > Destination Location > Select WH/Output 5. Routes > Deliver in 2 steps (pick + ship) > Push To > Action > Change to Pull From 6. Operation Types > Delivery Orders > Packages > Enable Move Entire Packages 7. Go to any product, ex. Drawer > On Hand > Set original on hand qty to 16 and new lot to 50 8. Create a new SO and make 2 lines, with the same product, and change the second line's price to something else, ex. 80.0 9. Deliveries > WH/PICK/00001 > Set quantity to 4 > Put in Pack > Validate and Create Backorder 10. WH/PICK/00002 > Put in Pack > Validate 11. WH/OUT/00012 > Mark PACK0000001 Done > Save. Observe how the first line quantity is changed from 3 to 4 12. Mark PACK0000002 Done > Save > Validate > Observe how it's asking for a backorder even though we already packed all 5 items. ### Description of the issue/feature this PR addresses: Instead of using the `product_qty` from the stock move, use the quantity of the move line to correctly allocate the quantities in StockPackageLevel ### Current behavior before PR: In the Shop Floor when loading packages, marking the package level as done causes issues on the quantity processed on the corresponding move lines. On stock transfers, we currently allocate the Quantity Done to the wrong product line. The total quantity is correct, but the distribution across lines does not match the Demand values. This causes the transfer to remain stuck in Reserved, even though the shipment was already processed operationally. ### Desired behavior after PR is merged: The correct quantity from the move line is used and this resolves the issue with quantity distribution not matching move line quantities when using packages. opw-6040640 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#242487
This fix prevents restaurant POS orders from losing their order lines when the same table is used across multiple devices before payment. It ensures paid orders keep the correct products and totals, reducing the risk of incorrect sales records and follow-up corrections.
Original PR description
Steps to reproduce: - Restaurant config with two POS devices on the same session - Device A: open a table, add two products, press Order (the order is synced as a draft, its lines get server ids) -…
Steps to reproduce:
- Restaurant config with two POS devices on the same session
- Device A: open a table, add two products, press Order (the order is synced as a draft, its lines get server ids)
- Device A: remove both lines, without syncing
- Device B: touch the same order, so device A re-reads it from the server through the synchronisation websocket
- Device A: pay and validate the order
Issue:
The order is saved as paid, with its total and its payment, but without any orderline. The lines are deleted on the server: odoo.models.unlink: deleted pos.order.line records with IDs: [...]
Cause:
Removing an orderline queues an unlink command in
models.commands['pos.order'].unlink['lines_<order id>'] (delete_ in related_models.js). That command is only discarded by clearCommands(), which syncAllOrders() calls after a successful sync, so it stays pending in between.
Any read of the order in that window puts the line back: a deleted record counts as missing in missingRecursive(), so it is fetched again and loadData() re-creates it with its server id.
serialize() then emits both the update of the live line and the still pending unlink, and sync_from_ui writes
lines: [[1, id, {...}], [3, id]]. The ORM applies commands in order, and pos.order.line.order_id is ondelete='cascade', so Command.UNLINK deletes the line right after writing it.
Fix:
Skip a removal command when the record is still linked to the parent at serialization time. A record cannot be both linked and removed in the same payload, so the pending command is stale and dropping it keeps the local state. Genuine removals, where the record is no longer linked, are still sent.
opw-6401146
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#285427
Forward-Port-Of: odoo/odoo#284695Argentine export invoices now send the correct recipient identification information in the QR validation data. This prevents ARCA from showing the wrong ID type and allows these invoices to be verified as valid legal documents on the official ARCA page.
Original PR description
Before this change we were sending id type code 0 and this generate two problems * ARCA verification page it was wrongly taking "CI Policia Federal" as the identification type of the receptor * We were not able to validate the expo invoice, we get always an error With this change the expo invoice can be checked as a real legal document in the ARCA page https://servicioscf.afip.gob.ar/publico/comprobantes/cae.aspx Forward-Port-Of: odoo/enterprise#126704
Fixes Polish e-invoicing so K_12 taxes are correctly treated as reverse charge in KSeF XML exports. This helps invoices using the 0% EU U tax report the right reverse charge status and tax base, reducing compliance and reporting errors.
Original PR description
**PROBLEM** K_12 taxes needs to be reported as reverse charge tax. **STEP TO REPRODUCE** 1. Create an invoice with the tax 0% EU U. 2. Send the invoice the ksef. 3. Open the xml, an notice P_18 value is 2 (meaning no reverse charge), and there is no tag P_13_10. expected behavior: P_18 = 1, P_13_10 = base for the tax. opw-6460338 Forward-Port-Of: odoo/odoo#281934
Accountants can now generate BOE files for Spanish Modelo 115 tax reports without needing company access-rights permissions. This removes an incorrect access error caused by the export wizard trying to save company-related data that users were not actually editing.
Original PR description
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax…
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax reports, even though exporting a BOE file has nothing to do with editing company configuration and should be available to any accountant. Steps to reproduce: ------------------- * Log in as a user with accounting rights only (not part of the Companies > Access Rights group) * Go to Accounting > Reporting > Tax Return, open the Mod 115 report * Click the gear icon > BOE > Generate BOE > Observation: An AccessError is raised: "You are not allowed to modify 'Companies' (res.company) ... This operation is allowed for the following groups: Access Rights", even though the user is not trying to edit the company. Why the fix: ------------ The BOE wizard shared by Mod 111/115/303 declares a `company_partner_id` field, related to `company_id.partner_id`, with `readonly=False`. That field is invisible in every view and only exists to compute the domain of `partner_bank_id`; it was never meant to be edited by the user. Because it is declared writable, the ORM attaches an inverse to the related field, so saving the wizard (which happens when generating the BOE, since the field, though invisible, is still part of the view and thus of the saved values) writes `company.partner_id` back onto `res.company`, even though the value never actually changes. That implicit write requires write access on res.company, which is only granted to the Access Rights group, causing the error for regular accountants. Dropping `readonly=False` keeps the field as a plain readonly related field, still usable for the bank account domain, without ever triggering that spurious write. opw-6388869 Forward-Port-Of: odoo/enterprise#129841 Forward-Port-Of: odoo/enterprise#126661