Monday, September 1, 2025
19 changes · saas-18.4
Enhancements to existing features
The HTML builder gains a new overlay panel that brings visual styling controls closer to the content being edited. This should make common design adjustments such as backgrounds, shadows, and image shapes more discoverible and faster for users building pages.
Original PR description
WIP
Point of Sale users can now switch the IoT Box connection mode directly from the local, online, or offline status button. This makes it easier to recover or choose the best connection method when devices need to communicate through either local polling or websocket mode.
Original PR description
We used to allow longpolling again manually if the IoT Box was reachable (by pinging it), but we couldn't force the connection to use websocket if needed. We now switch between modes when clicking the local/online/offline button in PoS. Task: 5055024
Resolved issues and error corrections
India EDI, e-waybill, and IRN retry actions now leave a log entry on the related document. This helps businesses see which user retried a submission, which is important because too many GST requests can temporarily block access for 24 hours.
Original PR description
Manual fw-port of https://github.com/odoo/odoo/pull/223957, https://github.com/odoo/odoo/pull/223886, https://github.com/odoo/odoo/pull/207184 *=edi,ewaybill,ewaybill_irn Following the implementation of [Black list request by GST](odoo/iap-apps#1039) the users are blocked for 24 hours on generating too many request. When processing through EDI there is no log when clicked on the retry button, Which is more essentially needed now to know by which user the EDI was retried and we logged the same on the move --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#224169
Hungarian e-invoicing now correctly reports credit notes as modifications when the original invoice had any payment before reversal. This prevents incorrect STORNO submissions to NAV and helps keep tax reporting accurate.
Original PR description
Before this PR: - Previously, a credit note was marked as STORNO if the base invoice's residual amount was zero, regardless of whether any payments had been made. This led to incorrect STORNO reports being sent to NAV in cases where the invoice had been partially or fully paid before reversal. After this PR: - If any payment was made, the credit note is marked as MODIFY instead of STORNO. Example: - Case 1: No payments before reversal Invoice: 1000 Credit Note 1: -100 Credit Note 2: -900 => Credit Note 1 should be sent as a Modification, Credit Note 2 as STORNO. - Case 2: Payments before reversal Invoice: 1000 Payment: -100 Credit Note: -900 => The Credit Note should be sent as a Modification. task-4818762 Forward-Port-Of: odoo/odoo#224861 Forward-Port-Of: odoo/odoo#211831
This fix prevents order tracking numbers from appearing in every Point of Sale setup, limiting them to restaurant or preparation-display flows where they are useful. It also keeps clear prefixes for kiosk and self-order receipts, helping staff distinguish order sources and avoiding confusion.
Original PR description
- Fix issue where `tracking_number` was displayed for all config. We want to display this number only for `pos_restaurant` configurations. We also want to display it for POS config which have a preparation display configured (see enterprise linked PR). - Ensure Kiosk & Self orders correctly contains a prefix (S or K) inside their `tracking_number` to avoid regression. task-id: 4922308 enterprise PR: https://github.com/odoo/enterprise/pull/91833 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#224492 Forward-Port-Of: odoo/odoo#222094
Unsupported IoT devices are now checked repeatedly while they remain connected, instead of requiring users to unplug and reconnect them. This makes device setup and recovery smoother when a device becomes supported after initial detection.
Original PR description
Before this commit, in order for an unsupported device to become supported, it would need to be disconnected so that it was removed from the detected devices, and then reconnected at which point the supported method will be checked again. After this commit, the supported method is run on every iteration of the interface for any existing unsupported devices. This way if they can become supported without disconnecting them entirely. task-5055685 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Fixes an issue where product capacity lines could seem to disappear immediately after saving a new storage category, even though they returned after reloading. This keeps the saved information visible and consistent for users, and includes a CRM test correction so the fix can be safely validated.
Original PR description
_Note: The main fix of this PR (the orm one) raised an error in CRM, a test was working thanks to some cache pollution (cf description of crm commit). The below text only shows the description of the…
_Note: The main fix of this PR (the orm one) raised an error in CRM, a test was working thanks to some cache pollution (cf description of crm commit). The below text only shows the description of the orm commit._ The use of a computed inverse o2m field does not correctly work when creating the record of the main model. To reproduce: (Need stock) 1. In Settings, enable "Storage Locations" 2. Create a new Storage Category - Make sure to have one Capacity by Product Error: on save, the Capacity by Product disappears. Yet, if the user reloads the page, the capacity will be back. First, few details about the Storage Category model. We are dealing with the field `product_capacity_ids`, a computed inverse o2m field: https://github.com/odoo/odoo/blob/e5e3a3f7bf3770fe2bba11b501870d4fb7ef2e51/addons/stock/models/stock_storage_category.py#L15 Its content is a subset of the `capacity_ids` field: https://github.com/odoo/odoo/blob/e5e3a3f7bf3770fe2bba11b501870d4fb7ef2e51/addons/stock/models/stock_storage_category.py#L14 So, its compute simply get a subset of `capacity_ids` and its inverse will write some values on `capacity_ids`: https://github.com/odoo/odoo/blob/e5e3a3f7bf3770fe2bba11b501870d4fb7ef2e51/addons/stock/models/stock_storage_category.py#L39-L41 Now, back to the issue. When we `web_save` the category, at some point in the create process, it leads here https://github.com/odoo/odoo/blob/bdb24afbf85f4d58722db493f725dd95c5780ff7/odoo/orm/models.py#L4389-L4408 Where we want to resolve all the pending inverse. To do so, we first update the cache (L4401) and we then call the inverse methods (L4408). In the above case, it means that we first update the value of `product_capacity_ids` in the cache. The value we are passing is a `Command.CREATE` value. In that case, when converting the value for the cache, we actually create a `NewId` record: https://github.com/odoo/odoo/blob/ae55f5b494005a1e7566c819592f7dd64623c3fd/odoo/orm/fields_relational.py#L513-L516 When running the inverse, we write this record on `capacity_ids` (cf the code quoted above). This will lead to the actual creation of the capacity record. But... Here is where the problems begin: we have updated the cache with a `NewId` value and define `capacity_ids` with an existing record. However, we don't update anything in the cache. As a result, at the end of `web_save`, we do a `web_read`. It will lead here: https://github.com/odoo/odoo/blob/bdb24afbf85f4d58722db493f725dd95c5780ff7/odoo/orm/models.py#L3427 Where we convert the value of `product_capacity_ids`. Since available in the cache, we will use the `NewId` value and convert it, i.e.: we will return the `.ids` of the recordset: https://github.com/odoo/odoo/blob/ae55f5b494005a1e7566c819592f7dd64623c3fd/odoo/orm/fields_relational.py#L569-L570 Which means... The actual IDs, excluding the `NewId` one. This explains why the line suddenly disappears on save. Then, reloading the page will trigger the compute based on `capacity_ids`. This field is correctly defined, so will do the compute -> the line will appear. Since we update the cache to compute the inverse, we should then clear that cache to ensure proper consistency with what happened during the inverse. OPW-4915087 Forward-Port-Of: odoo/odoo#222763
This fix prevents invoices from crashing during Veri*Factu sending when a Spanish company does not have a VAT number set. Users will see a more reliable invoice sending flow instead of an unexpected system error.
Original PR description
The system will crash when user tries to send the invoice.
**Steps to produce:-**
- Install the **Accounting** module and switch to the **ES company** (with demo data).
- Remove the **VAT** from the ES company and save the changes.
- Go to **Accounting** and create any invoice.
- Click on **Send**.
- In the send wizard, ensure that **Veri\*Factu** is checked at the top, then click the **Send** button.
**Error:-**
`KeyError: 'NIF'`
**Cause:-**
- When the company VAT is not set,` _l10n_es_edi_verifactu_get_values()` does not provide an 'NIF' key.
- Accessing 'NIF' directly in such cases raises a `KeyError` when sending an invoice.
**Solution:-**
- In this PR, `.get('NIF')` instead of direct key access to safely handle missing values.
**sentry-6829500308**
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prIoT Boxes now allow more time and retry when downloading certificates from Odoo.com. This reduces setup or renewal failures caused by slow networks, high service load, or certificate provider delays.
Original PR description
Certificate download on the IoT Box from Odoo.com can take more time than the currently set 10 seconds. This can be due to the network, to odoo.com's load, or to let's encrypt. We aligned the timeout to let's encrypt library's timeout, and added a retry, as the iot box should always get a certificate. Task: 4948448
This fixes supplier bills created from foreign-currency purchase orders when tax is already included in the line price. The bill line balances now deduct the included tax before currency conversion, preventing incorrect accounting amounts.
Original PR description
**Steps to reproduce** - Setup a foreign currency [CUR] with rate - Create a purchase order - Add [CUR] as currency - Add an order line with price included tax - Confirm and receive - Create Bill - Check generated lines values **Issue** Balance of the move lines will be off, as if it was computed using the wrong conversion rate **Investigation** It occurs because when preparing the move values, the system add the balance calculated from the product price. This does not work for price included taxes, as the balance of the invoice line need to have the tax amount deducted opw-4954649 Forward-Port-Of: odoo/odoo#224705 Forward-Port-Of: odoo/odoo#221952
Public holidays spanning multiple days now appear as blocked for every day in calendar views when flexible working schedules are used. This gives employees and managers an accurate view of unavailable days and avoids confusion when planning time off.
Original PR description
**Issue**: Multi-day public holidays only display as single days in calendar views when using flexible working schedules. A 3-day holiday appears as only 1 day blocked, though time-off requests are still correctly prevented for all 3 days. **Cause:** In `_get_unusual_days()`, the implementation for flexible schedules only captures the start date of each leave interval https://github.com/odoo/odoo/blob/132938929d46c8248a9e3a7e2972174ae38eacfa/addons/resource/models/resource_calendar.py#L683-L685 **Steps to reproduce:** 1. Configure a flexible working schedule for an employee or company 2. Go to Time Off > Public Holidays 3. Create a 3 day public holiday 4. Check Time Off calendar view Only 1 day appears blocked instead of all 3 days opw-4997757 Forward-Port-Of: odoo/odoo#224845 Forward-Port-Of: odoo/odoo#224668
Fixes an issue where users could not continue typing after choosing a font size in the HTML editor, even though their text selection still appeared active. The editor now correctly returns focus after the font size dropdown is used, reducing confusion and avoiding interrupted editing workflows.
Original PR description
### Steps to reproduce: - Go to the To-Do app and type something in the editor. - Select the typed text. - Click on the Font Size Input and choose a value from the dropdown (e.g.,80). - Try typing…
### Steps to reproduce: - Go to the To-Do app and type something in the editor. - Select the typed text. - Click on the Font Size Input and choose a value from the dropdown (e.g.,80). - Try typing again in the editable area. - Selection is still visible, the focus is no longer in the editable area. ### Description of the issue/feature this PR addresses: - `focusEditable()` skipped restoring focus if the selection was inside the editor, even when the editor itself wasn’t focused. - When the font size input (inside an iframe) is focused, editable loses focus. - Selecting a value from the dropdown blurs the iframe input, but focus is not returned to the editable area. - As a result, the selection is still visible but the user cannot type. ### Desired behavior after PR is merged: - Does nothing if the editor or its descendants have focus. - Focuses the editor if needed. - Restores selection only when it's outside the editor. - When the iframe input is blurred, focus is returned to the editable area. task-4932364 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#222360 Forward-Port-Of: odoo/odoo#218774
Razorpay payments now check whether the saved access token has expired when a customer pays. If needed, the system automatically generates a new token, reducing failed payments caused by expired authorization.
Original PR description
Version: - saas-18.2 Issue: - The refresh token method was removed in PR https://github.com/odoo/odoo/pull/188774. Because of this, the Razorpay access token expiry was no longer being checked. Fix: - When a user makes a payment, the system now checks if the Razorpay access token has expired. If it has, a new token will be generated automatically. opw-4953953 Forward-Port-Of: odoo/odoo#224233
Subscription orders that include one-time products now correctly create deliveries and generate invoices. This ensures one-off items added to subscriptions are fulfilled and billed as expected, avoiding missed shipments and manual follow-up.
Original PR description
**Version:** - saas-18.4 **Steps to reproduce:** - Install the sale_subscription_stock module. - Create a one-time product and save it. - Create a subscription order, add the one-time product to the order line, and confirm the order. **Before this commit:** - When a one-time product was added to a subscription order, no delivery was created. **After this commit:** - A delivery is properly created, and an invoice is automatically generated when the order includes a one-time product. **Solution:** Add a condition to check for one-time products in the order lines and create a delivery if found. **Impact:** - A delivery is now created when a one-time product is in the sale order. Also, an invoice is automatically generated for it. task-4938898
The Kenya OSCU e-invoicing checks now ignore cancelled or draft credit notes when validating invoice reversals. This prevents incorrect blocking errors when businesses issue a new credit note after an earlier one was cancelled or reset.
Original PR description
[FIX] l10_ke_edi_edi_oscu: ensure quantity and monetary values checks are performed on reconciled reversals only. Fixes a behavior where the checks performed on the credit notes related to their quantities and monetary values include non reconciled credit notes. Steps to reproduce: 1 - activate `l10n_ke` on some company. 2 - Create an invoice. 3 - Create a partial or full credit note ( this one will be reconciled with the invoice automatically ) 4 - cancel the credit note or reset it to draft. 5 - create another credit note where the quantities and/or monetary values exceed that of the invoice if summed up with the cancelled credit note. Following the steps will result in an error message saying that the monetary value or quantities on the credit notes exceed that of the invoice. The correct behavior is to simply not count any credit note that isn't explicitly reconciled with the invoice. opw-4779976 Forward-Port-Of: odoo/enterprise#92319
Users who belong to a secondary company can now create multi-company tax returns without hitting an access error. This ensures tax reporting works smoothly for companies operating across multiple entities.
Original PR description
When a tax return is created with multi companies and a user member of one of the secondary companies, he would get an access error due to missing sudo() task-5039551
Italian POS orders now send only positive payment amounts to the fiscal printer, avoiding unsupported negative change payments. This helps ensure receipts are processed correctly and sales are reported to the authorities as required.
Original PR description
Before this commit, specifying the payment method used to give back the change in a POS order would lead to the fiscal printer receiving a negative payment as input, which is not supported, thus leading to the order not being treated by the fiscal printer (so not reported to the government). Only the payments with is_change=true where filtered out. I am now adding a filter to only keep the positive payments in the receipt, as the fiscal printer is computing the change itself. opw-4931671 Forward-Port-Of: odoo/enterprise#91794
Fixes an issue in Mexican sales where a sale order could show zero invoiced quantity after a related electronic invoice was cancelled and replaced. The system now refreshes the invoiced quantity when the electronic invoice status changes, keeping sales records accurate for users.
Original PR description
How to reproduce the issue: In l10n_mx: 1. Create a sale order. 2. Create an invoice from the SO, with yesterday’s date, and send it to the CFDI. 3. Lock the period at yesterday’s date. 4. Request the invoice cancellation with the “01” method. This creates a new invoice — confirm it. 5. Create a credit note for the original invoice. 6. Retry sending the cancel request to the CFDI; the CFDI state is now cancelled for the original invoice. On the original SO, the quantity invoiced is 0 despite the CFDI state of the original invoice being cancelled. This commit forces a recompute of the quantity invoiced when the CFDI state changes. Since _compute_qty_invoiced uses _get_invoice_lines, which filters out invoices in sent state, only lines from invoices in cancelled state will be taken into account. opw-4910139 Forward-Port-Of: odoo/enterprise#93480 Forward-Port-Of: odoo/enterprise#91924
Rental orders paid through Point of Sale now keep the delivered quantity accurate when items are returned. This prevents returned rental products from being counted as delivered again, improving order accuracy and avoiding confusion in rental operations.
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#93358 Forward-Port-Of: odoo/enterprise#90510