Wednesday, August 26, 2026
69 changes · master
Enhancements to existing features
Odoo now starts real-time notification subscriptions from a confirmed point instead of relying on a short replay window. This reduces the risk of missed updates after connection issues and avoids unnecessary message bursts after long inactivity.
Original PR description
*: im_livechat, mail, point_of_sale, pos_self_order, web, website_livechat. When the client subscribes to new channels, it passes its last known notification id as the starting point of the stream.…
*: im_livechat, mail, point_of_sale, pos_self_order, web, website_livechat. When the client subscribes to new channels, it passes its last known notification id as the starting point of the stream. For the very first connection, the last id defaults to 0. In this case, the server replays notifications from the last 50 seconds. This heuristic can lead to missed notifications (e.g. if the WebSocket fails to connect and retries exceed the window), or to a large useless dispatch when reconnecting after a long period of inactivity. This commit fixes both issues by having the client always start from an explicit, known-good id instead of 0. A topic fetches notifications starting from the lowest last id among its subscribers. If a single subscriber joins with 0 as its last_id, that 0 becomes the lower bound for the whole topic, and the 50s heuristic then applies to everyone sharing it, possibly excluding notifications the topic still needed. Providing a real id also fixes this issue. follow-up of task-5449503 enterprise: https://github.com/odoo/enterprise/pull/128917
This update makes Turkish e-Dispatch workflows easier by adding a single fetch action for XMLs and PDFs, improving upload placement, and naming files so they are easier to match. It also fixes commercial invoice status and banner behavior so users can correctly see whether a recipient response is pending, approved, auto-approved, or rejected.
Original PR description
## Description of the issue/feature this PR addresses: Fetch-button and matching UX improvements for e-Dispatch (receipts & deliveries), plus a fix to commercial (TICARIFATURA) invoice status…
## Description of the issue/feature this PR addresses: Fetch-button and matching UX improvements for e-Dispatch (receipts & deliveries), plus a fix to commercial (TICARIFATURA) invoice status handling and its response banner on account.move. ## Current behavior before PR: - "Upload e-Dispatch (XML)" is only available as a list-view toolbar button. - There is no single action to fetch e-Dispatch XMLs and then their PDFs. - "Update From GİB e-Dispatch (XML)" shows even when no XML is linked to the receipt. - Updating a receipt from its XML does not (re)fetch the matching Nilvera PDF. - Outgoing deliveries do not fetch the Nilvera PDF on status synchronization. - Fetched XML attachments are hard to match (no customer name in the name). - Commercial (TICARIFATURA) invoices that succeed without a recipient answer never reach the "succeed" status, and the commercial response banner (awaiting / approved / rejected) does not display correctly. ## Desired behavior after PR is merged: - "Upload e-Dispatch (XML)" is moved to the Actions menu on the list view. - A new "Fetch e-Dispatches" action fetches the XMLs and then the PDFs, in order (receipts and deliveries). - "Update From GİB e-Dispatch (XML)" is hidden until an e-Dispatch XML is linked. - Updating a receipt from its XML (re)fetches the matching Nilvera PDF. - Outgoing deliveries fetch the Nilvera PDF (via the Sale channel) on a successful status sync. - Fetched XML attachments carry the customer name for easier matching. - Commercial invoices persist "succeed" while awaiting the recipient's answer, and the awaiting / approved / auto-approved / rejected banners display correctly. task-6044179 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
HR will now automatically create company closure days for the next 12 months on a monthly schedule. The wording is also updated from public holidays to closure days, making it clearer that these days can cover any company-wide closure, not only official holidays.
Original PR description
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
Partner autocomplete now searches across additional company identifier fields, not just name or VAT. This makes it easier for users to find the right company using identifiers such as DUNS, improving data entry speed and accuracy.
Original PR description
We want to add the autocompletion feature on the multi-ids fields. Before, we could search by VAT number or by name. Now, we can search by name, VAT, or any field in the multi-ids (including DUNS) Related on IAP : https://github.com/odoo/iap-apps/pull/1755 Task-5367705
The icon picker in the website editor now searches Material Symbols on the server instead of sending the full searchable icon list to every browser. This reduces unnecessary page-load weight and makes icon searches feel more responsive, while also making icon font generation more consistent for future updates.
Original PR description
Enterprise PR: odoo/enterprise#127664 [REF] web: rename the webIcon "iconClass" key to "icon" --- __Before this commit__ - The `webIcon` object built from `ir.ui.menu.web_icon` exposed its first part…
Enterprise PR: odoo/enterprise#127664
[REF] web: rename the webIcon "iconClass" key to "icon"
---
__Before this commit__
- The `webIcon` object built from `ir.ui.menu.web_icon` exposed its first
part as `iconClass`, a leftover from the FontAwesome era.
- Since the Material Symbols migration that part is a `data-icon` name,
not a class: every reader passes it to `t-att-data-icon`.
__After this commit__
- The key (and the local variables around it) is named `icon`.
[IMP] html_editor: shorten icon search debounce
---
__Before this commit__
- `SearchMedia` hardcoded a 1000ms debounce, so the icon picker waited a
full second after each keystroke before searching.
__After this commit__
- `SearchMedia` accepts an optional `delay` prop (still 1000ms by
default, leaving the file/image selectors untouched).
- `IconSelector` passes `delay="250"` for a snappier pictogram search.
[IMP] html_editor, web: move ms icons list in backend
---
__Before this commit__
The Material Symbols list used by the media dialog's icon picker was a
generated JS module of ~152 KB for 446 icons, shipped in the assets
bundle to every browser on every page load. Most of that weight is the
`tags` search terms, only ever used to filter the list when the user
types in the picker.
__After this commit__
`generate_icons.py` writes a Python `MS_ICONS` dict in
`html_editor/controllers/ms_icons.py` instead of a JS module, and the new
`/html_editor/material_symbols_search` route searches it server-side
against a `name tags` index built once at import. It returns only
`{name, has_fill}`, so the tags never reach the browser.
The picker fetches the full list on start, then one filtered list per
search. Odoo UI icons (`oi_*`) are still read from the CSS rules and
searched client-side, since they are cheap to discover there.
`MediaDialog` rebuilds the pre-selected icon from the element's
`data-icon` attribute instead of looking it up in the full list.
[FIX] web, mail: make the icon font generation reproducible
---
__Problem__
Two runs of `addons/web/tooling/icons/generate_icons.py` on an unchanged
`icons_wishlist.txt` produce different font files, so a diff on those
binaries tells nothing about whether the icons actually changed.
__Reason__
- `detect_filled_variants` returns a `set`, whose iteration order varies
from one process to the next (string hash randomization). That order
is what gets handed to `fontext` as its ligature list, and `fontext`
numbers the glyphs it keeps in the order it is given them, so the
filled half of `glyf` is reshuffled on every run -- 242 of the 717
glyphs.
- `fontext` stamps `head.created` / `head.modified` with the current
time, and the `TTFont` reading its output recomputed `modified` once
more on save.
__Quick fix__
Sort the suffixed icon names before subsetting, and date the fonts only
when their content actually changed: `save_font` compares the newly built
font with the one already on disk, both with their `head` dates equalized,
and rewrites the same bytes when they match. `created` is kept for the
lifetime of the file, `modified` only follows a real change.
Rebuilding on an unchanged wishlist now leaves every generated font
untouched, so any diff on them means the icons really moved. The WOFF1
fallbacks and the `_pua_cmap` font are regenerated here, as they still
carried the old glyph order.Customer credit and debit notes in India can now be marked as either standard adjustments or price-only adjustments. This helps GST filings, e-invoicing, printed documents, and sales quantities correctly distinguish goods movement from value-only corrections.
Original PR description
Customer credit/debit notes are often issued to adjust prices without any movement of goods, for example, for a discount, rebate, or price revision without any change in quantity. This PR introduces…
Customer credit/debit notes are often issued to adjust prices without any movement of goods, for example, for a discount, rebate, or price revision without any change in quantity. This PR introduces an Adjustment Type field on customer credit/debit notes with two options: - **Standard:** Used when the adjustment involves a change in quantity, such as goods returned, cancelled service contracts, or additional goods supplied. - **Price Adjustment:** Used when the adjustment only changes the amount, with no change in quantity, such as a discount, rebate, or price revision. This distinction allows GST filing, EDI, and sales documents to correctly reflect whether an adjustment involves movement of goods or is purely a value correction. Changes included: - Add an Adjustment Type field on credit/debit notes. - Add the Adjustment Type field to the invoice report so users can clearly identify the type of credit/debit note. - Add Adjustment Type field on account move reversal wizard - For Price Adjustment moves, the EDI reports quantity and unit price as zero on each line while preserving the actual taxable value and tax amounts. - Exclude Price Adjustment moves from invoiced quantity computation in sales documents. task-6370202 Related enterprise Pr - https://github.com/odoo/enterprise/pull/126929 Related Upgrade Pr - https://github.com/odoo/upgrade/pull/11013
This change prevents deletion of records that are still linked to Indian e-Waybill documents, helping businesses avoid accidental loss of compliance-related information. It improves data integrity across invoicing and stock operations where e-Waybills are involved.
Original PR description
task-6445766 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Users can now use a middle-click on the expand button in form dialogs to open the record in a new browser tab. This makes it easier to keep the current workflow open while reviewing or editing related information separately.
Original PR description
This commit adds the ability to detect a middle click on the Expand button to the Dialog API. This is achieved through the `t-custom-click` directive. The expand callback function that is given to the Dialog API, will now receive two parameters: the event and whether it's a middle click. This commit also uses the new API to allow the FormViewDialog and x2ManyFieldDialog form dialogs to expand to a new tab. task-id: 5429014
Website links that open in a new browser tab now include hidden text or updated labels so screen readers can announce this behavior. This helps non-visual users understand what will happen before activating a link, improving accessibility and reducing confusion.
Original PR description
Screen readers generally do not automatically announce that a link opens in a new tab when a user navigates to it, creating a potential barrier for non-visual users who may become disoriented if the current page is replaced without warning. Solution: Add a visually hidden span inside a tags with target=_blank Task-6009931
Point of Sale no longer creates separate rescue sessions when orders arrive after a sales session has closed. Orders are now redirected to an available open session when possible, or staff are notified to reload and resync, reducing duplicate session handling and simplifying operations.
Original PR description
Rescue sessions are not created anymore. Before, they were use to store orders that were sync with sessions after these sessions were closed. Now if we try to sync an order with a closed session, it will either be synced with the current open session (if any) or raise an error if no valid session is available. After that, the frontend will receive a notification from the backend telling that the session is closed and will reload the page and then resync the orders with the new session. Rescue session is thus not needed anymore. task-id: 6332359 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Timesheet Assistant suggestions for Helpdesk tickets now show the actual ticket name and carry it into the timesheet form when added. This makes time entry faster and reduces mistakes caused by unclear labels or lost ticket details, while also avoiding incorrect grouping of unrelated events.
Original PR description
Before this commit, the Timesheet Assistant displayed static labels for Helpdesk Tickets. Furthermore, when a user clicked "Add" on a ticket suggestion, the Timesheet Inline Form did not auto-populate the ticket name, as the source ID was lost during the grouping phase. Task: 6320652 Forward-Port-Of: odoo/enterprise#121662
Quality reporting now helps teams compare how well vendors, products, and control points perform based on yearly pass rates. Buyers can see supplier quality information directly on vendor records, purchase requests, and quality control views, making sourcing and follow-up decisions easier.
Original PR description
Quality reporting did not provide a direct way to evaluate successful checks by vendor, product, or control point. This commit's changes: - Compute Quality Rate as the average pass percentage, with every quality check contributing the same weight regardless of control type. - Add partner and effective-date filters to Quality Check Analysis. - Show the yearly Quality Rate on partner forms and group its report by product. - Add an auto-installed Purchase/Quality bridge that shows the vendor's yearly Quality Rate on RFQs. - Add a Suppliers smart button on control points that opens yearly Quality Rate results grouped by partner. - Count distinct partners from incoming receipts as control point suppliers. task-6392885
Mexican payroll users now get a warning when paid payslips in a pay run are still waiting for their required Payroll CFDI. This helps employers issue documents within the legal deadline based on company size and avoid compliance risk.
Original PR description
RMF Rule 2.7.5 gives Mexican employers a limited number of business days after the payment date to issue Payroll CFDIs, depending on the company's headcount: 3 days up to 50 employees, 5 up to 100, 7 up to 300, 9 up to 500, 11 above. This adds a payroll warning on Mexican payslips in a pay run that are still waiting for their CFDI. One change in hr_payroll: issues were only computed for draft and validated payslips (plus paid ones with wrong data), but a CFDI deadline only starts running once the payslip is paid, so the warning vanished exactly when it mattered. _compute_issues now takes its payslips from a new _get_payslips_to_compute_issues() that localizations can extend. Default behaviour is unchanged, and the Mexican override adds a deliberately narrow set. task-6433985
Studio now uses the shared icon picker already used elsewhere in Odoo, making icon selection more consistent and easier to maintain. Users creating app icons or button boxes can also choose filled icon styles, while internal naming was simplified to better match the current icon system.
Original PR description
Community PR: odoo/odoo#278149 [IMP] web_studio: use the html_editor icon selector --- __Before this commit__ - Studio had its own icon picker (`StudioIconSelector`), a `SelectMenu` built on top of…
Community PR: odoo/odoo#278149 [IMP] web_studio: use the html_editor icon selector --- __Before this commit__ - Studio had its own icon picker (`StudioIconSelector`), a `SelectMenu` built on top of `IconSelector.initFonts()`. That helper is gone: the Material Symbols list now lives in the backend and the html_editor `IconSelector` fetches it on demand, so the whole list is no longer available client-side to feed a `SelectMenu`. __After this commit__ - The Studio component is dropped and the html_editor `IconSelector` is reused directly, wrapped in a `Dropdown` in both places that picked an icon: the app icon creator and the "add a button box" dialog. - The selection to highlight in the grid is rebuilt from the icon name alone, the same way `MediaDialog` does it since the list is fetched lazily. - The picker also offers the filled variant of the icons. It is stored by suffixing the icon name with "_f", which is the ligature of the filled glyph in the font: no renderer has to know about it. [REF] web_enterprise, web_studio: rename "iconClass" to "icon" --- __Before this commit__ - The app icon name was carried around as `iconClass`, from the `webIcon` object down to the `IconCreator` prop, a leftover from the FontAwesome era. - Since the Material Symbols migration that value is a `data-icon` name, not a class: every reader passes it to `t-att-data-icon`. __After this commit__ - The key and the prop are named `icon`.
Managers can now clearly see employees without active contracts in the Attendance Gantt view, where they are highlighted in red with a greyed-out row. The attendance form also shows a warning and links to the employee profile, helping teams resolve missing contract issues faster.
Original PR description
Previously, employees without contracts is not explicit from the attendance gantt view. This made it hard for managers to notice that someone was missing a contract and needed attention. Now these employees are visible with clearly flagged with a red name and fully grayed-out row according to conditions as user have self edit and attendance approver rights. On attendance form displays a warning that employee is not in contract and redirect to Employee Profile. task-6259306
Price adjustment credit and debit notes will no longer change quantity totals in Indian GST HSN reporting or subscription invoicing. This keeps reported quantities aligned with actual goods or services delivered, while financial amounts and taxes continue to be reported correctly.
Original PR description
Price adjustment credit/debit notes are created to adjust total amounts only, they do not alter quantities, since no goods are returned or additional goods supplied. This PR ensures such moves are consistently excluded from quantity-based computations across GST reporting and subscriptions. Changes included: - Exclude price adjustment moves from the HSN quantity in the GSTR-1 HSN summary, both in the generated spreadsheet (HSN sheet) and the JSON sent to the government portal. Taxable value and tax amounts remain unchanged. - Exclude price adjustment moves from sale subscriptions invoiced quantities task-6370202 Related community Pr - https://github.com/odoo/odoo/pull/279532 Related Upgrade Pr - https://github.com/odoo/upgrade/pull/11013
Bulk account assignment in bank reconciliation now completes much faster when many statement lines are selected. This reduces waiting time for accounting teams and makes high-volume reconciliation work more efficient.
Original PR description
Description =========== The bank reconciliation widget sends the bulk "Set Account" action as a single RPC, but the server still processes most of the work separately for every selected statement…
Description
===========
The bank reconciliation widget sends the bulk "Set Account" action as a single RPC, but the server still processes most of the work separately for every selected statement line.
Each iteration searches for recent statement lines and reconciliation models, writes the account on one move line, and posts its matching confirmation independently. The cost therefore grows linearly with the selection size.
Cache reconciliation-rule lookups for the duration of the bulk operation, while updating the cache when rules are created or deleted.
Also assign the account to all selected move lines in one recordset write, avoiding frequent calls to `_compute_reconciled_payment_ids` 1 by 1.
Finally, collect the lines requiring a matching confirmation and create their chatter entries in one batch.
Benchmark
=========
The benchmark measures one server-side bulk Set Account call; fixture creation is excluded from the timings.
| Selected lines | Before | After | Improvement |
|----------------|--------|-------|------------------|
| 500 | 12.5 s | 2.5 s | 5x faster (-80%) |
Benchmark data cardinality:
- 1 company
- 1 isolated bank journal
- 3 accounts: liquidity, suspense, and target expense
- 500 unreconciled bank statement lines
- 500 suspense move lines passed to the method, one per statement line
- 1 target account shared by all selected lines
- 1 journal/company/account cache group
- 1 batched call, executed sequentially in one cursor
- Negative amounts, avoiding automatic bank-fee rule creation
- 500 distinct references shorter than 10 characters, preventing a new reconciliation model from being created
- No taxes on the target account
Blueprint
=========
```xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--
==========================================================
BENCHMARK: Bulk Set Account on Bank Statement Lines
==========================================================
Creates 500 unreconciled statement lines in one isolated bank
journal, then calls set_account_bank_statement_line() once on the
whole recordset, as the bank reconciliation widget's bulk action does.
Negative amounts bypass the unrelated bank-fee rule path. Distinct
labels shorter than 10 characters prevent an automatic reconciliation
model from being created during the run. Without the bulk cache, the
first line only runs the history search and every subsequent line runs
both searches in _check_and_create_reconciliation_rule(). This keeps
the query-count regression visible without changing the scenario.
-->
<record id="benchmark_bulk_set_account_bank_statement_line" model="populate.blueprint">
<field name="name">Benchmark: Bulk Set Account on Bank Statement Lines</field>
<field name="definition_xml" type="xml">
<create model="account.account" count="1" id="bench_bulk_set_account_liquidity" scale="False" parallel="False">
<value name="counter" generator="misc.counter" start="1"/>
<field name="name" eval="f'Benchmark Bulk Set Account Liquidity {counter}'"/>
<field name="code" eval="f'BSAL{counter:03}'" unique="True"/>
<field name="account_type" eval="'asset_cash'"/>
</create>
<create model="account.account" count="1" id="bench_bulk_set_account_suspense" scale="False" parallel="False">
<value name="counter" generator="misc.counter" start="1"/>
<field name="name" eval="f'Benchmark Bulk Set Account Suspense {counter}'"/>
<field name="code" eval="f'BSAS{counter:03}'" unique="True"/>
<field name="account_type" eval="'asset_current'"/>
</create>
<create model="account.account" count="1" id="bench_bulk_set_account_target" scale="False" parallel="False">
<value name="counter" generator="misc.counter" start="1"/>
<field name="name" eval="f'Benchmark Bulk Set Account Target {counter}'"/>
<field name="code" eval="f'BSAT{counter:03}'" unique="True"/>
<field name="account_type" eval="'expense'"/>
</create>
<create model="account.journal" count="1" id="bench_bulk_set_account_journal" scale="False" parallel="False">
<value name="counter" generator="misc.counter" start="1"/>
<field name="name" eval="f'Benchmark Bulk Set Account Journal {counter}'"/>
<field name="code" eval="f'BSA{counter:03}'" unique="True"/>
<field name="type" eval="'bank'"/>
<field name="default_account_id" ref="bench_bulk_set_account_liquidity"/>
<field name="suspense_account_id" ref="bench_bulk_set_account_suspense"/>
</create>
<create model="account.bank.statement.line" count="500" id="bench_bulk_set_account_statement_lines" scale="False" parallel="False">
<value name="counter" generator="misc.counter" start="1"/>
<field name="journal_id" ref="bench_bulk_set_account_journal"/>
<field name="date" eval="'2026-08-18'"/>
<field name="payment_ref" eval="f'{counter:08x}'"/>
<field name="amount" eval="-100.0"/>
</create>
<function model="account.bank.statement.line"
name="set_account_bank_statement_line"
ref="bench_bulk_set_account_statement_lines"
batched="True"
parallel="False"
context="{'account_default_taxes': True}">
<value name="journal_id"
generator="relation.one"
comodel_name="account.journal"
ref="bench_bulk_set_account_journal"/>
<value name="suspense_account_id"
generator="relation.one"
comodel_name="account.account"
ref="bench_bulk_set_account_suspense"/>
<arg eval="[
line.line_ids.filtered_domain([
('account_id', '=', suspense_account_id),
]).id
for line in model.search([
('journal_id', '=', journal_id),
], order='id')
]"/>
<arg generator="relation.one"
comodel_name="account.account"
ref="bench_bulk_set_account_target"/>
</function>
</field>
</record>
</odoo>
```
Reference
=========
task-6480127The Pakistan localization now treats 18% GST for 3rd Schedule sale and purchase taxes as already included in the printed retail price. This prevents GST from being added on top of the listed price and aligns tax calculations with local rules.
Original PR description
Description of the issue/feature this PR addresses: 3rd Schedule goods in Pakistan are taxed on the printed retail price, which already includes GST. The sale and purchase "GST 18% 3rd" taxes in the Pakistani chart of accounts were configured as tax-excluded. Current behavior before PR: The 18% is added on top of the product's sales price. Desired behavior after PR is merged: The 18% is extracted from the retail price. task-6466479 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Point of Sale now asks the browser to protect offline sales data from automatic cleanup when a device runs low on storage. This reduces the risk of losing unsynced orders on PoS terminals, while keeping startup unaffected because the request runs in the background.
Original PR description
All PoS offline data, including orders not yet synced to the server, lives in indexedDB. By default this storage is "best-effort": when the device runs low on disk space, the browser is allowed to silently evict an entire origin's data. On a PoS terminal holding unsynced orders, such an eviction means losing those orders for good. This PR requests persistent storage with `navigator.storage.persist()` when the data service initializes indexedDB. When granted, the origin's storage is exempted from automatic eviction; data can then only be removed by an explicit user action. The request is best-effort: Chrome grants or denies it silently based on engagement heuristics (it is always granted for an installed PWA), Firefox prompts the user once. The call is therefore not awaited in the startup path and its outcome is only logged. See https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persist
The web interface’s underlying OWL framework was updated to a newer release. This helps keep Odoo’s user interface technology current and can bring stability, compatibility, and maintainability improvements without introducing a specific new business feature.
Original PR description
Release notes: https://github.com/odoo/owl/releases/tag/v3.0.0-alpha.47 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 Forward-Port-Of: odoo/odoo#284147
The website SEO dialog now detects when translated page content is out of date and prevents users from accidentally confirming translations they have not reviewed. This helps protect translation quality by asking users to review delayed translations in translation mode before editing related SEO image text.
Original PR description
1. Saving the SEO dialog no longer confirms delayed translations. They stay
delayed until the user saves from translation mode, where they can see what
they confirm. (Reverts the logic of 03fa781.)
2. The dialog now loads the page rendered with `edit_translations`, which is the
only render that marks delayed translations, and looks for one in `#wrap`
(the part the dialog reads its images from). When it finds one, it:
- covers the content checks with a message explaining the content is out of
date,
- keeps the alt inputs disabled
task-[6465390](https://www.odoo.com/odoo/project/974/tasks/6465390)Online shoppers can now choose multiple values within the same product filter, such as Lenovo or HP together with a specific storage size, instead of being forced into overly narrow results. The shop filter panel also behaves more consistently, keeping options visible and improving the placement of clear filters for a smoother browsing experience.
Original PR description
Filters are now completely exclusive, which prevent 0 results but also prevents more "open" searches as "Lenovo" OR "HP" AND "512GB SSD". Allow selecting attribute values that are not exclusive if its from the same attribute. Further improvements: 1. move clear filters to below attribute values 2. avoid closing the offcanvas if no products visible 3. avoid putting the selected attributes on top in the offcanvas 4. avoid hiding filters when no products available 5. avoid small displacement in the sidebar filters when selecting a value task-6341310 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Mail activities and messages now load search results in smaller chunks when a result limit is used. This helps affected views open reliably while still respecting access rules, reducing cases where pages stall because too many records are processed at once.
Original PR description
When a limit is applied in the search method, fetch the data in small batches like we do in ir.attachment. This allows to search with a limit on views while applying security access. Without this, simple views cannot be opened because the ORM searches for all records before filtering them in memory. Note that this cannot be avoided for group by queries and that if we don't set a limit, we will eventually still fetch everything in smaller batches. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284235 Forward-Port-Of: odoo/odoo#265203
Belgian payroll can now carry unused employment bonus amounts into the following month when vacation lowers an employee's pay. This helps ensure payroll calculations and related social security reporting reflect the full bonus entitlement more accurately.
Original PR description
Allow unclaimed employment bonuses to be carried over to the next month when vacation reduces remuneration during the month. - Add bonus carry-over salary rules - Update bonus calculations to include previous month amounts - Modify ONSS restructuring to account for carry-over Task Id: 6147223
The web interface now keeps the default grouping option visible in search filters again. This helps users see and manage preconfigured grouped views consistently, avoiding confusion from a recent change that removed that option.
Original PR description
This reverts commit 7413e08c166ef3123ac7ed6623db1fb366f44e3c (#265574) task-6425644 Forward-Port-Of: odoo/odoo#279043
Salary benefit list and form screens have been visually improved to make benefit setup easier to review and manage. The form now also checks numeric benefit values more clearly, helping users enter valid information and reducing setup mistakes.
Original PR description
Visual improvements for list and form views of salary benefits. Add benefit value check for float type in the form view. task-6253384
The messaging menu can now be customized so AI-related views can show their own tabs, such as Automation, and hide unnecessary counters when focused on a single agent. The update also improves Discuss reliability by ordering empty conversations consistently, preventing loading flicker, and keeping restored URLs in sync.
Original PR description
ai_app adds its own "Automation" tab to the messaging menu, shows only AI and Automation tabs when the menu is scoped to a single agent, and hides counters in that scoped view. None of that was possible: the tab list and counters were read straight from the store in the template. Move both behind component getters so they can be overridden. Also fixed: - sort threads with no message by channel creation date instead of leaving them in arbitrary order. - show the empty thread placeholder only once the thread is mounted and loaded, so it no longer flashes while messages load. - sync the discuss `active_id` into the action service state, otherwise `action.restore()` rebuilds the URL from a stale value. - Agent cards and the New button open the agent chat in Discuss, not a form, so adding them to the clickbot exceptions. task-6334162
Self-order and kiosk customers can now add a tip during checkout when online payment is enabled. This helps staff capture gratuities that were previously missed, with tips shown as a separate line on the order and receipt.
Original PR description
Purpose ------- Staff were losing potential tips because customers placing orders through the self-order or kiosk flows. Specification ------------- - Add a tip step to the self-order/kiosk checkout flow, available whenever online payment is enabled. - Customers can pick a quick tip percentage (15%, 20%, 25%) or enter a custom amount/percentage via a numpad popup. - The tip is added as a dedicated line and appears on the receipt. Task-6254832 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Report action screens have been reorganized to be easier for users to understand and manage. This reduces technical clutter when configuring reports, especially in accounting and printing-related settings.
Original PR description
Clean the views of ir.action.report to be more user friendly. Before this commit, the views were very technical oriented. Task [link](https://www.odoo.com/odoo/project.task/6285465) task-6285465
Report action views in Odoo Studio have been simplified to make them easier for users to understand. This reduces technical clutter and helps business users configure reports more confidently.
Original PR description
Clean the views of ir.action.report to be more user friendly. Before this commit, the views were very technical oriented. task-6285465
The FACe electronic invoicing option for Spanish public administration invoices is no longer selected by default, reducing unnecessary steps for most customers. When a user selects FACe for a specific partner, Odoo remembers that choice for future invoices to that partner.
Original PR description
1. The generic wizard was not meant to override correctly the default of extra EDI, this commit fixes this problem. 2. FACe is only relevant for public administrations, so keeping it checked by default added unnecessary noise for the majority of partners that never invoice through it. It is now unchecked by default. The first time FACe is selected for a given partner, the choice is remembered so it stays checked for that partner's subsequent invoices, avoiding the need to re-enable it manually each time. 3. Cleaning some dead code, in particular `_get_ref_string` was never called and should've used `_prepare_default_reversal` instead. task-6345379
Discuss now keeps voice calls inline instead of switching users into a full meeting view, while video calls and meetings still open fullscreen. The messaging interface is also simplified by removing duplicate reaction controls, clearing unnecessary breadcrumbs, and improving the messaging menu layout.
Original PR description
A few design feedback fixes in the Discuss UI:
- Voice calls no longer open the fullscreen meeting view. Starting or joining a call with the phone button now stays inline, both in Discuss and in the chat window. Only video calls and meetings go fullscreen.
- "Open in Discuss" clears the breadcrumbs. Keeping the trail of the app the chat window was opened from ("Events / Marc Demo") was only wasted space.
- Removed the add reaction button displayed next to the reactions of a message: it duplicates the "Add a Reaction" message action, which is always available on hover.
- Removed the w-50 on the messaging menu action button and search bar, so the button takes the width it needs and the search bar gets the rest.
task-6488704
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prBelgian payroll now captures additional apprenticeship employee details, including contract type and contract number. Wage checks and payroll reporting are updated to reflect apprenticeship-specific requirements, helping businesses improve compliance and reduce payroll validation issues.
Original PR description
- add contract types and number to Apprenticeship employees. - update wages checks to adapt Apprenticeship details. Task: 6331079
Deferred account reports now look up related accounts in batches instead of one at a time. This reduces unnecessary database work and can make report generation faster, especially for companies with many accounts.
Original PR description
Browse all source accounts at once when resolving their deferred accounts. This lets the ORM prefetch `deferred_account_id` instead of issuing one query per unique account. Introduced in https://github.com/odoo/enterprise/pull/122696
Hong Kong payroll rental allowance records now use a clearer proof expiry date and rely on the existing document attachment flow for proof uploads. HR teams can see the current rental proof expiry directly on employee records and confirm or reset multiple rental records at once, reducing manual work.
Original PR description
Remove the unused payment_proof_file field, superseded by the attach_document-based proof upload flow, and rename valid_up_to_date to "Proof Expiry Date" for clarity. Also surface the current rental's proof expiry on the employee form, and allow confirming/resetting multiple rentals at once from the list view instead of one by one. Upgrade PR: https://github.com/odoo/upgrade/pull/11039 task-6391432
Belgian payslips now show and use a clearer disposable earnings amount before salary attachments are applied. This makes it easier for payroll teams to verify attachment limits and account for external replacement wage amounts correctly.
Original PR description
Currently, the net amount before salary attachments is unclear, making it difficult to verify attachment limits on Belgian payslips. - Add 'NET_REPLACEMENT_WAGE' input rule for external replacement wage. - Add 'DISPOSABLE_EARNINGS' rule to compute net base for attachments. - Update 'ATTACH_SALARY' to calculate limits from disposable earnings. Task: 6410485
Point of Sale now preserves manually entered line prices in the same tax display mode used by the cashier. This prevents small rounding differences from growing on multi-quantity sales and helps refunds match the original sale amount.
Original PR description
A price set manually on an order line is typed in the tax mode the prices are displayed in. It was then inverted through the taxes to recover a price expressed in the tax mode of the taxes, and that…
A price set manually on an order line is typed in the tax mode the prices are displayed in. It was then inverted through the taxes to recover a price expressed in the tax mode of the taxes, and that result was rounded to the "Product Price" precision before being stored. With a "Tax-Included Price" display, typing 100 on a product taxed at 15% stored 100 / 1.15 = 86.9565... as 86.96. The residual rounds away at a quantity of 1, but it is multiplied by the quantity, so 2 units total 200.01 and 10 units total 1000.50. This commit stores the typed price as it was typed and adds a `document_tax_mode` field on the order line holding the tax mode that price is expressed in. The mode is passed when the base line is created, in the frontend as well as in the backend, so the taxes engine resolves the price inclusion per tax instead of the price being converted beforehand. It is reset as soon as the price is recomputed, so any other price keeps following the tax configuration of the product, and it is carried over to refund lines so that a refund matches what was sold. task-6472425 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
Restores the page state used when mobile bottom sheets, such as the blog mobile menu, are open. This fixes incorrect styling and prevents the page behind the sheet from scrolling, improving the mobile browsing experience.
Original PR description
Regression from #281432: the `bottom-sheet-open` class the bottom sheet plugin set on the body was removed there, following [a review comment of…
Regression from #281432: the `bottom-sheet-open` class the bottom sheet plugin set on the body was removed there, following [a review comment of mine](https://github.com/odoo/odoo/pull/281432#discussion_r3756639100) that wrongly concluded it was dead code — my grep missed `website.scss`, which keys the frontend bottom sheet styles on `body.bottom-sheet-open` and uses it to lock the page scroll behind an open sheet:
```scss
body.bottom-sheet-open {
--BottomSheetStatusBar__entry-background--active: #{$primary-bg-subtle};
...
// Prevent the page from being scrollable when a bottom sheet is open.
overflow: hidden;
}
```
Since then the blog mobile menu is styled wrong and the page scrolls behind the sheet on mobile.
This restores @jucop-odoo's original code from the PR, with two changes:
- `bottom-sheet-open-multiple` is not restored: nothing in odoo/enterprise ever read it.
- the count is decremented from the overlay's `onRemove`, which runs exactly once, rather than from the returned `remove`, which can be called several times for the same sheet.This update lets saved searches and default filters correctly use newer relative date options such as today or this week. It also improves date display consistency for locales using non-Western numerals and keeps older customized views from breaking.
Original PR description
In the previous [PR](https://github.com/odoo/odoo/pull/267980) we introduced relative filters (such as `today`, `this week`, ...) and removed the hardcoded filters that duplicated them…
In the previous [PR](https://github.com/odoo/odoo/pull/267980) we introduced relative filters (such as `today`, `this week`, ...) and removed the hardcoded filters that duplicated them (`3e7106201cfe`), for example:
```xml
<!-- BEFORE (planning/views/planning_views.xml) -->
<filter string="Start Date" name="start_datetime" date="start_datetime" end_month="1">
<filter name="start_today" string="Today" domain="[
('start_datetime', '<', 'today +1d'),
('start_datetime', '>=', 'today'),
]"/>
<filter name="start_this_week" string="This Week" domain="[...]"/>
<filter name="start_next_week" string="Next Week" domain="[...]"/>
</filter>
<!-- NOW -->
<filter string="Start Date" name="start_datetime" date="start_datetime"/>
```
However this would now break if trying to target the new relative filter:
```xml
<field name="context"> { 'search_default_start_datetime': 'custom_start_today' }</field>
```
(This example was not in production code but this PR tried to do it, and it broke on rebase:
https://github.com/odoo/enterprise/pull/125775)
In this PR we make it so that relative filters (not only today) can be activates through context keys and `default_period=`. We also make a number of small improvements / refactoring and 1 localisation fix.
**Commit 1** - [REF] web: tidy relative filter internals
- Make filter and option lookups throw on an unknown id instead of returning `undefined` and failing later.
- Centralize the "period + year" concatenation in one `joinWithYear` helper (2 call sites, one from the previous PR).
- Build `displayedFilterItems` in a single pass, attaching each date filter's relative twin to it.
- Drop a missed hardcoded "Today" in `stock_fleet`'s batch transfer view.
- Re-add the four range attributes to the RNG as deprecated-but-accepted, so a custo view no longer crashes.
(Will do a follow-up PR with an upgrade script to remove it)
**Commit 2** - [IMP] web, base: smart dates as date filter defaults
- Accept relative option ids in both `default_period` and `search_default_<filter>` (`today`, `this_week`, `this_month`, `this_quarter`, `this_year`).
**Commit 3** - [FIX] web: use the active numbering system for hand-built date labels
- The week number of the `formatLocalWeekRange` was not being translated to locale numbering system.
**Enterprise commit** - [REM] helpdesk, frontdesk: drop Today filters duplicating the smart date
- Remove the Today filters on Closed On / Creation Date / Rated On (helpdesk) and next to Date (frontdesk), that are redundant with the relative filters we introduced in the previous [PR](https://github.com/odoo/odoo/pull/267980)
Follow up to: https://github.com/odoo/odoo/pull/267980
Enterprise: https://github.com/odoo/enterprise/pull/128934When users start a timesheet timer from a task linked to a sales order item, the timer now automatically keeps that sales link and shows the billable option immediately. This prevents saved timesheets from losing billing information and reduces manual correction work.
Original PR description
**Problem:** Starting the timer on a task that is linked to a sale order item produces a timesheet that is not linked to it, and the Billable toggle is missing from the timer. **Steps to reproduce:**…
**Problem:** Starting the timer on a task that is linked to a sale order item produces a timesheet that is not linked to it, and the Billable toggle is missing from the timer. **Steps to reproduce:** 1. Install Timesheets and Sales 2. Open a task whose Sales Order Item is set 3. Start the timer from the Timesheets systray 4. Save it and open the resulting timesheet **Current behavior:** The Sales Order Item is empty. The Billable toggle only appears after removing and re-adding the task in the timer. **Expected behavior:** The timer is billable on the task's sale order item as soon as it is opened. **Cause of the issue:** `_get_timesheet_pre_filled_form_data` returns only `project_id` and `task_id`. The timer form merges that pre-fill over `timesheet_default_values`, which `lazy_session_info` computes once per session from `account.analytic.line.new()` - a record with no project and no task, so `so_line`, `allow_billable` and `has_available_so` are all `False` in it. Because the pre-fill carries none of those keys, they keep the task-independent session values: the timesheet stays unlinked from the sale order item, and the Billable toggle stays hidden since it is displayed from `has_available_so`. **Fix:** The pre-fill endpoint is the only place that knows which task the timer is being opened on, so it is where the task-dependent values have to be resolved. Reading them off a new timesheet built with that project and task keeps the endpoint generic - it returns whatever `_get_aw_timesheet_fields_specification` declares, so the sale fields stay owned by sale_timesheet_enterprise rather than being named in timesheet_grid. Dropping the session defaults instead was rejected: they are also the only source of `date`, `user_id` and `company_id` for the timer record, and removing them makes saving fail on the required Date field. opw-6423577 Forward-Port-Of: odoo/enterprise#127800
Financial reports now use a generic Date column instead of Invoice Date, so payments and journal entries show the relevant payment or entry date rather than appearing blank. This makes Aged Payable, Aged Receivable, and Partner Ledger reports clearer and more consistent for users reviewing balances.
Original PR description
- In Aged Payable and Aged Receivable show payment date for payments and journal entry date for misc entries instead of leaving them empty, just like Partner Ledger. - In Partner Ledger, Aged Payable and Aged Receivable, rename 'Invoice Date' column to 'Date', because former will be appropriate for invoice but in case of payment or misc entry, we'll show payment date or JE date. So more generic column name 'Date' is more appropriate. - In tests setup, move for month 11th is created before 10th and no invoice_date was being set, so in report invoice_date was empty, and in tests where we have sort by invoice_date ASC and where nothing is given report sorted it with creation date ASC , because invoice_date was missing. But now when we have added fallback for invoice_date, the report is using that Date column for sorting and therefore tests are modified to show 10th month entries before 11th. [task- 6467119](https://www.odoo.com/odoo/project/967/tasks/6467119)
The payroll employee card now shows the wage from the employee's contract for the relevant payslip period, rather than relying on the payslip value. This gives payroll users a more accurate historical view and correctly presents hourly wages without converting them to a monthly format.
Original PR description
The wage displayed in the payroll information was coming from the payslip itself instead of the employee's contract version at that specific period. And if the employee had an hourly wage, it was forced into a monthly format. This fetches the historical wage directly from the contract version linked to the payslip period and fixes the hourly display. task-6361600
Mexican payroll users can now refresh SAT status directly from a payslip. The change also ensures payslip tax documents are included in automatic SAT status checks, so validated CFDIs no longer remain shown as undefined in Odoo.
Original PR description
Add a new button to update SAT info on MX payslips. target: master task-6231563
This fixes an issue where the same contact assigned to sign multiple times could be prompted to sign again before other required signers had completed their turn. Signing requests now only show the next document to a user when it is actually their turn, helping businesses keep approval flows in the intended order.
Original PR description
### Steps to Reproduce: 1. Create a sign request and have 3 total signers (User, Customer, Employee) 2. Enable Signing Order and make the order as follows: (1) User, (2) Customer, (3) Employee But…
### Steps to Reproduce: 1. Create a sign request and have 3 total signers (User, Customer, Employee) 2. Enable Signing Order and make the order as follows: (1) User, (2) Customer, (3) Employee But make the User and Employee the same contact 3. Send and sign the request > Notice that (1) is able to sign for (3) immediately after, (2) has not signed yet. ### Description of the issue/feature this PR addresses: **Issue:** The signing order is ignored when the same user has to sign multiple times on a document, even if it is configured for a different person to sign in between. This happens because all signature request items are initialized in the 'sent' state upon creation, rather than strictly advancing based on the order. As a result, the system prematurely allows users to sign out of order and prompts them with their next turn too early. **Solution:** To resolve this, the controller was updated to include an `is_mail_sent = True` domain filter. This ensures that the UI's post-sign popup only displays documents where it is explicitly the user's active turn, rather than prompting a premature sign. ### Current behavior before PR: Users are able to sign prematurely, and the system will disregard the configured signing order. ### Desired behavior after PR: Users will only be prompted and able to sign a document when it is explicitly their turn, per the `mail_sent_order`. This way, documents are signed in order. opw-6417327 Forward-Port-Of: odoo/enterprise#128487 Forward-Port-Of: odoo/enterprise#125573
The Inventory Valuation report now includes accounting differences for products that currently have no stock on hand. This helps businesses spot and correct unbalanced valuation or variation accounts without losing the performance benefit of skipping full value calculations for zero-quantity products.
Original PR description
## Problem If multiple valuation/variation accounts are used, the Inventory Valuation report will not show the balance of accounts attached to products that have 0 quantity available if a different…
## Problem If multiple valuation/variation accounts are used, the Inventory Valuation report will not show the balance of accounts attached to products that have 0 quantity available if a different account has quantity. ## Solution In order to maintain the performance improvements intended by the commit that introduced the `qty_available != 0` filter, we will avoid calculating `total_value` for products with 0 quantity. We will still run `stock_accounting_value` on these products in order to capture interim accounting value on the Inventory Valuation report. ## Steps to Reproduce (Runbot v19) (defer to the test for more info) 1. Create an extra set of valuation/variation accounts 2. Create a product, avco perpetual accounting the default valuation/variation accounts 3. Create a second product, avco perpetual accounting the new valuation/variation accounts 4. Purchase 1 unit of each of the products and receive, bill both 5. Sell 1 unit of the product attached to the new valuation/variation 6. Go to Accounting > Review > Inventory Valuation, and note that the new valuation/variation accounts are not present. If you click Generate Entry, you will see that these accounts need to be balanced opw-6473319 Forward-Port-Of: odoo/odoo#283787 Forward-Port-Of: odoo/odoo#282819
This fixes an issue where users could not create custom fields from the technical settings after installing AI Fields. The system now ignores an empty model value submitted by the form, preventing an unnecessary validation error and restoring the expected setup flow.
Original PR description
**Steps to reproduce** - Install `ai_fields` - In debug mode, go to Settings > Technical > Fields - Trying to create any field results in a `Validation Error` **Cause** Commit ebeab340264af42450b74a76d69fc284b600f94c introduced a check on `model` to prevent a mismatch. `ai_studio` adds the `model` as an invisible field to the form, sending a `False` value to the `create`. https://github.com/odoo/enterprise/blob/bafa674d287577a0f32e08af165dd9561b1667c0/ai_fields/views/ir_model_views.xml#L39 **Change** Ignore `model` if it is `False` opw-6463182 Forward-Port-Of: odoo/odoo#283018
This fix restores the ability to delegate Studio approval responsibilities as intended. It helps teams keep approval workflows moving when the original approver is unavailable or responsibilities need to be reassigned.
Original PR description
opw-6321766 Forward-Port-Of: odoo/enterprise#128666 Forward-Port-Of: odoo/enterprise#122441
This fix prevents discounts from being counted twice when calculating withholding tax amounts. Businesses using withholding taxes will see more accurate tax totals on affected accounting documents.
Original PR description
When calculating tax details for `withholding_total_amount_currency`, the discount was already applied to `price_unit` before passing it to `_add_tax_details_in_base_line`. However, `_add_tax_details_in_base_line` already applies the discount itself. As a result, the discount was applied twice, causing the withholding amount to be calculated incorrectly. In this commit, remove the initial discount calculation and pass the original price_unit so that the discount is applied only once. ref- https://github.com/odoo/odoo/blob/master/addons/account/models/account_tax.py#L1804C9-L1804C34 task-6471414 Forward-Port-Of: odoo/odoo#282419
The accounting reports date filter now keeps the correct fiscal year when users switch between companies with different fiscal year calendars. This prevents reports from showing incorrect date ranges, helping businesses compare and review financial data more reliably.
Original PR description
Fix year-mode date filter when switching between companies with different fiscal years With two companies configured: one using a standard fiscal year and one using an offset fiscal year, switching between them could produce incorrect date ranges. This happened because the previous company’s `date_to` value was reused to compute the current period for the newly selected company, and vice versa. The fix is to use the `date_to` year instead and select the latest fiscal year ending in that same year. Forward-Port-Of: odoo/enterprise#127945 Forward-Port-Of: odoo/enterprise#117603
Point of sale orders using online payments now validate correctly after items are added or changed. The system updates the order total before checking payment status, preventing incorrect payment errors and reducing checkout disruption.
Original PR description
When products were added after selecting an online payment method and going back to the floor plan, the subsequent validation failed with "Invalid online payments" because the server's amount_unpaid was based on the old order total. Fix: sync the order to the server before querying amount_unpaid, so the server always has the latest total when checkRemainingOnlinePaymentLines is called. Also guard cancelPayment against calling the payment terminal interface on online payment methods that do not use one. task-id: 6330704 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The point of sale customer display now updates more consistently during checkout, ensuring shoppers see the latest order information. The change also reduces unnecessary refreshes and communication behind the scenes, improving responsiveness and stability.
Original PR description
Fixes customer display updates by moving the data format and preparation synchronously inside the useEffect hook. This allows OWL 3 to correctly register reactive dependencies, while only the final dispatch remains debounced (100ms). Optimizations: - Persist CustomerDisplayPosAdapter on Chrome. - Add JSON serialization diffing before dispatch to skip redundant RPC/broadcasts. - Use recursive deepUpdate in-place to avoid complete DOM re-renders. task-id: 6292603 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Point of Sale receipts now show the correct cash rounding line even when a customer pays more than the order total. This improves receipt accuracy and keeps payment totals consistent for cash transactions that require rounding.
Original PR description
**Steps to reproduce:** - Make a rounding method, Nearest and 0.05 of rounding - Make a product that costs $4.99, don't set a tax - Go to the PoS - Order the product - Before paying click the +10…
**Steps to reproduce:** - Make a rounding method, Nearest and 0.05 of rounding - Make a product that costs $4.99, don't set a tax - Go to the PoS - Order the product - Before paying click the +10 button, then pay - The rounding line is not present on the ticket **Why the fix:** When making a normal rounded purchase, by just clicking the "Cash" button, the rounding line will be displayed. This is because we do not try to apply the rounding if the rounding of the remaining is not equal to zero. https://github.com/odoo/odoo/blob/995629db3231de944710751c3184bf1b8b1355c7/addons/point_of_sale/static/src/app/models/accounting/pos_order_accounting.js#L118-L123 When we try to over pay, the remaining will be negative by the amount we overpay, so the amount will be set to zero, and the rounding will not be set. We now take the amount we overpay into account, and deduct it from the amount we paid to then correctly compute the remaining amount without having to deal with the amount overpaid. Some tests were not taking the rounding as it was not working correctly, so it has now been changed now that it works as it should. opw-6025807 Forward-Port-Of: odoo/odoo#283413 Forward-Port-Of: odoo/odoo#256117
Project margin reports now correctly exclude company-paid expense payment lines from revenue totals. This prevents expenses from appearing as positive “Other Revenues,” giving teams a more accurate view of actual project profitability.
Original PR description
Steps to reproduce --- 1. Install Sales (with Margins) and Project, and open a billable project linked to a sale order. 2. From the project's Expenses view, create an expense paid by the Company and…
Steps to reproduce --- 1. Install Sales (with Margins) and Project, and open a billable project linked to a sale order. 2. From the project's Expenses view, create an expense paid by the Company and post it. 3. Open the project's Actual Margins: the expense shows under Other Revenues as a positive amount. Issue --- Creating an expense from a project's Expenses view keeps `project_id` in the context until its journal entry is built. For a company-paid expense that entry is a payment, and `AccountMoveLine._compute_analytic_distribution` puts the project's analytic distribution on every line that is not receivable or payable, which also covers the Outstanding Payments liquidity line. An analytic amount is the opposite of the move line balance, so the negative liquidity balance becomes a positive analytic line, classified as Other Revenues, on top of the real cost already booked on the expense account. The receivable/payable filter from b6200026ecf1 narrowed the override introduced in ac1995ad6ddf but ignored the liquidity counterpart of a payment; since only profit and loss lines make up a project margin, restricting the distribution to `income` and `expense` accounts keeps the settlement line out of the report. https://github.com/odoo/odoo/blob/f037dead17eb6a74d1ea9c56b0861b285be17516/addons/sale_project/models/account_move_line.py#L10-L19 opw-6326551 Forward-Port-Of: odoo/odoo#283938 Forward-Port-Of: odoo/odoo#273273
This update fixes an issue where selecting a suggested word on mobile with Gboard could place the replacement text incorrectly and delete only part of the original word. It improves text editing reliability for users working in Odoo's HTML editor on mobile devices.
Original PR description
Before this commit: on mobile, when typing using Gboard and select a word suggestion will only delete the last character and put the new word at the beginning of the word to be replaced. This is because Gboard extends the selection to the text to be corrected, then deletes it, and inserts the corrected text. This flow falls in our previous fix for MS Swiftkey's delete backward, and wrongly uses cached old selection instead of using extended new selection from Gboard. After this commit: We strict the Swiftkey fix further, and only execute it when the cursor is at the beginning of the p element. Related commit: https://github.com/odoo/odoo/commit/822fd4e8fec7e114e6748dd8c9b4969f423fb290 task-6233756 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278266
The web interface now handles invalid filters on relational properties without crashing the editor. Users can still open the property settings to correct or remove the problematic filter, preventing them from being locked out of editing or deleting the property.
Original PR description
When a relational property has a domain the server cannot evaluate, opening its definition editor crashes. The editor calls search_count on that domain to show how many records match, both when it…
When a relational property has a domain the server cannot evaluate, opening its definition editor crashes. The editor calls search_count on that domain to show how many records match, both when it opens and on every later render. The server raises a ValueError and the call has no error handling, so the whole editor goes down. The bad domain stays saved on the property, so reopening the editor fails the same way and the property can no longer be edited or deleted. Wrap the search_count call in _updateMatchingRecordsCount (property_definition.js) in a try/catch and show no count when it fails. This is the only place the editor counts matching records, so guarding it here handles a bad domain from any source, the field selector or the code editor. The field selector still shows its warning on the invalid path, so the user can fix or delete the property. Steps to reproduce: 1. On a model that has a Properties field, add a Many2one property and set its Model to a model that itself has a Properties field. 2. Open the property Domain and click New Rule. 3. In the field selector pick the Properties entry, then close the selector. => An error dialog appears and the property can no longer be edited or deleted. Ticket [link](https://www.odoo.com/odoo/project.task/6101311) opw-6101311 Forward-Port-Of: odoo/odoo#283802 Forward-Port-Of: odoo/odoo#259886
This fix ensures Odoo correctly refreshes whether taxes and related accounting rules are marked as used when invoices, expenses, purchases, or point-of-sale records change. This helps prevent outdated tax status information from appearing in accounting-related workflows.
Original PR description
Currently, `is_used` is computed using queries on `account.move.line`, `account.reconcile.model.line`, etc. As a result, it has no depends and is not automatically updated when records in either model are created, modified, or deleted. This commit reverse M2M fields for respective models and use it as dependency to `_compute_is_used`. It also adds a missing dependency of `is_used` to `_compute_repartition_lines_str`. Forward-Port-Of: odoo/odoo#283406
Mentions in Odoo Mail now choose an active user account for each recipient instead of potentially selecting an archived account. This ensures mentioned people receive their inbox notifications reliably when they have both archived and active user records.
Original PR description
Before this commit, mentioning a partner that has an archived user sent the inbox notification to that archived user, so the mentioned person never saw the mention. This happens because the query picking the user of a recipient joins res_users without filtering on active, and keeps one row per partner with DISTINCT ON and no ORDER BY, so which row survives is arbitrary. One solution could have been to keep every active user of the partner, which is what we want as each of them has its own notification type, but a notification is stored per partner, so the type of a single user applies to all of them. Picking one user is a current limitation. This commit fixes the issue by taking the first active user of each partner in a lateral join, ordered as mail.followers._get_recipient_data already does: internal users first, then the lowest id. Forward-Port-Of: odoo/odoo#284214 Forward-Port-Of: odoo/odoo#283806
Aged Receivables and Aged Payables now calculate aging periods correctly when horizontal groups are applied. This prevents incorrect amounts from appearing in older-period columns, improving reliability of customer and vendor aging reports.
Original PR description
Problem: When using horizontal groups in Aged Receivables / Aged Payables reports, the amounts shown in the Older periods are incorrect. Steps to reproduce: 1. Activate debug mode 2. Go to Accounting…
Problem: When using horizontal groups in Aged Receivables / Aged Payables reports, the amounts shown in the Older periods are incorrect. Steps to reproduce: 1. Activate debug mode 2. Go to Accounting > Configuration > Horizontal Groups 3. Add a new horizontal group that results in at least 2 groups 4. Go to Accounting > Reporting > Aged Receivables / Aged Payables 5. Apply the horizontal group created 6. Notice how the amount in the Older period is incorrect, different from before applying the horizontal group. (It may be coincidentally correct, you can check by applying different aging intervals until you find one that shows the issue) Cause: The periods were not correctly calculated. The number of periods was calculated based on the number of period columns, without taking into account the number of column groups. When using horizontal groups, period columns are duplicated for each group that exists after applying the horziontal group. This is not considered when calculating the number of periods, which results in calculating too many periods and therefore having incorrect durations for each period. opw-6374639 Forward-Port-Of: odoo/enterprise#127570
This fixes monthly auto-planning so work slots can be scheduled through the last working day of the selected month. It prevents sales planning from under-scheduling hours due to timezone conversion issues, improving planning accuracy for service orders.
Original PR description
Steps to reproduce: --------------------------- 1. Install `sale_planning` with demo data. 2. Create a SO with a planning product, set the quantity to 100 hours, and confirm the SO. 3. Click the "To…
Steps to reproduce: --------------------------- 1. Install `sale_planning` with demo data. 2. Create a SO with a planning product, set the quantity to 100 hours, and confirm the SO. 3. Click the "To Plan" button, then click "Auto Plan". 4. Make sure the "Month" filter is selected in the scale options and observe the planned slots. Issue: -------- When auto planning slots for a month, the last day of the month is excluded. For example, slots are scheduled only until July 30th, even though July 31st is a working day. Cause: -------- While preparing the context, `stopDate` is set to July 31st at 00:00. It is then passed to [serializeDateTime()](https://github.com/odoo/odoo/blob/dacaad91bba8f959daf5d89a046c5a1c11e48eec/addons/web/static/src/core/l10n/dates.js#L553-L560), which converts the datetime to UTC. Depending on the user's timezone, this can shift the date to the previous day, causing the last day of the month to be excluded. Solution: ------------ Use `localEndOf()` to set `stopDate` to the local end of the selected range before passing it to `serializeDateTime()`. This ensures the last day of the month is preserved during UTC conversion. **NOTE:** Forward-port the solution from the 18.0 version, which was adapted to the publish shift use case in 18.3 and introduced this issue. Add a HOOT test case to prevent this regression in future versions. References: [18](https://github.com/odoo/enterprise/commit/bc3db24f83473d5646f7c2cfca8ed1c5b064ea2e) and [saas-18.3](https://github.com/odoo/enterprise/commit/c81fba31780869940f726b695ad46a87f69798fb) opw-6391495 Forward-Port-Of: odoo/enterprise#128775 Forward-Port-Of: odoo/enterprise#127950
Mexican point-of-sale global invoices now ignore cancelled refund orders when calculating refund amounts. This prevents valid invoices from failing when a cancelled refund exists alongside a paid refund.
Original PR description
Steps to reproduce: ------------------- 1. Install `l10n_mx_edi_pos` and set the company to Mexico. 2. In PoS, make an order with one product and pay it. 3. Open the order in the backend, click…
Steps to reproduce: ------------------- 1. Install `l10n_mx_edi_pos` and set the company to Mexico. 2. In PoS, make an order with one product and pay it. 3. Open the order in the backend, click "Return Products" to make a refund, but don't pay it, cancel it instead. 4. From the same order, click "Return Products" again to make a second refund, and pay it normally. 5. Go to the orders list, select the main order and the paid refund (not the cancelled one), then Actions > Create Global Invoice. -> Observation: error in the global invoice. In the CFDI tab of the main order the line is "Send Global In Error", and hovering on it the detail says "Failed to distribute some negative lines". Why: ---- When we make the global invoice, we remove the refunds from the order. A cancelled refund was never paid, so we should not count it. But we were counting it too. So we removed the refund amount twice in our case, one for the paid refund, and one for the cancelled one, and we end up with an order with negative amount that cannot be distributed. The fix: -------- We now skip the cancelled orders when we search the refunds, the same way it is done above when we collect the refunded orders. opw-6261404 Forward-Port-Of: odoo/enterprise#128026 Forward-Port-Of: odoo/enterprise#120996
This fix restores the default grouping behavior in Gantt views after it was unintentionally removed. Business users will see planned work grouped as expected again, reducing confusion when reviewing schedules and resource planning.
Original PR description
This reverts commit d35390a534fc60354a3c0174d6aa7cd158805f63 (#117918) task-6425644 Forward-Port-Of: odoo/enterprise#125983
Generated PDFs now render Arabic, Persian, and Hebrew text more reliably, including when mixed with English words or numbers. This improves readability of business documents for users working in right-to-left languages while keeping a safe fallback if the supporting library is unavailable.
Original PR description
# Summary Fixes incorrect rendering of Arabic/Persian/Hebrew (RTL) text in generated PDFs, especially when mixed with Latin digits or English (LTR). Uses python-bidi to compute display order and…
# Summary Fixes incorrect rendering of Arabic/Persian/Hebrew (RTL) text in generated PDFs, especially when mixed with Latin digits or English (LTR). Uses python-bidi to compute display order and introduces a safe fallback when that dependency isn’t available. # Problem - RTL strings were displayed in reverse order in PDFs. - Mixed content (e.g., Arabic + numbers/English) produced garbled ordering. - Existing logic flipped text only when the first character was RTL and no LTR chars existed, which broke mixed cases. # Solution python-bidi follows the Unicode Bidirectional Algorithm and correctly handles real-world mixed strings (Arabic + Latin + numbers + punctuation). Fallback ensures no hard runtime breakage on instances where new dependencies is missing. If python-bidi is missing, behavior is similar to previous “hotfix”: - Pure RTL: reverse text for legible display. - Mixed RTL/LTR: don’t reverse (favor readable English segments over fully correct RTL order). --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix ensures that approved leave properly clears negative extra hours created automatically for missing attendance. Employees and HR teams will see more accurate overtime balances when leave is added for a day that was previously marked as an absence.
Original PR description
Before this commit: --- When [`absence_management`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/res_company.py#L42) is enabled, a [scheduled…
Before this commit:
---
When [`absence_management`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/res_company.py#L42) is enabled, a [scheduled action](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/hr_attendance.py#L645) automatically creates an attendance record at [**12:00:00 AM**](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/hr_attendance.py#L649) to mark negative extra hours for employees with missing attendance.
<img width="1147" height="474" alt="image" src="https://github.com/user-attachments/assets/833a4387-bc20-4bb7-817d-9ebe9afa7d71" />
If an employee later creates a leave covering this autogenerated attendance, the extra hours should be reset to `0`. However, this does not happen.
#### Video demonstration:
https://drive.google.com/file/d/1DTNQuQ3uV5nOUVMBazCDo0hBZbKJZUIW/view
This happens because the [domain](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_holidays_attendance/models/resource_calendar_leaves.py#L8) used to fetch attendances for [`_update_overtime`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_holidays_attendance/models/resource_calendar_leaves.py#L34) compares the attendance `check_in` and `check_out` datetimes with the leave `date_from` and `date_to` datetimes.
The leave datetimes are aligned with the employee's working schedule. For example, if the working hours are **8:00 AM–5:00 PM**, the leave is stored from `{date, 8:00 AM}` to `{date, 5:00 PM}`. In contrast, the scheduled action creates the autogenerated absence attendance at **12:00:00 AM** (in the user's timezone). Since this attendance falls outside the leave datetime range, it is excluded from the domain, and `_update_overtime` is never called for it.
After this fix:
---
Instead of building the domain using the leave datetime range, the domain is built using the leave date range. This ensures that all attendances for the affected dates, including autogenerated absence attendances created at midnight, are included and their extra hours are updated correctly.
OPW: 6385811
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281123Odoo Studio now handles cases where fields shown on a form are generated behind the scenes and cannot be matched during view optimization. This prevents crashes when users edit affected accounting and Dutch reporting views, falling back safely instead.
Original PR description
* = account_invoice_extract, l10n_nl_reports Example of steps: - Install web_studio and `accountant` - Open the corresponding form view in Studio - With debug mode toggle "Show invisible Elements"…
* = account_invoice_extract, l10n_nl_reports Example of steps: - Install web_studio and `accountant` - Open the corresponding form view in Studio - With debug mode toggle "Show invisible Elements" and edit "Invisible" on the second partner_id field - Traceback `normalize()` compares the combined arch without the studio customization to the one with it, in order to compute the smallest possible set of xpaths. To do so, it calls `apply_inheritance_specs` (the low-level function from `odoo.tools.template_inheritance`) directly on the statically combined arch. Some models add or duplicate nodes dynamically in `_get_view()` (Python postprocessing, run after the static view combination). A studio operation can target such a node, since it is what the user actually sees and clicks on. But that node has no counterpart in the purely static combined arch used by `normalize()`, so `apply_inheritance_specs` raises a ValueError. `edit_view()` only catches `ValidationError` to fall back to an un-optimized (but valid) studio arch instead of failing the request. Since the low-level function raises a plain `ValueError` here, that fallback never triggers, and the exception is not caught anywhere. To fix this, we will keep the behavior from version 18.0 and catch the ValueError raised by `apply_inheritance_specs` in `normalize_with_keyed_tree` and re-raise it as a ValidationError, like `ir.ui.view.apply_inheritance_specs` already does elsewhere. This lets `edit_view()`'s existing fallback handle the case gracefully instead of crashing. Additionally, the two models responsible for the dynamically-added nodes described above are fixed at the source. `account_invoice_extract`'s duplicated `partner_id` field and `l10n_nl_reports`'s injected `company_id` field are now marked with `data-used-by`, the same attribute `_add_missing_fields` already sets in `ir_ui_view.py` for the fields it adds. Studio already skip rendering and computing xpaths for any node carrying this attribute (since https://github.com/odoo/enterprise/pull/92862), so these nodes are no longer exposed to the user and can no longer produce a studio operation that `normalize()` is unable to locate. opw-6332911 Forward-Port-Of: odoo/enterprise#127009 Forward-Port-Of: odoo/enterprise#122829
This fixes keyboard navigation in the Discuss Channels view so users can move from search results to channel cards without errors. It improves accessibility and lets users browse and open channels using arrow keys and Enter as expected.
Original PR description
**Description of the issue/feature this PR addresses:** ---------------------------------------------- Currently, in Discuss > Channels, pressing the down arrow while the search bar is focused raises…
**Description of the issue/feature this PR addresses:** ---------------------------------------------- Currently, in Discuss > Channels, pressing the down arrow while the search bar is focused raises a traceback instead of moving the focus to the first card. The channels kanban is rendered by a custom template written from scratch, which omits the t-ref="this.rootRef" of the standard kanban renderer, so this.rootRef() is null when the focus-view handler looks for the first card. A second traceback follows once the focus reaches a card, as focusNextCard looks for .o_kanban_group wrappers whenever the list is grouped, while the categories are rendered as plain rows, and the resulting empty list is then accessed by index. **Current behavior before PR:** ---------------------------------------------- - Pressing the down arrow from the search bar raises a traceback - Pressing the arrow keys again from a card raises a second traceback - Keyboard users cannot browse the channels kanban at all **Desired behavior after PR is merged:** ---------------------------------------------- - Pressing the down arrow from the search bar moves the focus to the first card - The arrow keys browse the cards in reading order, across categories - Pressing the up arrow on the first card returns the focus to the search bar - Pressing Enter on a card opens the corresponding channel - Keyboard navigation is consistent with the other kanban views Task-6439024 ---------------------------------------------- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Confirmed manufacturing orders now correctly update their operations when the related bill of materials changes. This prevents removed or edited production steps from staying incorrectly on existing orders, helping teams keep shop floor instructions aligned with the latest manufacturing plan.
Original PR description
### Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first…
### Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation on anything else than the company, name or workcenter - Go back to the MO, click the "Update Bom" button > The second operation is not unlinked and the first operation is not updated ### Cause of the issue: The `action_update_bom` updates the move raws and operations of the MO via the `_link_bom`: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L1214-L1218 For draft MO's all the work of these updates is done via the compute methods and by deleting all the records unrelevant to the new bom: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2603-L2626 And, in that case all the workorders that are not linked to an operation of the bom are expected to be deleted. However, when the MO is not in draft, the update of operations is expected to be performed here: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2647-L2664 However, since the operation of the bom has been deleted, the workorder that is expected to be deleted is not linked to any operation and hence does not satisfy the condition to be deleted: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2663-L2664 Concerning the non update of operations, it happens because the MO's operation are only updated on the three fields: `company_id`, `workcenter_id`, `name`: https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2647-L2664 https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2628-L2629 However, many other changes can and are actually relevant. ### Note: Prior to commit 80e6ed658fb43584bc2fad673ca40d9af6cf0ab6 operations were archived on boms rather than deleted: https://github.com/odoo/odoo/blob/4a5270218fe6fd7d30edb6d684b3340dc7423bab/addons/mrp/views/mrp_routing_views.xml#L53-L55 As such they would still be linked to an operation (but unrelated to the present values of the bom) and hence would fall into the condition of being unlinked from the MO. Since the bom operations are no longer archived there is no way to determine if an operation used to be linked to a bom and we therefore need to chose between deleting all operations unrelated to the present bom or to keep them all (when the MO has been confirmed). Enterprise: https://github.com/odoo/enterprise/pull/120709 opw-6285878 opw-6261738 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280803 Forward-Port-Of: odoo/odoo#269747
The mail system now checks and cleans message posting data before a message is created, based on the current user’s permissions. This helps prevent inappropriate or unexpected data from being included in discussions, improving reliability and data handling.
Original PR description
This change sanitizes some post data before allowing the post, making sure the data received by `message_post` is clean based on the current user. part of task-6452761 Forward-Port-Of: odoo/odoo#284201 Forward-Port-Of: odoo/odoo#280894
Confirmed manufacturing orders now correctly reflect changes made to their bill of materials when users choose to update them. This prevents obsolete operations from staying on production orders and ensures relevant operation changes are applied, reducing planning and execution errors on the shop floor.
Original PR description
Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation…
Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation on anything else than the company, name or workcenter - Go back to the MO, click the "Update Bom" button > The second operation is not unlinked and the first operation is not updated Cause of the issue: The `action_update_bom` updates the move raws and operations of the MO via the `_link_bom`: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L1214-L1218 For draft MO's all the work of these updates is done via the compute methods and by deleting all the records unrelevant to the new bom: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2603-L2626 And, in that case all the workorders that are not linked to an operation of the bom are expected to be deleted. However, when the MO is not in draft, the update of operations is expected to be performed here: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2647-L2664 However, since the operation of the bom has been deleted, the workorder that is expected to be deleted is not linked to any operation and hence does not satisfy the condition to be deleted: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2663-L2664 Concerning the non update of operations, it happens because the MO's operation are only updated on the three fields: `company_id`, `workcenter_id`, `name`: https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2647-L2664 https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2628-L2629 However, many other cahnges can and are actually relevant. Note: Prior to commit 80e6ed658fb43584bc2fad673ca40d9af6cf0ab6 operations were archived on boms rather than deleted: https://github.com/odoo/odoo/blob/4a5270218fe6fd7d30edb6d684b3340dc7423bab/addons/mrp/views/mrp_routing_views.xml#L53-L55 As such they would still be linked to an operation (but unrelated to the present values of the bom) and hence would fall into the condition of being unlinked from the MO. Since the bom operations are no longer archived there is no way to determine if an operation used to be linked to a bom and we therefore need to chose between deleting all operations unrelated to the present bom or to keep them all (when the MO has been confirmed). Community: https://github.com/odoo/odoo/pull/269747 opw-6285878 opw-6261738 Forward-Port-Of: odoo/enterprise#128120 Forward-Port-Of: odoo/enterprise#120709
Product videos in the website shop now load only when their carousel slide is shown, so the preview image loads at the correct size. This prevents blurry video thumbnails and improves the product page experience for shoppers.
Original PR description
Steps to reproduce: =================== 1. Add a video (e.g. a YouTube URL) to a product from the Sales app. 2. Open the product page on the website. 3. Slide the carousel to the video. => The video…
Steps to reproduce: =================== 1. Add a video (e.g. a YouTube URL) to a product from the Sales app. 2. Open the product page on the website. 3. Slide the carousel to the video. => The video preview cover is blurry. Root cause: =========== The product images are rendered in a carousel (the shop_product_carousel template in ) where only the first slide gets the "active" class; https://github.com/odoo/odoo/blob/af1b3ee2e7ac56a35bff5e030c3a831c27dbcf24/addons/website_sale/views/templates.xml#L3224-L3226 every other slide is "display: none". A product video is rendered as a live <iframe> inside its slide, so when the video is not the first media its iframe loads while its container has no dimensions (0x0). The embedded player then initializes as a small mobile player and loads a low resolution cover thumbnail (120x90), which looks blurry once the slide is shown at full size. Reloading only the iframe while the slide is visible fixes it, a full page reload does not. Fix: ==== Defer loading the video iframes located on hidden slides their src is moved to a data-src attribute on start and restored once the slide becomes visible. The player then initializes at full size and loads a high resolution cover. opw-6349394 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282508 Forward-Port-Of: odoo/odoo#274002