Wednesday, September 23, 2026
17 changes · 18.0
Resolved issues and error corrections
Messages received while a Discuss channel is opening are no longer lost from view. This ensures users see new activity promptly without waiting for a later refresh or fetch.
Original PR description
Before this commit, a message received while a channel opens in Discuss does not appear, and stays out of the thread until the next fetch. This happens because the channel opens on its last read message through `loadAround`, which replaces the message list with the fetched messages. The bus handler of a new message adds it to that list as long as the thread displays the present, so the replacement drops what arrived during the fetch. This commit fixes the issue by putting those messages back: in the list when it displays the present, in `pendingNewMessages` when it does not, where `fetchMoreMessages` already picks them up. https://runbot.odoo.com/odoo/error/947188
This fixes an issue where the email/chat reply suggestion list could reopen by itself after a user pressed Escape, preventing the reply from being discarded as expected. The change makes the interface respect the user's close action even if delayed search results arrive afterward, improving reliability in the mail composer.
Original PR description
Before this commit, the composer suggestion list comes back on its own after Escape closed it, as soon as the server answers the mention search. The re-opened list takes the next Escape, and the reply is never discarded. The test "reply: discard on pressing escape" fails that way on runbot: ``` Failed to find 0 of ".o-mail-Composer" (Timeout of 10 seconds). Found 1 instead. ``` This happens because NavigableList opens on every new set of options: the list first opens on the partners the store already holds, and the answer brings the ones it does not. The fetch is debounced by 250ms, so it lands between the two Escapes only on a loaded machine. This commit fixes the issue by ignoring the fetched suggestions once the user closes the list, until the search changes. Note that the test now flushes the debounced fetch right after Escape, so the race happens on every run. https://runbot.odoo.com/odoo/error/947267
This fixes an error that could stop certain electronic invoices from being imported when a fully discounted line still included an added charge and a fixed tax. The change makes invoice imports more reliable for these edge-case supplier documents and avoids duplicate tax handling during import.
Original PR description
In the special case when there is an invoice line fully discounted but having a charge and if and only if the related fixed tax is retrieved during the import, a ZeroDivisionError occurs. This fix also highlights another weird behavior. In this scenario, the fixed tax was marked twice as to be retrieved: - once in _import_invoice_retrieve_taxes - once in _import_ubl_invoice_line_add_taxes_values --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an unreliable automated test in the Mail app by waiting until the selected contact model is fully loaded before continuing. It helps prevent false test failures in Odoo's validation pipeline, improving release confidence without changing end-user behavior.
Original PR description
Before this commit, mail_template_dynamic_placeholder_tour could fail when the server answers the onchange of "Applies to" slowly: Tour mail_template_dynamic_placeholder_tour failed at step Check if…
Before this commit, mail_template_dynamic_placeholder_tour could fail when the server answers the onchange of "Applies to" slowly:
Tour mail_template_dynamic_placeholder_tour failed at step Check if
the dynamic placeholder popover is opened
(trigger: div.o_model_field_selector_popover)
This happens because the tour waits a fixed 200ms after picking "Contact" before typing "#" in the subject. The popover needs the model, and the record only holds the model once the onchange answers. On runbot the answer came after 230ms, so "#" showed the "select a model" notification instead of the popover.
This commit fixes the issue by waiting for the internal link button of the many2one, which only renders once the record holds the model.
Note that this step relies on "[FIX] web: cancel the pending search on autocomplete select": without it, a search still pending on the picked value marks the input as edited, which hides that button.
https://runbot.odoo.com/odoo/error/947209
Ref commit: https://github.com/odoo/odoo/pull/287888
Forward-Port-Of: odoo/odoo#290185This fixes an internal data model issue where certain calculated many-to-many fields could incorrectly keep a database relation. The change prevents unwanted cross-field side effects, helping keep related data reads accurate and predictable.
Original PR description
When we setup a many2many field which is not stored, it must not have a relation. This is already done for nonrelated fields, but we must do it also for related fields. Otherwise, we may have…
When we setup a many2many field which is not stored, it must not have a relation. This is already done for nonrelated fields, but we must do it also for related fields. Otherwise, we may have side-effects like finding sibling fields in 20.0: in the code below, reading categories would fill roles.
```py
model_id = self.env["ir.model"]._get("test_new_api.foo")
fields = [{
"name": "x_partner_id",
"ttype": "many2one",
"relation": "res.partner",
}, {
"name": "x_role_ids",
"ttype": "many2many",
"relation": "res.partner.category",
}, {
"name": "x_partner_category_ids",
"ttype": "many2many",
"relation": "res.partner.category",
"related": "x_partner_id.category_id",
"store": False,
"readonly": True
}]
for f in fields:
f["model_id"] = model_id.id
self.env["ir.model.fields"].create(fields)
env['test_new_api.foo']._fields['x_partner_category_ids'].relation # should be None
```
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#290067Turkish Nilvera e-invoices now count only actual product lines in the required line count field, instead of including tax, note, or other accounting lines. This helps generated invoices better match official documentation and reduces the risk of validation or compliance issues.
Original PR description
Currently, the LineCountNumeric node is filled as the length of `line_ids` which includes all the journal items on that move, including product lines, tax lines, note lines etc. The documentation explains that the node's value should be the number of product lines instead. This commit filters the lines to only use the product lines count. task-6584840 Forward-Port-Of: odoo/odoo#289178
This fixes an issue where a selection dropdown could reopen and remain visible after a user picked an item. It improves form reliability and prevents related automated checks from timing out.
Original PR description
Before this commit, the autocomplete dropdown of a many2one could open again right after a suggestion was picked, and stay open. The step of mail_template_dynamic_placeholder_tour waiting for it to…
Before this commit, the autocomplete dropdown of a many2one could open again right after a suggestion was picked, and stay open. The step of mail_template_dynamic_placeholder_tour waiting for it to close then times out:
FAILED: [8/36] Tour mail_template_dynamic_placeholder_tour
Step Wait for the drop down to disappear
(trigger: div[name="model_id"] .o-autocomplete:not(:has(.ui-autocomplete)))
TIMEOUT step failed to complete within 10000 ms.
This happens because the search filling the dropdown runs 250ms after the last keystroke, so a suggestion of the previous search can be picked while the next search is still scheduled. Picking a suggestion only closes the dropdown. The scheduled search then runs, opens the dropdown on the selected value, and nothing closes it after that.
This commit fixes the issue by discarding the scheduled search when the dropdown closes.
https://runbot.odoo.com/odoo/error/233574
https://runbot.odoo.com/odoo/error/237744
https://runbot.odoo.com/odoo/error/944454
https://runbot.odoo.com/odoo/error/945517
https://runbot.odoo.com/odoo/error/947141
Forward-Port-Of: odoo/odoo#287888Hungarian electronic invoice reports sent to NAV now leave out cash rounding lines, aligning the XML with local legal requirements. This prevents rounding adjustments from being reported as product or service lines and helps ensure compliant tax reporting.
Original PR description
Global cash rounding can be applied to customer invoices. Before this commit, the rounding would be included in the XML file sent to NAV. It would be included as a new invoice line (same as the products lines) and the ATK tax is applied on it. As stated in the legal Hungarian Documentation, an invoice line should always relate to the supply of a good or the service provided. In this case, a cash rounding (which is not a financial advantage or disadvantage) will be considered by the law as a settlement difference, that is not part of the invoice. So, this commit removes cash rounding lines from the NAV XML. Moreover, it uses base_lines for the amounts computation instead of line_ids. task-6527383
The web editor now skips channels a user cannot access instead of stopping the entire subscription process. This prevents one unavailable channel from blocking other real-time updates, improving reliability for users.
Original PR description
`_build_bus_channel_list` should never raise. Otherwise, the entire request is aborted, meaning the client fails to subscribe to *all* channels, including completely unrelated channels. Instead, if a client do not have permission to subscribe to a channel, the channel should just be skipped. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue in the HTML editor where clicking inside a link that contained formatted text could place the cursor in the wrong position. Users can now edit linked text more reliably, reducing frustration when working with formatted content.
Original PR description
Since #284197 a pointerDown event inside a formated link was not setting the selection in the correct position. We fixed the issue by getting the clicked element closest link to ensure we are effectively outside a link. task-6592373 --- Backport of #289945 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Employees assigned as Time Off approvers can now see the Time Off shortcut for the people they manage, even if they do not have broader Time Off access. This lets managers review and manage requests they are responsible for without needing extra permissions.
Original PR description
Issue: A user without any rights on Time Off should still be able to manage the requests of the users he's manager of. However, the computation for `show_leaves` only considers Time Off Officers/Admins and the employee themselves, while it should also consider the employee's Time Off approver. Fix: Include the employee's Time Off approver when computing `show_leaves`, allowing them to access the employee's Time Off smart button. Reproduction Steps: 1. Set a user (e.g. Marc Demo) to "No" for Time Off. Note: If reproducing in v19, Administrator rights on Employees are also needed to access the private employee form view where the issue occurs. 2. Set that user as another employee's Time Off approver. 3. Log in as that user and open the employee's form view. 4. Observe that the Time Off smart button is not visible. Related Tickets: opw-6445714 Forward-Port-Of: odoo/odoo#281589
Fixed an issue where copied images or attachments could remain connected to the original content instead of the page or record currently being edited. This keeps website and editor content in sync immediately and helps prevent confusing image updates after copying content.
Original PR description
When an attachment tied to one record was copied while editing content linked to a different one, the duplicate could keep referencing the original model instead of the new target, leaving the two out of sync until the next save. opw-6560233 Forward-Port-Of: odoo/odoo#287784
Users scheduling shifts across multiple companies will no longer see an access error when another company is inactive or unavailable. The overlap check now only considers shifts from the user's active company context, preventing crashes and avoiding exposure of inaccessible shift information.
Original PR description
Steps to Reproduce --- 1. Log in as a user with access to multiple companies (e.g., Company A and Company B). 2. Ensure both companies are ticked in the top-right multi-company widget. 3. In the…
Steps to Reproduce --- 1. Log in as a user with access to multiple companies (e.g., Company A and Company B). 2. Ensure both companies are ticked in the top-right multi-company widget. 3. In the Planning app, create a shift for an employee from 09:00 to 17:00 in Company B. 4. Remove the access of Company B 5. In the Planning Gantt view, click the same empty cell to schedule the same employee at the same time for Company A. Issue --- The _compute_overlap_slot_count method uses raw SQL to find overlapping shifts. However, this raw SQL fetches overlapping slot IDs from shifts belonging to companies the user has currently deselected or does not have access to. Current behaviour --- The raw SQL populates the conflicting_slot_ids field with inaccessible record IDs (the shift from the deselected Company B). This triggers accessError. Expected behaviour --- The system should only calculate overlapping shifts for companies the user currently has active in their environment. It should not leak the existence of shifts in deselected/unauthorized companies, and it should open the new shift dialog without crashing. Fix --- Add company_id to both raw SQL queries (for existing records and new virtual records) inside _compute_overlap_slot_count. Pass company id to ensure the database only returns conflict IDs that are valid within the user's active multi-company context. task - 4554813
German quarterly tax report XML exports now correctly include the reporting period field. This helps ensure submitted tax files contain the expected information when companies use quarterly filing.
Original PR description
The `Zeitraum` tag was not set when the tax return periodicity is `quarterly`. The `account_tax_periodicity` field defines `trimester` as the key for the `quarterly` label. In [account_generic_tax_report.py] though, the code compared the periodicity with the `quarterly` label instead of the `key` trimester. **Steps to reproduce**: - Install the `l10n_de_reports` module and switch to the DE Company. - Go to Accounting settings and set `Tax Return Periodicity` to `quarterly`. - Navigate to Accounting > Reporting > Tax Return. - Export the tax report as `XML`. - Open the generated XML file and observe the `Zeitraum` tag. [account_generic_tax_report.py]: https://github.com/odoo/enterprise/blob/338630decbec76580766dd3b38c3241ecfb4c77a/l10n_de_reports/models/account_generic_tax_report.py#L54 Ticket [link](https://www.odoo.com/odoo/project.task/6581536) opw-6581536
The Luxembourg reporting module now uses a working download link for the FAIA XSD file. This prevents failed or empty downloads and helps businesses access the required reporting schema reliably.
Original PR description
The old link points to a file with zero bytes. opw-6344914
Budgets now include analytic tax amounts posted on liability accounts, such as sales tax received. This fixes understated revenue and budget figures when analytic taxes are used, making budget reporting more accurate and consistent with purchase tax handling.
Original PR description
When a tax flagged "analytic" is used on an invoice, its amount also generates an account.analytic.line on the tax's own account (e.g. "Tax Received" for a sale tax), in addition to the line…
When a tax flagged "analytic" is used on an invoice, its amount also generates an account.analytic.line on the tax's own account (e.g. "Tax Received" for a sale tax), in addition to the line generated for the revenue/expense account. The budget report's _get_aal_query only kept analytic lines posted on income/expense accounts, plus asset_current/asset_non_current/ asset_fixed (added to also catch fixed asset purchases). Sale taxes are usually posted on a liability_current account, so their analytic line was silently excluded from the committed/achieved amounts of revenue and both budgets, while the equivalent purchase tax (posted on an asset_current "Tax Paid" account) was correctly counted on expense budgets. Mirror the existing asset-side handling on the liability side: - where_account_type now also accepts liability_current and liability_non_current accounts. - the new budget_profitability mirrors the _field_to_sql method and treats those liability accounts as revenue, the same way asset accounts are already treated as loss, without changing the shared analytic_profitability field on account.analytic.line. opw-6543933
Cancelling several deliveries at once now sends each carrier only the shipment that belongs to it. This prevents duplicate cancellation attempts and avoids carrier API errors or incorrect cancellations when different carriers are involved.
Original PR description
When cancelling shipments for multiple pickings with different delivery carriers, passing the entire recordset (self) instead of the individual picking to the carrier's cancel_shipment method causes each carrier to receive tracking references that do not belong to it. This results in API errors or silent wrong cancellations at the carrier level, and each shipment being cancelled N times instead of once, where N is the total number of pickings being processed. Forward-Port-Of: odoo/odoo#289809