Friday, September 4, 2026
22 changes · 19.0
Resolved issues and error corrections
The documentation for temporary records now accurately explains that standard access rights and record rules apply. This prevents misunderstandings for implementers and administrators relying on the documentation to understand data access behavior.
Original PR description
Since 6d8688bb124d, TransientModel records use the regular access rights mechanisms instead of being implicitly restricted to their creator. The docstring was not updated with that change and has therefore incorrectly documented creator-only access since 14.0. Forward-Port-Of: odoo/odoo#286374 Forward-Port-Of: odoo/odoo#286251
Delivery slips now show rounded quantities when receipts or deliveries are split across multiple stock move lines. This prevents confusing decimal artifacts on printed documents and keeps ordered, delivered, and packaging quantities readable for customers and staff.
Original PR description
**Issue** When a move has several move lines, the printed quantities are not rounded, causing floating-point arithmetic artifacts to appear on the report. **Steps to reproduce** - Create and confirm…
**Issue** When a move has several move lines, the printed quantities are not rounded, causing floating-point arithmetic artifacts to appear on the report. **Steps to reproduce** - Create and confirm a PO for 15.6 units of a product. - On the receipt, change the quantity to 17.8 (this splits it into two stock move lines). - Validate the receipt and print the delivery slip. -> The ordered quantity on the generated PDF is not rounded (floating-point arithmetic issue). **Cause** While printing the delivery slip, quantities are aggregated by product: https://github.com/odoo/odoo/blob/189df3538aa07d22f683008522b9143421f411a2/addons/stock/report/report_deliveryslip.xml#L174 No rounding is performed while subtracting quantities from the ordered quantity (resulting in 13.399..): https://github.com/odoo/odoo/blob/189df3538aa07d22f683008522b9143421f411a2/addons/stock/models/stock_move_line.py#L927 Nor while adding the second move line's quantity back to the ordered quantity (resulting in 15.599..): https://github.com/odoo/odoo/blob/189df3538aa07d22f683008522b9143421f411a2/addons/stock/models/stock_move_line.py#L938 **Additional note** Same issues arise for `packaging_qty_ordered`, `quantity` and `packaging_quantity`. opw-6469422
Contact merges no longer copy the OCR-created marker from one contact to another. This prevents validation errors when merging duplicate contacts with the same name, making cleanup of OCR-created contacts smoother.
Original PR description
`is_created_by_ocr` identifies partners that were automatically created while processing an OCR document. A constraint prevents multiple partners with the same name to be created by OCR. But, when…
`is_created_by_ocr` identifies partners that were automatically created while processing an OCR document. A constraint prevents multiple partners with the same name to be created by OCR. But, when merging an OCR-created partner into a regular partner with the same name, the merge copies `is_created_by_ocr` to the destination before deleting the source partner. This temporarily leaves two active OCR partners with the same name and raises the unique constraint. Fix: `is_created_by_ocr` should have `copy=False` and should not be transferred when merging. Make the merge skip fields that are not copyable. This prevents the True value from being transferred to the destination, avoiding the unique constraint error. A test has been added in `account_invoice_extract` in enterprise, since `is_created_by_ocr` is only added to `res.partner` when that module is installed. Steps to Reproduce on Runbot: 1. Create 2 contacts with the same exact name and have one created by OCR. I used a server action to manually set the value of 'is_created_by_ocr' to simplify this process. 2. Select the contacts and merge. In the merge window, set the non-ORC contact to be the destination contact. 3. Upon confirming merge contacts, the validation error will appear. Related ticket: opw-6513607
Fixed an issue where the color picker could fail to recognize the solid color tab when Odoo was used in a translated language. This improves reliability for users working with the HTML editor across different locales.
Original PR description
### Purpose of this PR: - The color picker tabs are registered with a translated name (`_t(Solid)`), and the tab button renders that name as its only content. ColorUIPlugin read the active button's `innerHTML` and compared it to the literal string Solid to know whether the solid tab was the one in use. - Rely on the `solid-tab` class instead, which is built from the untranslated tab id. task-6441654
Reference fields now show a placeholder when a record still needs to be selected after choosing a model. This helps users notice incomplete links before saving, reducing confusion when values disappear after a page refresh.
Original PR description
Steps to reproduce: 1. Install Sign. 2. Open the form view of a document. 3. Select a model in the "Link to" (Reference) field, but leave the record empty. 4. Save and refresh the page. Issue: -…
Steps to reproduce:
1. Install Sign.
2. Open the form view of a document.
3. Select a model in the "Link to" (Reference) field, but leave the record empty.
4. Save and refresh the page.
Issue:
- After refreshing, the selected model is cleared because the reference value is invalid.
Cause:
- A reference field is only valid when it contains both a model and a record ID. However, the record selector has no placeholder, making it easy to overlook and save an incomplete value.
Solution:
- Add a default placeholder to the record selector of reference fields to make it more visible.
<table>
<tr>
<th>Before</th>
</tr>
<tr>
<td>
<img src="https://github.com/user-attachments/assets/3ba34b77-f901-4d3e-9768-5acaf2e673b8" alt="Before" width="100%">
</td>
</tr>
<tr>
<th>After</th>
</tr>
<tr>
<td>
<img src="https://github.com/user-attachments/assets/1fe54b89-221f-4d28-bd2b-0a3c706d5746" alt="After" width="100%">
</td>
</tr>
</table>
opw-6426339
Forward-Port-Of: odoo/odoo#280266The Point of Sale no longer uses an older cleanup step that could remove more order data than necessary. A newer, more targeted fix now handles outdated loyalty reward lines, reducing the risk of unintended changes during checkout.
Original PR description
This fix is no longer required(https://github.com/odoo/odoo/pull/202752) as this one (https://github.com/odoo/odoo/pull/257043) is cleaner and less aggressive (it will only delete stale reward lines). This is the relevant part of the new fix to delete the previous one: https://github.com/odoo/odoo/pull/257043/changes#diff-18cef42f8c39513a82387e9cb81bc732b252304cd15b5b2f7b0b4623ac20cb41R100-R104 opw-6447092 Forward-Port-Of: odoo/odoo#286072 Forward-Port-Of: odoo/odoo#285376
This fix ensures the HTML editor properly removes file-related event handlers when an editor is closed or destroyed. It helps prevent gradual memory leaks and performance issues when users open multiple editor instances over time.
Original PR description
FilePlugin registered its click, keydown and pointerdown handlers with raw `addEventListener`, so they were never removed when the plugin was destroyed. The pointerdown one is bound to the document, which outlives the editable, leaking a handler per editor instance. Use `addDomListener` so Plugin.destroy() removes them. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286144
Merging a contact created from OCR into an existing contact with the same name no longer triggers a validation error. The OCR-created marker now stays with the original record only, allowing users to complete contact merges reliably.
Original PR description
`is_created_by_ocr` identifies partners that were automatically created while processing an OCR document. A constraint prevents multiple partners with the same name to be created by OCR. But, when…
`is_created_by_ocr` identifies partners that were automatically created while processing an OCR document. A constraint prevents multiple partners with the same name to be created by OCR. But, when merging an OCR-created partner into a regular partner with the same name, the merge copies `is_created_by_ocr` to the destination before deleting the source partner. This temporarily leaves two active OCR partners with the same name and raises the unique constraint. Fix: is_created_by_ocr should have copy=False and should not be transferred when merging. Make the merge skip fields that are not copyable. This prevents the True value from being transferred to the destination, avoiding the unique constraint error. A test has been added in `account_invoice_extract` in enterprise, since `is_created_by_ocr` is only added to `res.partner` when that module is installed. Steps to Reproduce on Runbot: 1. Create 2 contacts with the same exact name and have one created by OCR. I used a server action to manually set the value of 'is_created_by_ocr' to simplify this process. 2. Select the contacts and merge. In the merge window, set the non-ORC contact to be the destination contact. 3. Upon confirming merge contacts, the validation error will appear. Related ticket: opw-6513607
This fix prevents an accounting test from running in setups where the required Accountant app is not installed. It helps keep automated testing results accurate and avoids false failures that do not reflect a real customer issue.
Original PR description
This issue occurs because the `_is_user_able_to_review()` check returns `True` when the `accountant` module is not installed, which causes the `checked` field to be set to `True` in the `_compute_checked()` method. However, when the `accountant` module is installed, `_is_user_able_to_review()` is overridden and returns `False` for "Invoicing & Banks" users, causing the `checked` field to be set to `False` in `_compute_checked()`. Therefore, the `accountant` module needs to be installed when running the test. runbot-946621
Fixed an issue in the HTML editor where dragging an image and dropping it back in the same position could trigger an error, especially in Chrome. This improves editing reliability and prevents users from being interrupted while arranging images in content.
Original PR description
Steps to reproduce: - Insert an image as the last child of a paragraph. - Drag and drop it below or after itself. Description of the issue: - A traceback occurs. Cause: - When dropping an image below or after itself `document.caretPositionFromPoint()` computes a drop offset equal to the current node size. - The image is then removed from the DOM before being reinserted. Since it is the last child of its parent, removing it shrinks the parent, making the previously computed offset out of bounds. - Restoring the selection at that stale offset results in a traceback. Solution: - Treat dropping the image at its current position as a no-op and skip the remove/reinsert process, since it would not change the DOM. - Clamp the drop offset to the current node size before restoring the selection preventing out-of-bounds offsets. task-6435091 Forward-Port-Of: odoo/odoo#283680 Forward-Port-Of: odoo/odoo#280612
Rental order lines created from the rental schedule now use the normal product name instead of adding stock quantity text to the line description. Stock quantities still appear where useful in the schedule rows, reducing confusion while preserving planning visibility.
Original PR description
Versions -------- 19.0 and later Steps ----- - Install `sale_stock_renting`. - Go to Rental > Orders > Rental Schedule. - Create a new rental order line from a cell of the gantt view, on a row…
Versions -------- 19.0 and later Steps ----- - Install `sale_stock_renting`. - Go to Rental > Orders > Rental Schedule. - Create a new rental order line from a cell of the gantt view, on a row grouped by a storable rentable product. Issue ----- The first line of the description of the created line is named "Bike (3 items)" instead of "Bike". Cause ----- The `display_name` override adding that quantity is keyed on the `in_rental_schedule` context key. That key is set on the `action_rental_order_schedule` action itself, so it is part of the search context and is propagated to every record, dialog and dropdown opened from the schedule, while it is only meant to flag that we are in the schedule (default values conversion, hidden onchange buttons, group expansion, ...). Solution -------- Introduce a dedicated `display_renting_stock_quantity` context key and depend on it instead when fetching data to build the gantt rows, leaving the records opened from the schedule with their regular display name.
This fix prevents electronic invoice generation from failing when the enterprise accounting add-on is not installed. It checks whether optional deferred billing date fields are available before using them, improving reliability for Community Edition users.
Original PR description
The fields `deferred_start_date` and `deferred_end_date` are created by the enterprise addon `account_accountant`, so not having it installed, this crashes with:
```
File "/opt/odoo/auto/addons/account_edi_ubl_cii/models/account_edi_cii.py", line 684, in <listcomp>
billing_start_dates += [move_line.deferred_start_date for move_line in invoice.invoice_line_ids if move_line.deferred_start_date]
AttributeError: 'account.move.line' object has no attribute 'deferred_start_date'
```
This PR protects the access to these fields checking first if they exist.
Bug introduced in the refactoring in #261572.
@Tecnativa TT64359
Forward-Port-Of: odoo/odoo#286245Vertical tabs in example setup dialogs now line up correctly, making the page easier to read. Longer tab names wrap neatly instead of disrupting the layout, which helps users navigate empty Project or UTM setup screens more reliably.
Original PR description
When a user opened a page with a vertical notebook, the tabs were not aligned with each other. Vertical notebooks should now have properly aligned tabs. If a tab title is too long, it will wrap onto the next line instead of breaking the layout. task-[5933892](https://www.odoo.com/odoo/project/4105/tasks/5933892) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes the display of vertical notebook tabs in dark mode so each tab is visually distinct. It improves readability and navigation for users working with pages that use this layout.
Original PR description
## Behavior Before the Commit When a user opens a page with a vertical notebook in dark mode, the different tabs aren't separate from one another. task-[5933892](https://www.odoo.com/odoo/project/4105/tasks/5933892)
The scheduled GST token refresh now correctly handles multiple companies instead of relying on a single company context. This helps ensure the next refresh is planned when any company token is successfully renewed, supporting more reliable GST reporting operations.
Original PR description
The `_cron_refresh_gst_token` method is called by a cron job. Previously, when scheduling the next cron execution, it checked `self.company_id.l10n_in_gstr_gst_token`. However, since the cron can process multiple companies, relying on `self.company_id` could result in incorrect behavior. In this commit, a flag is introduced to track whether at least one GST token was refreshed successfully. If a token was refreshed, the cron is scheduled to run again after 6 hours.
This fix ensures remaining hours on sales order lines for timesheet-based services are recalculated when relevant unit or availability details change. Businesses get more accurate project and service tracking without relying on manual refreshes or corrections.
Original PR description
The dependencies of _compute_remaining_hours do not match the fields actually used for the computation: it lists analytic_line_ids, which it never uses, and omits both remaining_hours_available, and product_uom. _compute_remaining_hours_available has the same issue: it uses product_uom but only depends on product_id.service_policy. analytic_line_ids, on the other hand, can be dropped: qty_delivered already depends on it, along with its so_line, unit_amount, product_uom_id and project_id, so the timesheet flow keeps triggering the recomputation. This PR fixes the dependencies for both aforementioned compute methods. Task-4748521 Forward-Port-Of: odoo/odoo#285685 Forward-Port-Of: odoo/odoo#284750
Odoo now handles requests with overly long web addresses more reliably. Instead of triggering an internal error while preparing the rejection response, the server safely returns the expected response, reducing noise and improving stability.
Original PR description
- When the request URI is too long, the HTTP server rejects the request before parsing the headers. As a result, `self.headers` is not available when the WebSocket compatibility code in `send_header()` and `end_headers()` is executed. - Access `self.headers` safely to avoid an AttributeError while handling the 414 response. **opw-6501275** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286330 Forward-Port-Of: odoo/odoo#285870
Paid French electronic invoices now automatically include the required due date in exports. This helps invoices comply with the latest French validation rules and reduces the risk of rejected submissions.
Original PR description
According the schematron v1.4, the cbc:DueDate is required when the move is PAID. "[BR-FR-CO-09/BT-23] : Si le cadre de facturation (BT-23) est B2, S2 ou M2, alors la date d’échéance (BT-9) doit être renseignée et correspondre à la date de paiement." no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286263
Fixed an issue in the HTML builder where some applied design options could be ignored when their priority was below zero. This helps ensure the editor correctly recognizes the selected option in composite actions, improving reliability for website editing.
Original PR description
The function `useSelectableComponent` looked for the selected option by searching for the option with the highest priority among the options that are applied. The search for highest priority implicitely excluded options with negative priority. This case happens with `composite` action when the inner actions have no definition of `getPriority`. This commit initialize the "highest priority found so far" as `-Infinity` instead of 0. task-5245362 Forward-Port-Of: odoo/odoo#286503
This fix ensures that user-specific settings are respected during bank reconciliation quick creation. It prevents inconsistent behavior when automatic statement processing settings differ between the user's session and the global screen state.
Original PR description
Since this commit: https://github.com/odoo/enterprise/commit/938978c622700f9de097d9ff163f5b3c043231ed We pass the auto_statement_processing context key to false when destroying the component. The problem is that for the quick creation we use the model context. It might happen that those two contexts are different and can create inconsistancy. This commit will make sure the user context has priority on the global state context. no task id
This fix stops users from accidentally creating API keys that are already expired, such as when copying example dates from documentation. It helps avoid confusing login or integration failures caused by unusable keys.
Original PR description
Prevent creating API keys that are already expired. One typical case is when you copy/paste the documentation and end up creating keys that are already expired, without noticing.
Selecting a suggested partner or company now correctly updates the form’s saved status after the record is enriched and saved. This prevents users from seeing save or discard buttons that appear active but do nothing, reducing confusion during partner entry.
Original PR description
Steps to reproduce: 1) open partner form view 2) type in the name field 3) select a suggestion from the autocomplete dropdown Issue: The record is enriched and saved, but the form still displays the save/discard buttons, and clicking them does nothing. The record dirty indicator is driven by 2 signals 1) `model.root.dirty`, which is cleared by save() call earlier in the onSelect() 2) the state `fieldIsDirty` of the `FormStatusIndicator` The second indicator is set to true when the user types in an input field, and selecting an option never clears it. The `setDirty` prop no longer exists, and therefore was deadcode. This commit emits `FIELD_IS_DIRTY` bus event, which is the only way to update the second indicator. With that, the indicator goes back to saved state once the record is updated. task-6475332 Forward-Port-Of: odoo/odoo#286268 Forward-Port-Of: odoo/odoo#285897