Friday, October 3, 2025
19 changes · saas-18.4
Enhancements to existing features
IoT box information is now kept locally so Odoo can continue sending requests to connected devices when internet access is unavailable. This reduces unnecessary server checks and improves reliability for IoT-powered flows such as self-ordering kiosks.
Original PR description
In order to make the `iot_http` service work offline, we cache the iot box records until there is a full action failure. This avoids useless orm calls and in the meantime, allow making requests to the iot box without internet connection. Community PR: odoo/odoo#226839
Resolved issues and error corrections
Field service sales orders now recalculate line prices when a task’s warranty status is changed. This prevents prices from incorrectly staying at zero after warranty is removed, helping ensure customers are billed accurately.
Original PR description
### Steps to reproduce:
- Create a sales order linked to the customer
- Assign a customer (partner) to the task and link the task to the sales order
- Create a sales order line for a product and link it to the task
- Verify the price unit matches the product's list price by default
- Set the task as under warranty
- Add or remove an item from SOL
- Verify the price unit is set to 0.0 in the sales order line
- Unset the warranty status
- Add an item to the SOL
### Cause:
When setting the task as under warranty we modify the price of each SOL to 0.0 but when unset the warranty option we try to fetch the prices from the SOL which we already set it to 0.0
### Fix:
Backporting https://github.com/odoo/enterprise/pull/85492/commits/8615fad5b75d32483b25cf9b1525883e7a730fac to check when writing on the under_warranty value we recompute the SOL prices
opw-4579404
Forward-Port-Of: odoo/enterprise#96045Pasting over selected link text in the editor now respects protected and non-editable content. This prevents website menus or other protected links from being accidentally removed and replaced with plain text.
Original PR description
When the label of a link is fully selected and the user pastes some text, the link is removed. It was removed even if the link was in a `contenteditable=false` or was unremovable. This commit only…
When the label of a link is fully selected and the user pastes some text, the link is removed. It was removed even if the link was in a `contenteditable=false` or was unremovable. This commit only attempts to remove the link element after checking these conditions. It also only selects the link in the `before_paste` handler, and lets the normal paste logic remove it. Steps to reproduce (after 18.4, where it was noticed): - Copy some simple text - Open website builder - Select completely the label of a menu in the header - Paste - Bug: the menu item is removed, and replaced with simple text Steps to reproduce (in 18.0 and later): - Open "To-Do" app - Add a link in the middle of a line of text - With inspector, edit html to put `contenteditable="false"` on the container of the line, and `contenteditable="true"` on the link - Select completely the label of the link in the document - Paste some text - Bug: the link is removed, and the clipboard content is inserted after the non editable element task-5110141 Forward-Port-Of: odoo/odoo#229558 Forward-Port-Of: odoo/odoo#228223
The French accounting FEC export now excludes invoice note and section lines that do not belong to an accounting account. This prevents non-accounting content from appearing in statutory export files, improving accuracy and compliance of reports.
Original PR description
Step to reproduce: - for l10n_fr Localization - Create a customer invoice and add a note or Add a section . - Go to accounting > reporting > FEC - Export FEC (don't exclude 0 lines) Obseravtion: - The journal items with note and section will be included in the FEC Cause: - for Fec report, we consider move_line which do not have account_id linked to it, due to left_join, hence lines with display_type line_note or line_section are included Fix: - use `join` instead of `left_join` - **v17.0, when the behaviour was as expected** https://github.com/odoo/odoo/blob/3d3898b442379d7416da0ee7e363b6587c725218/addons/l10n_fr_fec/wizard/account_fr_fec.py#L194-L196 opw-5079457 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#227817
This fixes an issue where increasing a sale order quantity could create the wrong additional delivery quantity when custom warehouse routes were used. Businesses using multi-step deliveries and personalized routes will now get more accurate picking quantities, reducing manual corrections and fulfillment mistakes.
Original PR description
**Steps to reproduce:** - enable multi-step routes setting. - navigate to warehouse management/locations create a new location (the "test location"). - select "internal location" for the location…
**Steps to reproduce:** - enable multi-step routes setting. - navigate to warehouse management/locations create a new location (the "test location"). - select "internal location" for the location type. - select WH for the parent location - navigate to warehouse management/warehouses and select the warehouse corresponding to WH. - set the warehouse in 3 steps delivery. - click on the routes smart button. - click on the "deliver in 3 steps (pick+pack+ship)" route. - add a rule, for the action select "push to", for the operation type select "internal transfers", for the source location select the "test location" you just created and for destination location select "WH/Output". - save. - create a storable product and set an on-hand quantity - create a new sale order for 1 quantity of this product and confirm it - click on the picking smart button, change the destination location to the test location and validate - open the sale order and change the quantity to 3 **Current behavior:** A new picking is created from stock to packing zone (which is the expected behavior) but the quantity is 1 **Expected behavior:** The quantity should be 2. If we only increase the quantity by 1 on the sale order it does not even create the new picking **Cause of the issue:** The warehouse_id field is invisible in stock.rule form view when the action is push. Therefore, the rule is created without a warehouse_id. Also, moves created from a rule have the same warehouse_id as the rule. https://github.com/odoo/odoo/blob/a729578afb7fed79aac2d622aae4da4c0917f8e5/addons/stock/models/stock_rule.py#L275 So, when we validated our first move (from stock to the test location), this created a second move (from test location to output) that does not have a warehouse id (because it was created from our own push rule that we created). When we update the quantity of the sale ordre line, _action_launch_stock_rule calls _get_quantity_procurement to compute the current quantity on the moves. This method then calls _get_outgoing_incoming_moves to get the initial move created from the rule. In this case this should return only the first move created. But because the second move does not have a warehouse_id, it's rule.id is added to triggering_rule_ids. https://github.com/odoo/odoo/blob/a729578afb7fed79aac2d622aae4da4c0917f8e5/addons/sale_stock/models/sale_order_line.py#L315-L317 And the move is later added to the outgoing moves that will be returned. https://github.com/odoo/odoo/blob/a729578afb7fed79aac2d622aae4da4c0917f8e5/addons/sale_stock/models/sale_order_line.py#L322-L329 So the two moves are returned and the sum of the quantities of the moves is 2 instead of 1. https://github.com/odoo/odoo/blob/a729578afb7fed79aac2d622aae4da4c0917f8e5/addons/sale_stock/models/sale_order_line.py#L292-L294 So the product quantity for the procurement will be 1 (3-2) instead of 2 (3-1). https://github.com/odoo/odoo/blob/a729578afb7fed79aac2d622aae4da4c0917f8e5/addons/sale_stock/models/sale_order_line.py#L386 opw-5039249 Forward-Port-Of: odoo/odoo#229332 Forward-Port-Of: odoo/odoo#227421
Fixed an issue where opening the chat tab in the messaging menu could crash on iOS or load very slowly in other browsers when many chats were present. The menu now builds and sorts its chat list more efficiently, improving reliability and responsiveness for users with large chat histories.
Original PR description
Before this commit, a maximum call stack traceback occurred when accessing the chat tab of the messaging menu on iOS when many chats were present. On chrome and firefox, no traceback occurred, but…
Before this commit, a maximum call stack traceback occurred when accessing the chat tab of the messaging menu on iOS when many chats were present. On chrome and firefox, no traceback occurred, but the menu took a long time to open. Threads shown in the messaging menu rely on the `menuThreads` store property, which had two issues: - It was a computed field done on the many side of the relation, while relying on the inverse (thread) side would be much faster. - The sort function was triggered for each thread inserted or removed from the relation. The sort function is not trivial, and accessing sort fields through the reactive proxy is very slow. This commit fixes the issue by: - Updating the `menuThreads` property to use an inverse instead of a complex compute. - Debouncing the array sort to ensure it is executed only once when the relation is properly filled. task-4794325 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
This fix ensures Spain's Modelo 303 VAT return only considers the relevant tax tags when preparing closing entries. It helps prevent incorrect accounting entries in VAT return processing, improving reliability for Spanish tax reporting.
Original PR description
Before this commit the domain of the modelo 303 would take into account irrelevant tax_tags, causing the closing entry to be incorrect. Fixed this by adding an additional domain to the _get_vat_closing_entry_additional_domain function. Forward-Port-Of: odoo/enterprise#96106
Rental subscriptions using kit products now keep the correct delivered quantity when they are closed or reopened. This prevents erroneous return errors that could block subscription closure after deliveries were validated.
Original PR description
Versions -------- - 18.0+ Steps ----- 1. Enable rental transfers; 2. have a rental product with a kit BoM; 3. create a subscription order in the Rental app; 4. add the rental product; 5. confirm…
Versions -------- - 18.0+ Steps ----- 1. Enable rental transfers; 2. have a rental product with a kit BoM; 3. create a subscription order in the Rental app; 4. add the rental product; 5. confirm order; 6. validate deliveries; 7. close the subscription. Issue ----- Invalid SQL command, cannot return more than was delivered. Cause ----- When closing or reopening a subscription, the `_compute_qty_delivered` method gets triggered. By default, these methods required the relevant moves to have the same `product_id` as the sale order line. For products with kit BoMs, the move's `product_id` is tied to the BoM instead of the final product, leading to `qty_delivered` getting reset reset to 0 on recompute. This causes an error, as `qty_returned` is non-zero. Solution -------- The `qty_delivered` for these lines was set in the `_action_done` method of `stock.move`. By instead moving this logic into a `_compute_qty_delivered` override, any recompute should have the same result, instead of getting reset to 0. opw-4833280 Forward-Port-Of: odoo/enterprise#96179 Forward-Port-Of: odoo/enterprise#88691
Canceling a quality control worksheet now leaves the quality check unchanged instead of creating a completed worksheet by mistake. This prevents incorrect quality records and helps teams rely on worksheet completion status.
Original PR description
**Problem:** Opening the worksheet wizard and discarding it makes the worksheet "completed" **Steps to reproduce:** - create a quality check - set a product - in type select worksheet - select the "quality issues" template - select a team - click on the worksheet smart button - discard **Current behavior:** the worksheet is marked has completed **Cause of the issue:** when discarding, this line causes the creation of an instance of worksheet.template linked to the quality.check via its worksheet_template_id https://github.com/odoo/enterprise/blob/a1dd58f2b59ecd2d22efd29eb0aace7bdca64f66/quality_control_worksheet/static/src/views/quality_worksheet_fromview.js#L35 which will make the worksheet_count field of the quality check worth 1 after discarding https://github.com/odoo/enterprise/blob/1c5e547b59a57c840ef72b2e76c6a6a627f1f18e/quality_control_worksheet/models/quality.py#L37-L39 opw-4980945 Forward-Port-Of: odoo/enterprise#95219
This fixes website header menus so they automatically move overflowing items into the dropdown when header content changes, not only after resizing the browser. It also keeps text selection and editing behavior consistent when menu items move into or out of dropdowns, preventing lost typing focus or floating toolbars.
Original PR description
> [VBAL] Supported payment methods inner content (in the header): You can adjust the height, but this moves the elements on the right outside of the screen (can be fixed by zooming/unzooming on the…
> [VBAL] Supported payment methods inner content (in the header): You can adjust the height, but this moves the elements on the right outside of the screen (can be fixed by zooming/unzooming on the screen but not user friendly): https://drive.google.com/file/d/1J0Vp050kDzx_jnPVfWyHxy6GpQ6GvpBX/view?usp=drive_link ### [FIX] website: re-adapt extra menu on size changes of menu and navbar When the size available or needed for the the top menu changes (for other reasons than a window resize), the menus were not auto-hidden. They were auto-hidden only if the window changes size. If the user is editing the website and increase the width of some element in the header, it may overflow. The overflow disappears only once the user changes the size of the window (which causes some menu to be hidden again). This commit fixes that by replacing the listener for a window `resize` event by a `ResizeObserver` that observe the sizes of the navbar, the menu and the menu's siblings. Steps to reproduce: - Open website builder - Add text in the header until it gets too large - Bug: the last menu is not moved to the dropdown to make more space available task-4367641 ### [FIX] website: move selection with menu when auto-hiding menus When some menu are moved to be hidden in the dropdown, if the selection is inside a moved menu, it was lost. This commit fixes that by opening the dropdown and moving the selection if it is in a menu moved to the dropdown Steps to reproduce: - Open website builder - Add text in the label of a menu until it is moved to the dropdown - Bug: the selection is lost, keep writing does not write anywhere task-4367641 ### [FIX] website: remove selection in dropdown when it closes When the user has the selection inside a dropdown that closes, the selection was kept. If the toolbar was shown on the selection, then used to stays floating where the selection used to be. This commits listen for the closing of the dropdown to remove the selection if it was in the dropdown. Steps to reproduce: - Open website builder - Click on the user's name to open the dropdown - Select some text in the dropdown (the toolbar should appear) - Press "esc" (the dropdown should close) - Bug: the toolbar is left hanging where the selection used to be task-4367641
Product prices on the website now display using the correct currency precision, such as showing no decimals when the currency is configured that way. This avoids inconsistent pricing displays between editor sessions and regular customer visits, improving clarity and trust at checkout.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Set currency rounding of EUR to 1.0; 2. use the currency on a website pricelist; 3. go to a product page in /shop; 4. open the url in a new session. Issue…
Versions -------- - 17.0+ Steps ----- 1. Set currency rounding of EUR to 1.0; 2. use the currency on a website pricelist; 3. go to a product page in /shop; 4. open the url in a new session. Issue ----- From the editor, the price gets displayed as expected, with no decimals. In the new session, the price gets displayed with two decimals. Cause ----- The `_priceToStr` method used, always uses a `precision` of 2, except in editor mode when it will retrieve a different value from a hidden `.decimal_precision` element. Solution -------- Add the website's currency precision to `combination_info` via the controller, and use this value in `_priceToStr`. For the product configurator, store the currency precision in the `.js_price_total` element's dataset. Also insert the precision in the `.oe_price` element's dataset, allowing it to be used as a fallback in case the configurator template isn't up to date. opw-4996878 Forward-Port-Of: odoo/odoo#229416 Forward-Port-Of: odoo/odoo#224429
This fixes an inventory calculation issue where outgoing stock moves could be missed when quantities were computed for a specific location. Businesses using strict location-based stock checks should now see more accurate product availability and inventory figures.
Original PR description
### Issue: Commit ba54310a11d2b702753d4b9b028a62dd00a91467 has altered the location domain for quantities computations. However, the `dest_loc_domain_out` has not been correctly replaced: https://github.com/odoo/odoo/blob/f173c738b1adcf85a80eb641ad307b7cccf17294/addons/stock/models/product.py#L319 Since the returned value used to be negated and is not anymore. This results in out moves being ignored by the `_compute_quantities` in `strict` mode. opw-4997982 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#229304
DHL delivery insurance settings are now included when calculating shipping prices and creating shipments. This helps ensure customers are charged accurately and insured shipments are properly requested from DHL, with clearer feedback when insurance is unavailable for a route.
Original PR description
**PROBLEM** Insuring a delivery using the dhl carrier don't work. It doesn't affect the estimated rate of the delivery, and the shipment created when validating the delivery order isn't insured.…
**PROBLEM** Insuring a delivery using the dhl carrier don't work. It doesn't affect the estimated rate of the delivery, and the shipment created when validating the delivery order isn't insured. **STEP TO REPRODUCE** 1. Install the `delivery_dhl_rest` and the `l10n_be` modules (we will use the be demo company). 2. Set the insurance percentage of the dhl be delivery method to 100%, and set the region to Europe (the demo data is incorrect), and activate the debug (click the "No Debug" smart button to activate the log of requests). 3. Switch to the be company. 5. Create a sale order, with a customer located in Belgium, and add shipping using the dhl method. 6. Go to the delivery order, and validate it. 7. Go to settings/Technical/Logging and look at the rating_request and shipment_request, notice there is no information about insurance. **CAUSE** We don't send any info about insurance in the api requests. **FIX** Computing and sending the insured amount, only if the insurance percentage is not null. If the package can't be insured between the origin and the destination, a error message will be displayed when updating the delivery price. **TESTS PROBLEM/FIX** The localization of `your_company` was not recognized by DHL, leading to the DHL api returning a 0 delivery price. Switching the localization to Eghezee, Rue du Laid Burniat 5 fixes this. Assertion regarding the delivery price were restored. The picking date could sometimes be refused by DHL (stop working after arround 4/5 PM). Changing the picking date to, two day after, at noon works. `test_01_dhl_basic_be_domestic_flow` was modified to also test domestic shipment insurance in addition of the basic flow. Some code in it was refactor into inner function to avoid boilerplate. Adding `INSURED_RATE_MOCK_RESPONSE` to mock response in test_01. opw-4989281 Forward-Port-Of: odoo/enterprise#93105
Products created under a parent company will no longer have a branch company's default tax added back after a different tax is selected. This prevents incorrect tax settings on products and helps keep pricing and accounting behavior aligned with the user's intended choice.
Original PR description
**Issue description:** The logic introduced in #127196 adds default taxes from "other" companies to products created without a specific company. However, because child companies (branches) share…
**Issue description:** The logic introduced in #127196 adds default taxes from "other" companies to products created without a specific company. However, because child companies (branches) share taxes with their parent company, when creating a new product using the parent company and setting a specific tax (different from the default), the default tax was incorrectly added back to the product. This happened because the logic considered the branch an "other company" and applied its default tax. **FIX:** Exclude branch companies from the domain when we set the default tax of other companies on the product. **Steps to reproduce:** 1. Create a branch company. (It will automatically have the same default tax as its parent). 2. With the parent company selected, create a new product, leaving the 'Company' field empty, and change its sales tax to any tax other than the default, and save. 3. Notice that the default tax is set again on the product. opw-5094415 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#229066
Tax returns now correctly recognize fiscal years that do not start in January. This prevents an incorrect warning from appearing when users create annual tax returns aligned with their company fiscal year.
Original PR description
When the company fiscal year is not the first of the year (Aug 1 → Jul 31), creating a tax return for the fiscal year (2024-08-01 → 2025-07-31) wrongly triggers the wizard’s “wrong dates” warning.…
When the company fiscal year is not the first of the year (Aug 1 → Jul 31), creating a tax return for the fiscal year (2024-08-01 → 2025-07-31) wrongly triggers the wizard’s “wrong dates” warning. The wizard validates the range by slicing it into periods via `_get_period_boundaries()`, which anchors the first period using `_get_start_date_elements()`. If we dont have `deadline_start_date` that anchor falls back to a fixed Jan 1 (calendar year) instead of the company’s fiscal-year start. Consequently, the first computed period becomes 2024-01-01, so the check sees a mismatch and flags the warning even though the user’s dates are perfectly aligned with the fiscal year. The fix is to use the company’s fiscal-year start as the anchor for period slicing instead of silently defaulting to Jan 1. `_get_start_date_elements()` still prefers the explicit `deadline_start_date` (unchanged behavior for calendar-anchored VAT returns), and otherwise derives the day/month from `company.compute_fiscalyear_dates(today)['date_from']`. Steps to reproduce: Accounting: Settings and set Fiscal Year End to July 31 Reporting: tax reports and set it to Year and the year to 2024 Top left there is the Return, click on it and set: - Opening Date: 08/01/2025 - Fiscal Year End: 31 July - VAT Periodicity: Annually Creat a new tax return and chose any type and set: - start date 08/01/2024 - end date 07/31/2025 opw-4990676
This fix prevents consolidated invoices from being created when selected Point of Sale orders have different Mexican e-invoicing details. Instead of failing with a technical error, users now receive a clear validation message so they can invoice incompatible orders separately.
Original PR description
Issue: Currently when we consolidate billing for PoS orders we receive an error because some l10n fields expect a single record and not a recordset. This can be solved by looping over the PoS orders instead and preparing the invoice values per order (this is how the sale orders handles consolidated billing) however, we run into an issue if not all PoS orders have the same l10n fields. Ideally PoS orders with different l10n fields should not be consolidated. Purpose of this PR: check to make sure that the three l10n_mx_edi fields are the same among PoS orders before creating consolidated invoice. raise a validation error if the fields are not the same. Steps to reproduce on Runbot: install pos and l10n_mx* create pos orders for same contact try to create invoices with consolidated billing enabled singleton error is raised Note: main discussion about consolidated billing with l10n_mx localization: #86255 opw-4802180 Forward-Port-Of: odoo/enterprise#86579
This fix prevents locked bank account number data from being updated after it has been protected. It helps preserve the integrity of stored payment information and reduces the risk of accidental or unauthorized changes.
Original PR description
Before this fix it was possible to update sanitized_acc_number even if it is locked. Forward-Port-Of: odoo/odoo#229833 Forward-Port-Of: odoo/odoo#184736
This fix prevents an access error that could stop branch users from creating point of sale orders for products linked to a parent company. It helps keep checkout operations running smoothly when real-time inventory valuation is enabled.
Original PR description
Before this commit, if a product was assigned to company A and a user from one of its branches tried to create an order with real-time inventory valuation enabled, the system would raise an access error when reading the product's cost_currency_id field. opw-4969390 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#229414 Forward-Port-Of: odoo/odoo#223951
The partner ledger now includes reconciled accounting entries that do not have a partner when calculating opening balances. This keeps balances and totals consistent across reporting periods, reducing confusion in financial reports.
Original PR description
### Issue: The partner ledger does consider lines without partners when calculating the initial balance. ### Steps to reproduce: - Create an invoice in 2025 - Create an entry in 2025 without partner…
### Issue: The partner ledger does consider lines without partners when calculating the initial balance. ### Steps to reproduce: - Create an invoice in 2025 - Create an entry in 2025 without partner for the same amount - Reconcile the two - Open the partner ledger for 2025, everything is correct - Change the dates to 2026, the amount of the initial balance ignores the entry but not the totals ### Cause: The method `_get_sums_without_partner` is called for the totals, but not for the initial balance. Its purpose is to add the amounts of the lines without partners that were reconciled with lines with a partner. ### Solution: Call `_get_sums_without_partner()` in `_get_initial_balance_values()` add the results before returning the initial balances. As this is the same logic as `_query_partners()` we create a new method. This method needs to be called with the dates of the initial balance in the options. So we create a duplicate of the options and input the new dates options. opw-5068790 Forward-Port-Of: odoo/enterprise#96125 Forward-Port-Of: odoo/enterprise#95881