Wednesday, August 26, 2026
59 changes · master
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/128934This fixes a display issue where the employee presence badge could appear in the corner of employee cards instead of on the avatar. The change keeps the badge styling limited to avatar layouts, improving visual consistency in HR screens.
Original PR description
Commit[^1] moved the badge's overlap styling out of a SCSS rule scoped to `.o_hr_employee_form_view … .o_employee_avatar` and into `additionalClasses` on the field registry entry. Those classes are…
Commit[^1] moved the badge's overlap styling out of a SCSS rule scoped to `.o_hr_employee_form_view … .o_employee_avatar` and into `additionalClasses` on the field registry entry. Those classes are applied unconditionally, so `position-absolute top-0 end-0 bg-light rounded-circle` leaked into every usage of the widget. On the kanban card the field sits in a non-positioned `float-end` div, so the badge resolved against `.o_kanban_record` and pinned itself to the card corner as a grey disc. A later commit papered over the symptom with `mt-1` (Commit[^2]), removed here. The overlap styling goes back to SCSS, scoped to `.o_employee_avatar` — the container marking the three "badge over picture" layouts, including the enterprise wizard the original rule missed. Also drops a `margin: unset !important` kanban rule left inert since the same refactor. task-6487546 [^1]: https://github.com/odoo/odoo/commit/dc8f38b1054664a0e382530bb4fc73983e2085cb [^2]: https://github.com/odoo/odoo/commit/fbae74ab0c6fa1d8fc0789b27bd60062a5bd29bf --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Rating snippets now keep their accessibility label in sync when the number of stars changes. This helps screen reader users understand ratings correctly across website pages and mass mailing content.
Original PR description
aria-label was not used correctly on s_rating snippet. Moreover, it was not updated when the number of stars is updated. Now, aria-label is updated correctly. Task-6009931
When 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
Businesses using only Point of Sale can now access the product variants setting from their POS configuration. This fixes a missing option that prevented OAF plan users from enabling product variants when no other related apps were installed.
Original PR description
If only PoS is installed (if you are on the OAF plan). The variants settings is unavailable and cannot be activated. Steps to reproduce: ------------------- * Install only PoS * Look for variant in settings > Observation: The option is not showing up Why the fix: ------------ The setting is just a copy of the other places where the settings is available. opw-6378568 Forward-Port-Of: odoo/odoo#276179
This update fixes an issue that could cause certain employee searches to fail or return incorrect results for users without access to private employee data. It helps ensure HR search behavior remains reliable while preserving existing access restrictions.
Original PR description
The hack to search fields as a user that has no access to private employee data and searching on the `current_version_id` instead of the provided field since we force to wrap searchable fields domains in a Query in odoo/odoo#280373. The hack did not support usage of the 'any!' operator on `current_version_id` leading to a query like: "hr_employee.id in (select id from hr_version ...)". task-6468820 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284271 Forward-Port-Of: odoo/odoo#283811
A test that simulates buying a rental product on the website has been temporarily disabled because the related rental planning flow is still changing. This avoids repeated false failures while the final process is being settled, with no direct change to customer-facing features.
Original PR description
Given the rapid changes in spec for `{website_}sale_renting_planning` it doesn't make sense to fix the tour only for the flow to break right away after. Therefore, the tour is temporarily disabled until the flow of the module(s) is finalized.
task-6389324
Forward-Port-Of: odoo/enterprise#128170This fixes a display problem that could stop contact or user avatars from loading when their last update date was missing. Users should see a more reliable interface in forms and kanban views instead of encountering an error.
Original PR description
Issue: The `Many2OneAvatarField` and `KanbanMany2OneAvatarField` templates were directly calling `value.write_date?.toMillis()`. Optional chaining does not handle the case where `write_date` is `false`, resulting in a `TypeError` because `toMillis()` is not available on a boolean value. Solution: Added a `uniqueId` getter in both `Many2OneAvatarField` and `KanbanMany2OneAvatarField` to safely handle a missing or false `write_date`. The getter calls `toMillis()` only when `write_date` is available and returns `undefined` otherwise. Both templates now use `uniqueId` for the avatar URL. opw-6464172 Forward-Port-Of: odoo/odoo#284015 Forward-Port-Of: odoo/odoo#282659
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 fixes an error that could stop customers from generating batch payments. The payment file creation process now uses the correct address-cleaning logic, helping users complete payments without disruption.
Original PR description
The aim of this commit is to allow customer to make their batch payment without facing a Traceback. Context: odoo/enterprise@35f5341b9b44cc16eaea311295a064189dd802cb introduced bug during a badly…
The aim of this commit is to allow customer to make their batch payment
without facing a Traceback.
Context:
odoo/enterprise@35f5341b9b44cc16eaea311295a064189dd802cb introduced bug
during a badly handled forward port.
The method was removed in saas-18.3 in favor of a function. The forward-port
was half handled and now surfaces to Odoo's own production.
Generating a batch payment could generates the following Traceback:
```py
File "/home/odoo/src/enterprise/saas-19.3/account_iso20022/models/account_journal_sepa_ct.py", line 69, in _get_PstlAdr
return super()._get_PstlAdr(partner_id, payment_method_code)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.3/account_iso20022/models/account_journal.py", line 501, in _get_PstlAdr
CtrySubDvsn.text = self._sepa_sanitize_communication(partner_address['state'][:35])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'account.journal' object has no attribute '_sepa_sanitize_communication'
```
Task-id: None (internal issue)
Forward-Port-Of: odoo/enterprise#129084
Forward-Port-Of: odoo/enterprise#129006This 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 Sign app no longer replaces existing rules that control when the Mark Done button is shown in the activity scheduling wizard. This prevents the button from appearing in inappropriate cases and avoids conflicts with other apps that also manage its visibility.
Original PR description
Previously, the sign module was completely overwriting the `invisible` attribute on the "Mark Done" (`action_schedule_activities_done`) button in the activity schedule wizard. This inadvertently discarded base conditions (such as hiding the button when `has_error` is true) and caused conflicts with other modules (like `calendar`) that also need to modify this button's visibility. This commit updates the view inheritance to safely append the sign condition using `add` and `separator="or"`, preserving all existing visibility rules. Task-6499751 Forward-Port-Of: odoo/enterprise#129005
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
This fix keeps accountant knowledge PDF navigation working across newer and older PyPDF versions. It reduces the risk of errors when generating or processing PDF documents after library updates.
Original PR description
On latest versions of PyPDF, the `outlines` attribute was renamed to `outline`, we now handle both attributes to provide compatibility with both versions. A similar issue arises with the `addLink` method, which was renamed to `add_link`, and later replaced by `add_annotation`. Another similar issue arises with the `add_bookmark` method, which was replaced by `add_outline_item`. task-6474715 version-19.4 Forward-Port-Of: odoo/enterprise#127074
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
The image editor toolbar now shows the Wrap text icon correctly when users adjust image alignment. This removes a small visual glitch that could make the option look missing or unavailable.
Original PR description
### Steps to reproduce: - Insert an image in the HTML Editor (e.g. via /media). - Select the image and click on the alignment dropdown option in the toolbar. - Observe that the `Wrap text` icon is invisible. ### Purpose of this PR: - The `Wrap text` icon was set to `text_wrap`, which is an invalid Material Symbols icon name and was missing from the font subset. This PR fixes the issue by updating the icon to `format_image_left` in `image_plugin.js` and `oi_to_ms.scss`, adding `format_image_left` to `icons_wishlist.txt`, and regenerating the icon font subset. task-6448292 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes a website builder issue where connection shapes could switch to black or white when adjacent sections used the same background color plus an image or video. Shapes now keep the intended matching color, making page designs more consistent for editors and visitors.
Original PR description
When the user has not set a specific color to a connection shape, and changes the background color of the connected block, the builder automatically updates the color of the shape to match. There is an exception if the color of the shape is the same as the one of its block (in that case it uses a contrasting color). This commit removes the exception if the block also has a image background or a video background (because those will cover the color background once loaded, so that background does not really count) Steps to reproduce: - Open website builder - Drop a block - Set a color as "Background" - Set an image as "Background" (or a video) - Click on the "Shape" option and select a one in "Connections" - Drop a second block - Set the same color as "Background" - Bug: the shape get a contrasting color (black or white) instead of the background color of the neighbor task-6483027
This fixes a small styling issue in the HTML editor’s link popup by removing an invalid layout setting. The popup should continue to behave as before, with cleaner underlying code and reduced risk of browser styling quirks.
Original PR description
This PR aims to remove the unnecessary max-width property having invalid unit value from `link_popover.xml`, as the existing behavior is correct without it. --- 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
The website link tracking page no longer shows SEO optimization, page properties, or link tracker menu actions that are not useful for visitor-facing content. This reduces confusion for website editors and keeps management options focused on pages where they add value.
Original PR description
Since [this commit][1] you're able to optimize the link tracker page using "optimize seo." This makes no sense as it contains no useful content for visitors to the website. Access to the action is now disabled when the current page is the link tracking page. The page properties and link tracker menu items have also been removed for similar reasons. [1]: https://github.com/odoo/odoo/commit/ac55f2bb113ecf7c774fe6e96d28e716184a97d1 Task-6288891 Forward-Port-Of: odoo/odoo#283954 Forward-Port-Of: odoo/odoo#278132
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
When users insert dynamic fields in the HTML editor, related fields now default to a readable display name instead of a technical ID. This makes generated content clearer while still allowing users to choose the ID field when needed.
Original PR description
*: project Before this commit: when clicking a field having sub fields (canFollowRelationFor is true), we just return this field's id, which is not very useful in most cases. After this commit: We created subclass of DynamicPlaceholderPopover, EditorDynamicPlaceholderPopover, which uses EditorModelFieldSelectorPopover. We use the display name of the followable field by default and if the user really want the id, they may choose the id subfield. We also show the followable field's name as the default placeholder instead of "Display name". task-6265223 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283748 Forward-Port-Of: odoo/odoo#272129
When the cookie banner remains enabled, clearing the cookie policy page now restores the default policy page instead of leaving the website without one. This prevents administrators from losing access to the setting and helps keep cookie-related website configuration consistent.
Original PR description
Steps to reproduce: - enable the cookies bar in the website settings and save - clear the "Cookie Policy Page" field and save The website was left without a cookie policy page while the cookies bar was still enabled. Since the settings view only displays the field when it has a value, it disappeared with no way to set it back, other than toggling the cookies bar off and on again. The default policy page was only restored when the `cookies_bar` flag itself changed, so a write clearing only `cookie_policy_id` slipped through. Restore the default page whenever the policy is emptied while the cookies bar remains enabled, so the field reappears with the default page after saving. task-6356766 Forward-Port-Of: odoo/odoo#273901
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 prevents Accounting payment terms from crashing when a user enters zero or negative day values for end-of-month due dates. Instead of showing a technical error, the system can now handle the calculation safely and show the appropriate validation message when the record is saved.
Original PR description
Steps to reproduce: - Install `Accounting` module - Payment Terms > Create NEW - Add a new Due Term line with "Days end of month on the" and a negative amount of days(eg: -1) Traceback: `ValueError: day is out of range for month` When `days_next_month` is set to a negative value, it is passed directly to `relativedelta` as the 'day' value. Since a negative value is not a valid day of the month, the due-date computation raises a `ValueError`. Use the end of the month for the calculation when `days_next_month` is non-positive. This prevents the traceback while computing the payment term and allows the proper validation error to be raised when the record is saved. opw-6453640 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283865 Forward-Port-Of: odoo/odoo#281904
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
This fix prevents Belgian Intrastat reporting from crashing in rare cases where company data is accessed without the expected permissions. It mainly protects future customizations or edge-case setups, with no expected change for normal day-to-day use.
Original PR description
Due to some trouble with tests, we found that in some cases, this function is called on the root company, and if the user does not have the access rights to read data from the company (users with system rights have them by default), it will cause a crash. This situation is not possible with the standard UI, but we fix it in case it becomes possible in a future version or customization. Forward-Port-Of: odoo/enterprise#128212
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
The AI livechat snippet now has a preview image again, so it displays correctly before the feature is installed. This helps website editors recognize and choose the livechat block more easily in the website builder.
Original PR description
Problem: 1) The preview image of the livechat snippet was removed in this [commit][1] and wasn't replaced with another image. As a result, the uninstalled livechat snippet doesn't display properly in the website builder. Solutions: 1) An image has been added `ai_livechat.png` which is shown on preview Note: This fix will change in master to be up to date with current website snippet previews. The location will be moved to `snippet_previews` and the file type will be changed to `.webp` [1]: https://github.com/odoo/enterprise/commit/df05441e469157890253b5550b5f8735723b28fb Task-5248712 Forward-Port-Of: odoo/enterprise#126361
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
This fix updates a payroll test so it checks only rows containing payroll data, instead of counting automatically added blank rows. This prevents false test failures and helps keep payroll release validation stable.
Original PR description
Issue: The original trigger was searching for 2 table rows, when it enforces 4 with added empty rows. The [getEmptyRowIds](https://github.com/odoo/odoo/blob/33dc65bbac165f33030ad3da59ea785b69482b3f/addons/web/static/src/views/list/list_renderer.js#L1104-L1110) enforces max of 4 rows. The condtional (one up the stack) !ctx["this"].props.list.isGrouped&&!ctx["this"].props.noContentHelp returns true, and it adds empty rows. Fix: Since this enforces 4 rows with empty rows we check the rows that have data instead of how many rows are added. Because anything less than or equal to 4 but greater than 0 records it will always be 4 table rows while the conditional above returns true . opw-6349513 <img width="1337" height="674" alt="Screenshot 2026-07-15 at 4 53 51 PM" src="https://github.com/user-attachments/assets/76f53521-ec9f-4807-9083-95533904b5de" /> Forward-Port-Of: odoo/enterprise#127531 Forward-Port-Of: odoo/enterprise#125091
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
The mass mailing feature now correctly excludes temporary wizard screens from the list of models that can be used for mailings. This prevents inappropriate or unusable system objects from appearing as mailing targets, improving reliability and reducing confusion.
Original PR description
The search function ` _search_is_mailing_enabled` mistakenly used `model.is_transient()` (where the model is the `ir.model` record itself) to filter the transient models, which always returns `False` since `ir.model` is a regular persistent model. As a result, transient models (wizards) were never filtered out. This commit fixes it by using`self.env[model.model].is_transient()` to call `is_transient` on the actual model. Task-6458883 Forward-Port-Of: odoo/odoo#283781 Forward-Port-Of: odoo/odoo#282783
The HTML editor now places the drag-and-drop move handle on the correct side when users work in right-to-left languages. This improves editing usability and visual consistency for languages such as Arabic or Hebrew.
Original PR description
Problem: In MoveNodePlugin, `setMovableElement` sets the position of the drag-and-drop handler without considering `this.config.direction === "rtl"`. The handler is placed on the left side regardless of text direction. Solution: - In RTL mode, calculate the handle position from the right edge of the element so it is placed on the right side with the same distance as in LTR. - Update hover hooks, editable bounds, and dropzone rectangles for RTL mode. Steps to reproduce: 1. Open the editor in RTL mode. 2. Hover over a movable block element (e.g. `<p>`). => The move handle appears on the left side of the element instead of the right. task-6442717 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284190 Forward-Port-Of: odoo/odoo#281249
The HTML editor now keeps background colors when users turn colored text into lists or turn list items back into regular paragraphs. This prevents formatting from unexpectedly disappearing and makes document editing more consistent.
Original PR description
Problem: Background color was lost both when converting text with a background color into a list item and when converting a list item with a background color back into a paragraph. Cause: - `insertListAfter` only copied `color` from the font wrapper to `li.style.color`, ignoring `background-color`. - Unwrapping a list item (`ListPlugin`) extracted `color`, `font-size`, and `text-align`, but ignored `backgroundColor`. Solution: - Preserve `background-color` from font wrapper onto `li.style.backgroundColor` when creating a list. - Restore `li.style.backgroundColor` onto a `<font>` wrapper when unwrapping a list item. Steps to reproduce: - Apply background color to a paragraph and toggle list -> background color is lost. - Apply background color to a list item and toggle list off -> background color is lost. opw-6481665 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283158
The ecommerce product comparison page now shows the product tags table only when at least one tag is visible to shoppers. This prevents customers from seeing an empty specifications section when products only have hidden tags.
Original PR description
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the…
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the surrounding table remains rendered and appears empty. Only display the tags table when at least one tag is visible on ecommerce. @Tecnativa TT63855 **Description of the issue/feature this PR addresses:** The condition used to display the product tags table considers all tags associated with the product, including those that are not visible on ecommerce. **Current behavior before PR:** When a product only has non-visible tags, the tags table is displayed without any content. <img width="669" height="350" alt="image" src="https://github.com/user-attachments/assets/4758ea76-5186-4035-a065-aa4c71ce7053" /> **Desired behavior after PR is merged:** The tags table is only displayed when the product has at least one tag visible on ecommerce. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282348 Forward-Port-Of: odoo/odoo#278604
This fixes an issue where Australian tax reporting data could fail if the optional Australian reports module was not installed. The change keeps report calculation logic aligned with the module that provides it, improving reliability for Australian localization setups.
Original PR description
We had a case where l10n_au and account_reports were installed together, but not l10n_au_reports (manually uninstalled ?). Since the custom engine was used on expressions in l10n_au, this failed. Custom engines should always be used and declared within the same module (or a submodule of the one defining the handler) to avoid such issues. opw-6451274 Forward-Port-Of: odoo/odoo#282790
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 fix keeps Australian report-specific calculation logic within the same reporting module that provides it. This prevents errors when Australian localization is installed without the optional Australian reports module, improving reliability for affected configurations.
Original PR description
We had a case where l10n_au and account_reports were installed together, but not l10n_au_reports (manually uninstalled ?). Since the custom engine was used on expressions in l10n_au, this failed. Custom engines should always be used and declared within the same module (or a submodule of the one defining the handler) to avoid such issues. opw-6451274 Forward-Port-Of: odoo/enterprise#128132
This update prevents a rare crash in Hungarian Intrastat reporting when company data is accessed in unusual permission scenarios. It helps keep reporting stable for future customizations or edge cases, even though the issue is not expected through the standard user interface.
Original PR description
Due to some trouble with tests, we found that in some cases, this function is called on the root company, and if the user does not have the access rights to read data from the company (users with system rights have them by default), it will cause a crash. This situation is not possible with the standard UI, but we fix it in case it becomes possible in a future version or customization. Forward-Port-Of: odoo/enterprise#128218
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
Tax return submission now checks account settings only for tax groups that are actually used. This prevents businesses from being blocked by incomplete setup on unused tax groups, making tax closing smoother without changing reporting results.
Original PR description
…ax closing Steps to reproduce: - Remove the tax payable and receivable accounts of a tax group for which no move exists. - Open the tax returns view, set the opening date and submit the tax return -> Odoo prevents going further because the tax group configuration isn't fully done, but it's useless to ensure that for tax groups that aren't used. Forward-Port-Of: odoo/enterprise#128197
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