Daily updates from Odoo
Friday, July 10, 2026
72 changes · master
Security fixes and vulnerability patches
The Sign app now blocks unsafe or invalid bulk use of the auto-write feature, reducing the risk of unintended changes to related records. It also improves logging and test coverage so administrators get clearer feedback when automatic updates cannot be safely applied.
Original PR description
Fix scenarios where the auto-write feature could fail or be unsafe: - Prevent unsafe mass updates: Users could enable auto-write in bulk without proper awareness, leading to unintended behavior. Additionally, the field could be manually exposed even when no linked model/field is set. we add safeguards and constraints to prevent enabling it in invalid cases. - Improve test coverage: Update test cases to ensure correct behavior when users have access to partner records but must not be allowed to update sensitive fields (e.g., email) of other users through those records. task-6147410 Forward-Port-Of: odoo/enterprise#115118
New functionality added to Odoo
Turkish companies using TRY can now store official buying and selling exchange rates alongside the average rate. Invoices and bills automatically use the appropriate rate type by default, reducing manual corrections and helping accountants apply the correct rate consistently.
Original PR description
## Description of the issue/feature this PR addresses: Turkish accounting applies different exchange rates depending on whether the company is collecting foreign currency or paying it out. TCMB…
## Description of the issue/feature this PR addresses: Turkish accounting applies different exchange rates depending on whether the company is collecting foreign currency or paying it out. TCMB publishes both buying and selling rates daily but `currency_rate_live` only keeps the average, so accountants currently correct the rate by hand on every invoice and bill. ## Current behavior before PR: The TCMB daily update stores only the averaged rate on `res.currency.rate`. Invoices and bills use that same rate, and users have to adjust it manually per document. ## Desired behavior after PR is merged: - Both the buying and selling rates are stored on `res.currency.rate` next to the average. - Customer invoices and vendor bills get a Rate Type field, defaulting to "buying" for invoices and vendor refunds and to "selling" for bills and customer refunds. The user can override before posting. - The selected rate is written to `invoice_currency_rate`. The lookup uses the rate dated the document's date, or the most recent rate before it when no rate exists for that exact date. - Only TR companies with TRY as base currency are affected. task-5017817 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Enhancements to existing features
Point of Sale screens and related add-ons now include more complete translations for messages that staff may see during daily use. This improves clarity for users working in different languages, especially for dialogs, errors, alerts, and warnings.
Original PR description
pos* = All POS module In this commit: -------------------------------- Add missing translations for user-visible strings across POS modules. - Translated dialogs, errors, alerts, and other UI-visible messages - Updated Python-side UserError, ValidationError, and warning messages Task-5406947 Related PR-https://github.com/odoo/odoo/pull/239972 Forward-Port-Of: odoo/enterprise#122764 Forward-Port-Of: odoo/enterprise#102094
This update adds automated checks to ensure emails linked to newly generated coupons from helpdesk tickets remain traceable. It helps protect the reliability of customer communication history without changing day-to-day user workflows.
Original PR description
Added tests for email traceability when generating a new coupon in a ticket --- task-6341030 Forward-Port-Of: odoo/enterprise#122508
The printer setup screen now only shows the O-Box IP address setting when it is relevant for ePOS printers. It also hides technical service details from the O-Box view, making configuration clearer for business users.
Original PR description
This PR adapts the view to only allow the user to set obox ip if the type of printer used is epos as it doesnt matter otherwise It also hides the services installed on the obox as it's not useful for the user task-6330864 Forward-Port-Of: odoo/enterprise#123271
Point of Sale preparation displays can now be configured to create separate preparation orders for each product. This helps kitchen or prep teams organize work more clearly while keeping combo items grouped correctly with their main product.
Original PR description
In this commit: --- - This commit adds a split-per-product option on preparation displays, loads it in the PoS, and uses it to create separate preparation orders per product while keeping combo children attached to their parent line. related-https://github.com/odoo/odoo/pull/267412 task-6227300
VoIP call durations are now labeled and formatted more consistently in search filters, graphs, and pivot reports. This helps users understand whether duration values are shown in seconds or formatted time, reducing confusion when analyzing call activity.
Original PR description
Previous commits such as [1] worked towards a better uniformisation of the way we store and display duration values in VoIP. This commit hopefully takes care of the remaining issues: - Search view: custom filters (using the Domain component) would show things like "Duration" "greater than" "34", without any unit displayed. For that one, the only real possibility is to modify the label of the python field to "Duration (s)", so filters become clearer. It requires explicitly forcing labels to "Duration" everywhere else though. - Graph view: using widget="voip_duration" as in other views so that duration values are formatted properly. - Pivot view: using widget="voip_duration" as in other views so that duration values are formatted properly. [1]: https://github.com/odoo/enterprise/commit/906b0702daeddcc43782bc4234b18c8d01a29c8e task-6234431
The Grid and Gantt views were updated to work with a newer internal rendering method. This helps keep these views reliable and easier to maintain, with no expected change to day-to-day workflows.
Original PR description
- community: https://github.com/odoo/odoo/pull/273956 This commit follows changes in the `useVirtualGrid` hook regarding reactivity. The users of this hook, namely: the Gantt and Grid views' renderers, have been adapted to use its new API.
This update moves Odoo Enterprise screens and website snippets to the new shared icon system. Users should see more consistent icons across accounting, website, appointments, knowledge, sign, studio, room booking, and related areas, while reducing reliance on older icon assets.
Original PR description
Community PR: odoo/odoo#275347 task-5901783
Field Service shift notes can now include rich formatting such as links, images, and clearer instructions instead of plain text only. Product descriptions are also added automatically, helping technicians see relevant job details directly in their shift instructions.
Original PR description
Currently, the **Note** field only supports plain **text**, limiting the ability to include rich content such as links, images, and formatted instructions. This commit converts the **Note** field to **HTML** and automatically displays the product description in it, making Field Service shift instructions richer and easier for technicians to follow. Task-6285798
The PLM document view has been adjusted to better match the updated document management layout. This removes an unnecessary “Variant” banner and helps documents display and integrate more cleanly for users.
Original PR description
The goal is to remove the “Variant” banner and ensure the XPath follows the new document view structure so it can integrate properly. PR: https://github.com/odoo/odoo/pull/259695 upgrade PR: https://github.com/odoo/upgrade/pull/9990 task-5946575
The subscription portal now shows the “Change Plan” option as a lighter, less prominent button. This better reflects that changing plans is optional and helps avoid nudging customers toward an unintended action.
Original PR description
When changing the plan is allowed from the portal, a "Change Plan" button is shown in the subscription sidebar. It was styled as a primary button, which wrongly suggests to the customer that this is an action they are expected to take. Make it a light button instead. task-6280700
Sales users can now choose a subscription plan directly for optional subscription products in the configurator, instead of always receiving the first available plan. When a plan is already set by a parent product or cart subscription, the selector is locked so optional items stay aligned with the existing subscription.
Original PR description
Previously, optional subscription products in the configurator dialog would default to the first available subscription plan. This behavior was restrictive and did not allow users to choose a different plan. This change introduces an inline plan selector displayed next to the price of each optional subscription product in the configurator dialog: - The selector is editable when no plan is enforced (i.e., no parent subscription product and no existing subscription in the cart). - The selector is locked when a plan is already defined, ensuring optional products inherit the parent subscription plan. task-6130917
Validated tax returns can now be reset more flexibly when later returns already exist, as long as the report does not rely on carryover values. This reduces extra work for accounting teams that need to correct and resubmit an earlier period without undoing every subsequent return.
Original PR description
Let's consider we have validated the return of our tax report for January and February. Then, we realize we made an error in January, and want to modify this return and resubmit it. Before this…
Let's consider we have validated the return of our tax report for January and February. Then, we realize we made an error in January, and want to modify this return and resubmit it. Before this commit, an error message blocked the direct resetting of January's return, because February's had been posted. To be able to reset January, it was necessary to reset all subsequent returns. This was annoying. Such fixes need to happen in many countries (while some other rather make the adjustments in the next period to declare, like Belgium). This restriction was originally introduced to avoid inconsistencies in case the returns declared from the previously submitted returns. Two features could create such cases: 1) tax amount to recover, which was directly deduced from the closing entry when it contained something to pay 2) carryover, which created external values able to impact the following periods => Case 1) is not true anymore. When an amount needs to be recovered, we just show the balance taking it into account on the following returns, but don't change anything to their closing at all. => Case 2) still holds. So, all we need to put under control is carryover, which is what we do now. If the report doesn't use carryover at all, its returns can all safely be reset, whatever the state of the rest of the return chain.
The Sources tab for AI agents now has a clearer mobile-friendly layout. Adding a source also uses the same dialog as the list view, making the experience more consistent and easier to use on smaller screens.
Original PR description
The Sources tab in the AI agent form did not provide a dedicated kanban layout, resulting in a poor view on smaller screens. This commit adds a structured kanban view for AI agent sources and updates the 'Add Source' action to open the same creation dialog as the list view, providing a more consistent user experience. task-6366399
The bank reconciliation widget now loads less unnecessary data, especially on very large databases. This should make opening and using bank reconciliation faster for accounting teams without changing their workflow.
Original PR description
When opening the bank rec widget on huge DB's, it takes
a lot of time to load everything.
This commit aims to improve the loading performances by
removing some JS fields:
1 - reconciled_lines_ids: We only use the first element of
this recordset in JS, so we add a new computed field
to only send 1 record to the JS
2 - hasAttachment: replace the long JS computation of
`get hasAttachment` with a python computed field.
3 - Replace matched_credit_ids and matched_debit_ids
with exchange_diff_partial_ids.
Linked:https://github.com/odoo/odoo/pull/269119
task-6275945
Forward-Port-Of: odoo/enterprise#119557The timesheet assistant now gives clearer guidance when setup issues prevent activity tracking, including distinguishing server and CORS problems and warning when the browser watcher is missing or inactive. It also improves suggested timesheet entries by showing better context, restoring ActivityWatch suggestions after deleted Odoo events, and choosing more relevant projects for calendar events.
Original PR description
Forward-Port-Of: odoo/enterprise#122340 Forward-Port-Of: odoo/enterprise#115859
The WhatsApp message status icon now appears before message actions, keeping it in a consistent spot. This makes message threads easier to scan and improves readability for users.
Original PR description
Display the WhatsApp message status icon before the message actions to keep it consistently positioned and improve message readability. **before:** <img width="581" height="108" alt="image" src="https://github.com/user-attachments/assets/3971d86d-6210-4d26-87ca-88f425dd090d" /> **after** <img width="341" height="164" alt="image" src="https://github.com/user-attachments/assets/503f2861-34bf-4371-8ccd-4e1c6bc3f874" /> task-6085748
The Knowledge options dropdown has been simplified by removing non-essential icons while keeping menu text neatly aligned. The “Move To” action label was also clarified as “Move To...”, making the menu easier to scan without changing its functionality.
Original PR description
This commit removes non-essential icons from the knowledge options dropdown. It adds an invisible icon class to keep text alignment consistent and updates the "Move To" label to "Move To...". Related: odoo/odoo#271256 Task~6279545
Resolved issues and error corrections
This fixes how Belgian payroll calculates eco vouchers so employees receive the correct benefit amounts. It helps payroll teams avoid incorrect payslips and related reporting issues.
Original PR description
Forward-Port-Of: odoo/enterprise#119074
Audit reports exported to PDF now include images that users inserted with the file command. This prevents missing visual evidence or supporting material in generated reports and makes exported documents more complete.
Original PR description
Currently, when a user uses the `/file` command to insert an image into an audit report and exports the report to PDF, the image is omitted from the generated PDF. To improve the support of those blocks, we will pre-process the document and replace the embedded files that correspond to images with standard image elements before PDF generation. This will ensure that images are correctly rendered and displayed within the document's text flow in the exported PDF. Task [link](https://www.odoo.com/odoo/project.task/5115280) task-5115280 Forward-Port-Of: odoo/enterprise#122919 Forward-Port-Of: odoo/enterprise#121673
Marketing Automation now shows the correct reason when a participant is removed from a campaign. If a record still exists but no longer matches the campaign filter, users will see that explanation instead of the misleading “Record deleted” message.
Original PR description
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The…
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The removed bucket also contains records that still exist but no longer match the campaign filter, so the cancelled trace dialog shows "Record deleted" even when the record was only filtered out. In `sync_participants`, the to_remove participants are split between those whose record still exists in the database (filtered out by the campaign domain) and those whose record was actually deleted. `action_set_unlink` accepts an optional `trace_message` argument, defaulting to "Record deleted", and the filtered-out batch passes "Record no longer matches campaign filter" so the cancelled trace dialog reflects the real cause. Steps to reproduce: 1. Install Marketing Automation and CRM. 2. Open Marketing Automation, create a campaign on Lead with filter Stage = New. 3. Add a begin activity to the workflow. 4. Open CRM, create a Lead in the New stage. 5. Back in the campaign, click Generate Participants. 6. In the CRM pipeline, drag the Lead from New to Qualified. 7. Back in the campaign, click Generate Participants again. 8. Open the Participants smart button, click the participant for the moved Lead. 9. Click the cancelled activity in the workflow timeline. => The activity dialog shows "Error message: Record deleted" although the Lead still exists. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6251264) opw-6251264 Forward-Port-Of: odoo/enterprise#118692
This fix prevents delivery tracking from failing when EasyPost returns an empty tracker value. Users can continue working without seeing an error caused by incomplete carrier response data.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400Hong Kong payroll payslips no longer crash when a user clears the start or end date. This helps payroll users safely edit draft payslips and keeps Average Daily Wage and end-of-year pay calculations from running on incomplete date information.
Original PR description
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` >…
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` > `Payslips` > `Payslips`. - Create a `payslip` and remove the `start` or `end` period. **Error 1:** `TypeError: unsupported operand type(s) for +: 'bool' and 'relativedelta'` **Error2:** `AttributeError: 'bool' object has no attribute 'month'` When a user removes the start or end date of a payslip, the system computes the Average Daily Wage. Based on the payslip dates, it finds the previous year's payslips [1]. If the start or end date is not set, it raises an error [2]. For the second error, when computing whether to include EOY pay, it compares the company's EOY pay date with the end date's month. If the end date is not set, accessing its month raises an error [3]. This commit ensures that when retrieving previous-year payslips, if the start or end date is not set, it returns an empty payslip recordset. It also ensures that when computing whether to include EOY pay, if the end date is not set, `include_eoy_pay` is set to `False`. [1]: https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L124 [2]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L209-L215 [3]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L141 Forward-Port-Of: odoo/enterprise#123135 Forward-Port-Of: odoo/enterprise#120586
Popover content in dark mode now looks more consistent and easier to use. Secondary buttons stand out as clickable actions, and forms inside popovers better match the surrounding popover background.
Original PR description
Before this commit, content like form & secondary button rendered inside popovers had inconsistent styling in dark mode: - secondary buttons did not stand out properly from the popover background, making them look like plain text blocks rather than actionable buttons; - forms rendered inside popovers (such as the multi-create popover) kept their default background, which visually clashed with the popover background. This commit fixes these issues by: - adding dedicated secondary button background colors for popovers, including hover state; - aligning form backgrounds inside popovers with the popover background. task-6249985 Forward-Port-Of: odoo/enterprise#121631
The French Intrastat export wizard now opens warning links filtered to the specific journal entries with missing required Intrastat information. This prevents users from being sent to unrelated accounting entries, making correction of export issues faster and clearer.
Original PR description
Steps to reproduce: 1. Have a French company with intrastat report module installed 2. Create and validate a bill to another EU country, without filling out at least one of the required intrastat fields 3. Go to the intrastat report, and export it as XML DEBWEB2 4. In the export wizard, click on the internal links on the warning messages Issues: 1. In the Intrastat report in French localization, when there are missing values detected in the export, the Export Wizard shows internal links that lead to every journal entries - instead of showing only the relevant entries. The warning banner on the report uses the action action_invalid_code_moves which has a domain to limit what is shown on the view form. However in the method _fill_value_errors there was no domain. opw-6215339 Forward-Port-Of: odoo/enterprise#117997
International Easypost shipments now use the sale order currency on commercial invoices when available, instead of defaulting to the company currency. This helps prevent mismatches in customs documents for orders priced in a different currency.
Original PR description
Issue ----- When shipping internationally with Easypost, the currency on the commercial invoice does not always match the one of the sale order. Steps to reproduce ----- - Install Easypost - Create a…
Issue ----- When shipping internationally with Easypost, the currency on the commercial invoice does not always match the one of the sale order. Steps to reproduce ----- - Install Easypost - Create a new pricelist using a different currency from the company - Create a SO - Some product with a weight & HS code - Customer must be in another country from company (for commercial invoice) - Use the new pricelist - Add easypost delivery - Confirm SO - Validate linked picking > Commercial invoice uses company currency instead of SO's Cause ----- The currency being sent to Easypost is retrieved from the package in https://github.com/odoo/enterprise/blob/4c540f450d4de8b59b871662123f85ed54cca2a9/delivery_easypost/models/easypost_request.py#L146 The package object is actually created by calling the carrier's `_get_packages_from_picking` method https://github.com/odoo/enterprise/blob/4c540f450d4de8b59b871662123f85ed54cca2a9/delivery_easypost/models/easypost_request.py#L266-L270 Solution ----- We could be fixing this in `stock_delivery` by creating the package with the correct currency when calling `_get_packages_from_picking`. The problem with this approach is that this might negatively affect other carrier services, as discussed in https://github.com/odoo/odoo/pull/268224. Instead, we can apply a band-aid fix to take the currency from the picking's sale in the `delivery_easypost` module, which is the only one where the problem was reported. ----- Ticket: opw-6224883 Forward-Port-Of: odoo/enterprise#123083
Expense authorizations from Stripe now correctly recognize merchant category codes that fall within configured ranges, reducing incorrect errors during card use. Declined card expenses also avoid duplicate refusal messages, keeping expense records cleaner and easier to review.
Original PR description
# [FIX] hr_expense_stripe: Fix MCC ranges Context: Since 3e52d875 when receiving an authorization whose MCC fits in a range we would not find it in the search. This is logical yet we return an error before checking properly mcc codes with range included After this commit: This will also check that the authorization MCC exist if we don't directly find the range. We move the "not found" error after that check too The forgotten tests have been added into the overrides opw-6185961 opw-6288399 # [FIX] hr_expense_stripe: Fix double refusal of expenses Context: When an expense is created through a declined stripe authorization, the expense is refused twice, resulting in a duplicated refusal message After this commit: Do not refuse already refused expenses Forward-Port-Of: odoo/enterprise#123093 Forward-Port-Of: odoo/enterprise#121474
Pasting document links into an empty message no longer adds an unnecessary blank line at the start. This keeps shared document messages tidier while still separating links from any existing text.
Original PR description
Before this commit, adding document links always prepended a line break before the generated links. When the composer was empty, this resulted in messages starting with an unnecessary blank line. This commit only inserts a line break when the composer already contains text, avoiding the extra spacing while preserving the separation between existing content and pasted links. task-[5947683](https://www.odoo.com/odoo/project/1519/tasks/5947683) Forward-Port-Of: odoo/enterprise#123201 Forward-Port-Of: odoo/enterprise#120952
The Turkish Central Bank currency rate provider now uses the official selling rate instead of averaging buying and selling rates. This improves accounting accuracy and aligns import valuation with Turkish customs requirements.
Original PR description
## Short fix summary: The TCMB (Central Bank of Turkey) provider computed the exchange rate as an average of the buying and selling rates (`2 / (ForexBuying + ForexSelling)`). This is inaccurate for real accounting flows and does not follow Turkish customs regulation (Customs Law No. 4458, Art. 30), which requires the Central Bank's selling rate for goods import valuation. This now uses the selling rate (`ForexSelling`) only. task-6227500 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#122770
The Peru Profit and Loss report now includes Other Operating Income when calculating gross profit. This ensures gross profit, operating profit, pre-tax result, and net profit reflect all relevant operating income for more accurate financial reporting.
Original PR description
**Steps to reproduce:** 1. Install `l10n_pe` and switching to the Peru company. 2. Create and post a journal entry with a line on account 7520000 (Other Operating Income). 3. Open the Profit and Loss report (PE). 4. The amount appears correctly under "Other operating income" (`PE_PNL_A_5`). 5. "Gross profit", "Operating profit" , "Result before taxes" and "Net Profit" do not change when this amount is added or removed. **Issue:** The "Other operating income" line is excluded from the Gross Profit calculation, and consequently from Operating Profit and every downstream total in the PE Profit and Loss report. **Why this happens:** Gross Profit (`PE_PNL_A_4`) balance expression uses the aggregation with formula `PE_PNL_A.balance - PE_PNL_A_3.balance`, which doesn't include `PE_PNL_A_5.balance` as a term opw-6283907 Forward-Port-Of: odoo/enterprise#123063
A small compatibility fix keeps Knowledge file navigation behaving as expected in newer Chrome versions. This prevents browser changes from altering how scroll actions complete, reducing the risk of unexpected behavior for users.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
Blank US checks now print the same payment stub lines as pre-printed checks, making them easier to read and reconcile. The blank check layout was also adjusted so the bottom section fits on a single page instead of spilling onto a second page.
Original PR description
See individual commits. task-6359599 Forward-Port-Of: odoo/enterprise#123144
The shop floor now respects manufacturing settings that block creating new serial numbers for components. This prevents operators from bypassing inventory controls and helps keep production traceability consistent with company configuration.
Original PR description
**Issue**: Even when creation of new Serial Numbers for components is disabled on the Manufacturing Operation Type, it is still possible to create them from the shopfloor application. **Steps to…
**Issue**: Even when creation of new Serial Numbers for components is disabled on the Manufacturing Operation Type, it is still possible to create them from the shopfloor application. **Steps to reproduce**: - Enable "Lots & Serial Numbers", on the global settings - Create two products, one tracked by unique serial number - Go to Inventory > Configuration > Warehouse Management > Operations Types - Select Manufacturing and disable "Create New Lots/Serial Numbers for Components" - Create and confirm a MO using the tracked product as component - Go to shopfloor - Click the "+" button next to the component, then "New" -> No error is raised when creating a serial number **Cause**: The `_check_create` constraint relies on `active_mo_id`: https://github.com/odoo/odoo/blob/494cdcfdf4ec166e0a643ee70a53c12c810d02b4/addons/mrp/models/stock_lot.py#L11-L19 However, the shopfloor does not pass this, in context: https://github.com/odoo/enterprise/blob/54c6252a0e13b11fc297b6828883923c0f89881a/mrp_workorder/static/src/mrp_display/mrp_record_line/stock_move.js#L193-L199 As a result, the check is bypassed. opw-6041241 Forward-Port-Of: odoo/enterprise#111408
Mobile self-ordering now uses the same printing approach as kiosk ordering, so preparation receipts are printed more reliably. The change routes printing through the IoT Box using websockets when mobile devices cannot use the local long-polling connection.
Original PR description
Self ordering mobile now aligns on kiosk avoiding to update last order changes, which would prevent from printing preparation receipts. This is made possible by the IoT Box allowing to print receipts through websockets. We also take the opportunity to update the `iot_http` service in order to allow updating methods available on the service: it allows us adding a new method to disable longpolling for self ordering mobile, which would always fail, to end up using websocket (clients are not on the same network as the IoT Box). Forward-Port-Of: odoo/enterprise#123328 Forward-Port-Of: odoo/enterprise#121013
This fix ensures comments in Knowledge articles are visible immediately when an article is opened or reloaded. It also corrects comment positioning so comment markers no longer overlap or shift unexpectedly, making article discussions easier to follow.
Original PR description
### [FIX] knowledge: load comments on first load There was an issue where comments are not displayed when opening an article containing some. How to reproduce: - create a new article, write some text…
### [FIX] knowledge: load comments on first load There was an issue where comments are not displayed when opening an article containing some. How to reproduce: - create a new article, write some text and add some comments. - reload the page Issue: - comments are not displayed, but they are when switching back and forth to another article Reason: Owl2 -> Owl3 refactoring: commit [1] replaced useRecordObserver by onWillUpdateProps, however the 2 are not equivalent, especially over the timing of the first call (useRecordObserver callback is called during setup). ### [FIX] knowledge: batch vertical dimensions computation once There was an issue where comments were not displayed at their correct position (height/top) in "handler" mode. How to reproduce: - create an article with 3 comments over 5 lines, following a given pattern: - one comment on the first line - one comment on the second line - keep the third line empty - one comment across the 4th and 5th lines - reload the page (issue 1) - click successively on the 3 comments zones (issue 2) Issue: - issue 1: the comments on reload overlap each other while they should not - issue 2: when clicking on the 3rd comment, the 1st and 2nd comments appear offset by an abnormal vertical distance (which should not exist) Reason: Owl2 -> Owl3 refactoring: Commit [1] replaced reactive + batched callback with `useEffect` executing that same batched callback, however `useEffect` is already batched starting from the second call, effectively batching twice, which resulted in the wrong dimensions being computed for knowledge comments in the comments_handler [1]: https://github.com/odoo/enterprise/commit/ab1e2cad9a214a1303e13fdff0e8a62781ef56ee task-6370985 Forward-Port-Of: odoo/enterprise#123339
Grid views now display the user-friendly label for grouped selection values when opening related records from the cell magnifier. This avoids confusing internal codes such as "non_billable" appearing in list titles, making the view easier to understand for users.
Original PR description
When grouping a grid view by a selection field and clicking on the cell magnifier, the list title showed the technical name (e.g. non_billable) instead of the display name (e.g. "Non Billable"). This commit adds a condition specifically for selection fields, ensuring that their display names are used. task-5980035 Forward-Port-Of: odoo/enterprise#122303 Forward-Port-Of: odoo/enterprise#120894
This fix prevents DHL delivery validation errors for customers or warehouses located in regions whose local province codes are only one character long. Odoo now sends DHL the longer official province format where needed, allowing affected shipments to be validated successfully.
Original PR description
Steps:
- Install delivery_dhl_rest
- Create a new customer with barcelona as address
- Create a new Delivery
- Set DHL
- Validate de delivery
- Validation error #/customerDetails/receiverDetails/postalAddress/provinceCode: expected minLength: 2, actual: 1
DHL requires `provinceCode` to be at least 2 characters. Several countries in `res.country.state` data use single-character codes (e.g. ES: B, M, A…; AR: C, B, S…; CN: 京, 沪…). This caused API validation errors when shipping from or to addresses in those regions.
Add `PROVINCE_CODE_MAP`, a dict keyed by `(country_ISO2, state_code)`, mapping each offending code to its ISO 3166-2 form (e.g. ('ES', 'B') -> 'ES-B'). Both `_get_consignee_vals` and `_get_shipper_vals` now look up the map before sending `provinceCode`, falling back to the raw code for countries not in the map.
links: https://developer.dhl.com/api-reference/mydhl-api-dhl-express#shipments
opw-6341745
Forward-Port-Of: odoo/enterprise#122138This fixes a display issue in mass mailing where the snippet selection dialog could appear hidden behind the fullscreen editor when the AI chat was open. Users can now add mailing content blocks normally without the editor controls becoming stuck.
Original PR description
When an AI chatbox is active, all non-error dialog overlays are set to be behind the chatbox through their z-index. This causes an issue where the dialog overlay that adds new snippets to a mailing is placed behind the fullscreen mailing editor, preventing its use and freezing the use of some commands (save & discard). This commit restores the snippet dialog's z-index to its original value. Steps to reproduce: - Create a new mailing - Select a builder-enabled theme (such as Events Promo) - Open a new AI chat by clicking the AI icon in the top right - Open the fullscreen editor - Click on the Headers block category task-6321624 Forward-Port-Of: odoo/enterprise#123377 Forward-Port-Of: odoo/enterprise#123276
Fixed an issue in Accounting where choosing certain actions from the bank reconciliation control panel could fail with an error. Users can now use those actions reliably without being interrupted by a missing service problem.
Original PR description
Fixed an issue where selecting any action from the control panel that would use orm would result in an error because the orm service was undefined. no task id Forward-Port-Of: odoo/enterprise#123480
Fixed an issue where the Balance Sheet could crash after adding a custom Journal Item field in Studio and then filtering by analytic account. This helps accounting users access reports reliably without hitting an error in that configuration.
Original PR description
Steps to reproduce ================== - Activate Analytic Accounting. - Go to Accounting > Accounting > Reconcile. - Open Studio. - Add a new many2many field. - Set Journal Item as the related model. - Go to Reporting > Balance Sheet. - Select an analytic account. => RecursionError: maximum recursion depth exceeded Cause of the issue ================== Calling `self.env['account.move.line'].fields_get()` will cause a recursion error. `account.report::_prepare_lines_for_analytic_groupby()` calls `account.move.line::_where_calc()` which in turns calls _prepare_lines_for_analytic_groupby again Solution ======== It turns out we don't actually need to retrieve the groupable attribute, thus bypassing the error. opw-6129149 Forward-Port-Of: odoo/enterprise#122244 Forward-Port-Of: odoo/enterprise#116251
Payroll processing now evaluates only the warnings that apply to the payslips being computed, instead of checking every possible warning. This reduces unnecessary work and helps payroll calculations run more efficiently without changing the payroll results.
Original PR description
Ensure that we do not evaluate unnecessary warnings by only evaluating the warnings relevant to the payslips being computed; instead of evaluating all of them. task-6371828 Forward-Port-Of: odoo/enterprise#123401
This fix prevents an error when recalculating an Australian payslip after an employee's income stream type has been changed. Payroll teams can now update employee payroll details and recompute payslips without encountering a blocking traceback.
Original PR description
When an employee's Income Stream Type is changed after a payslip has been created, computing the sheet for payslip will raise a traceback. Steps to reproduce the error: - Install…
When an employee's Income Stream Type is changed after a payslip has been created, computing the sheet for payslip will raise a traceback. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module with demo data - Switch to ``My Australian Company`` company - Create a new payslip for ``Dennis Cactus`` Employee > Save - Go to Employees > Open the ``Dennis Cactus`` employee > In Payroll tab, Income Stream Type: Other specified payments > Save - Go back to payslip > click the compute sheet button Traceback: ```py KeyError: 'OSP' ``` https://github.com/odoo/enterprise/blob/13e64e0cb7f566cbbb46109fe1c218eb7a14eead/l10n_au_hr_payroll/models/hr_payslip.py#L175-L178 The ``l10n_au_income_stream_type`` field on the payslip is a computed field that only depends on ``employee_id``. As a result, changing the employee's Income Stream Type does not trigger a recomputation of the corresponding field on existing payslip. So, when the ``payslip_ytd_totals`` field is computed, it uses the old value of ``l10n_au_income_stream_type`` field at [1], The resulting ``payslip_ytd_totals`` is then used to build the ``totals`` dictionary, and eventually, when the employee's current ``income_stream_type`` is used to access ``totals``, the mismatch key leads to the above traceback. https://github.com/odoo/enterprise/blob/13e64e0cb7f566cbbb46109fe1c218eb7a14eead/l10n_au_hr_payroll_account/models/hr_payslip.py#L75-L88 [1]: https://github.com/odoo/enterprise/blob/13e64e0cb7f566cbbb46109fe1c218eb7a14eead/l10n_au_hr_payroll/models/hr_payslip.py#L269-L272 solution: I added ``l10n_au_income_stream_type`` to ``add_to_compute()`` in ``compute_sheet()``. This ensures that stale values of ``l10n_au_income_stream_type`` on existing payslips are recomputed when the payslip sheet is computed. sentry-7536819310 Forward-Port-Of: odoo/enterprise#123288 Forward-Port-Of: odoo/enterprise#120143
The Swiss payroll time off request form now always shows the start date field. This prevents confusion and ensures employees can consistently enter the required date for any type of time off request.
Original PR description
The time off request view was showing the request_date_from field conditionally, which makes no sense as you would always need to pick a date for a time off no matter which unit the request uses. runbot-241099 Forward-Port-Of: odoo/enterprise#122278
This fix prevents AI markdown-related tests from failing when an optional markdown component is not installed. It keeps automated checks reliable without changing functionality for users.
Original PR description
markdown2 is an optional dependency, so `markdown_format` can fail to process markdown, in which case all the markdown tests fail. Skip the markdown rendering test if there's no markdown rendering to test. Forward-Port-Of: odoo/enterprise#123484 Forward-Port-Of: odoo/enterprise#123002
Downloading a Knowledge article as a PDF no longer includes unwanted scrollbars or an open menu overlay. This makes exported articles look cleaner and more professional, especially for longer content or when the browser is zoomed in.
Original PR description
The Download PDF option of an article prints the page with the browser. On screen, the article body is inside .o_scroll_view_lg, which scrolls when the content is longer than the screen:…
The Download PDF option of an article prints the page with the browser. On screen, the article body is inside .o_scroll_view_lg, which scrolls when the content is longer than the screen: https://github.com/odoo/enterprise/blob/79f8defa04476e1b939dc8bb5449a775137aed62/knowledge/static/src/scss/knowledge_views.scss#L170-L177 The print stylesheet used to force overflow: visible on every div, so this container did not scroll when printing. It also hid every child of the body except the action manager, so the navbar and open dropdowns were left out of the print. Commit https://github.com/odoo/enterprise/commit/69612c80ea0aec5ccf2c2857449da03e61273457 rewrote knowledge_print.scss to scope its rules to the Knowledge view and removed both rules. The scroll container now keeps its fixed height and its scrollbar when printing, so the scrollbar is drawn in the print preview and on every page of the PDF. The dropdown opened to reach Download PDF is printed on top of the article when it overlaps the page area, which happens when the browser is zoomed in. Add overflow: visible to the print rule of knowledge_print.scss that already targets .o_scroll_view and .o_scroll_view_lg with position: static. That rule exists to undo the screen positioning of the scroll containers when printing, so the overflow reset belongs there. Its selector is also more specific than the screen one, so the value applies without !important, like position: static already does. Restore the rule that hides the body children other than the action manager, scoped to the Knowledge view like the rest of the file since the print stylesheet is now loaded on every page. Before: <img width="497" height="703" alt="image" src="https://github.com/user-attachments/assets/44aa3366-3fc8-4382-8aa2-84625fa4b6d8" /> After: <img width="497" height="703" alt="image" src="https://github.com/user-attachments/assets/8b6eb2bc-37a3-4666-b871-0e6149c41fea" /> Steps to reproduce: 1. Open the Knowledge app and create an article 2. Paste enough text in the article to fill more than one PDF page 3. Zoom the browser to 200% 4. Click the three dots in the top right corner, then Download PDF 5. Check the print preview or the saved PDF => A scrollbar is drawn on the right edge of every page and the dropdown menu is printed on top of the article Ticket [link](https://www.odoo.com/odoo/project.task/6279174) opw-6279174 Forward-Port-Of: odoo/enterprise#120249
Fixed an issue where Sendcloud batch deliveries could fail when a transfer was split into multiple packages. The system now uses a safe fallback for the shared delivery reference, allowing labels to be generated without interruption.
Original PR description
Issue ----- When using Sendcloud batch deliveries, users get a traceback if the transfer is split into multiple packages. Steps to reproduce ----- - Setup Sendcloud - Enable batch delivery - Create a…
Issue ----- When using Sendcloud batch deliveries, users get a traceback if the transfer is split into multiple packages. Steps to reproduce ----- - Setup Sendcloud - Enable batch delivery - Create a delivery for 2 units of a product - Delivery method set to sendcloud - Put each unit in a separate package - Validate the delivery > Traceback Cause ----- Bug introduced by #90302 (so only present in 19.3+). When using the batch deliveries option, the packages are sent in a single list. This means that, in `_prepare_parcel`, when we iterate over the packages, `pkg` can be a list https://github.com/odoo/enterprise/blob/2c89c8e5da7dcb83d5a60c9616de4d5d07f0b9ab/delivery_sendcloud/models/sendcloud_service.py#L462 This means that `pkg.name` will fail https://github.com/odoo/enterprise/blob/2c89c8e5da7dcb83d5a60c9616de4d5d07f0b9ab/delivery_sendcloud/models/sendcloud_service.py#L481 Considering that a batch delivery uses the same reference number on all labels, we can pass `None` as a fallback to `_get_unique_order_number_reference` (it is an accepted value) https://github.com/odoo/enterprise/blob/2c89c8e5da7dcb83d5a60c9616de4d5d07f0b9ab/delivery_sendcloud/models/sendcloud_service.py#L388-L393 ----- Ticket: opw-6267928 Forward-Port-Of: odoo/enterprise#120206
Vendor bills imported from Chilean electronic invoice files now use the correct foreign-currency amounts instead of mistakenly applying Chilean peso amounts. This prevents incorrect bill totals when companies work with currencies such as UF.
Original PR description
**STEP TO REPRODUCE** 1. Create a invoice to a chilian company, using another currency (for example UF, don't forget setup up a currency rate). 2. Confirm. 3. Download the xml in the chatter, and import it as a vendor bill. 4. Notice the imported bill amount are wrong (Pesos amount are used, with the currency being UF). opw-6269662 Forward-Port-Of: odoo/enterprise#123179 Forward-Port-Of: odoo/enterprise#119664
This change prevents WhatsApp messages from failing to load when they are linked to business documents that the user cannot access directly. Existing WhatsApp message visibility rules still control who can see messages, helping affected upgrades proceed without disruption.
Original PR description
The `body` field on `whatsapp.message` was defined with `related_sudo=False` with the intent of restricting access to messages from restricted records. However, this was never actually providing any…
The `body` field on `whatsapp.message` was defined with `related_sudo=False` with the intent of restricting access to messages from restricted records. However, this was never actually providing any security value because [`mail.message.fetch()`] was overriding it with `self.sudo()` till `v19.1`, meaning the body was always fetched as superuser regardless:
```py
web_search_read() -> search_fetch()
-> fields.py _compute_related()
-> record[self.related_field.name] # triggers fetch of mail.message.body
-> models.py _fetch_field()
-> mail_message.py fetch()
-> self = self.sudo() # sudo hack overrides related_sudo=False silently
```
In `v19.2`, the `fetch()` sudo hack was intentionally removed (see commit odoo/odoo@4727f12d274a0b2d7c455363d189565bd8fb2e7a) as access rights are now cached and can be checked without a performance penalty. This exposed the broken `related_sudo=False` which now causes an `AccessError` when trying to read the body of a `whatsapp.message` whose linked `mail.message` points to a document the current user cannot access (e.g. `purchase.order`).
Access control on `whatsapp.message` is already correctly enforced at the `ir.rule` level:
- Regular users can only see messages they created (`create_uid = user.id`)
- WA Admins can see all messages
We have upgrade requests failing on this issue: TBG-[2765]
[`mail.message.fetch()`]: https://github.com/odoo/odoo/blob/saas-19.1/addons/mail/models/mail_message.py#L812-L819
[2765]: https://upgrade.odoo.com/odoo/tbg/2765?debug=1
Forward-Port-Of: odoo/enterprise#119867This fix ensures that when warehouse staff scan an existing package followed by a package type, the newly created destination package is correctly linked to the products. It prevents silent package creation errors in barcode delivery flows, improving inventory accuracy and reducing manual correction work.
Original PR description
When scanning a package then a package type, from the point of view of the user nothing happend, and in the backend it will created a new package but it will not link it to the products nor will it…
When scanning a package then a package type, from the point of view of the user nothing happend, and in the backend it will created a new package but it will not link it to the products nor will it show any warning. Steps to reproduce: ------------------- * Install barcode and stock * Enable packages in settings * Open Inventory * Create a product, * Create a Package Type -> barcode PACKTYPE, * Create a Package linked to this package type -> PACK, * Add at least 2 unit of product to this package, * Create a delivery for 2 unit of the product, Open Barcode * Operation > Delivery orders > your delivery * Erase the destination package from the first line * Scan PACK ( don't click on the green line) * Scan PACKTYPE **Actual behavior** create a new package but does not link it to the new products **Expected behavior** create a new package and set it as destination package. Observation: ------------- When scanning the package (PACK), we will go through ```_processPackage``` -> ```async _processPackage``` where in the end the line is unselected: https://github.com/odoo/enterprise/blob/39d8a473fe03038ca0494a6a8165e3eb75bd8492/stock_barcode/static/src/models/barcode_picking_model.js#L2090 When we scan our package type (PACKTYPE), we will go to ``` _processPackage``` -> ```_processPackage```->```_processPackageType``` where we will obtains packagesIds checking that we have a source package: https://github.com/odoo/enterprise/blob/7cd9834d1d918f12dec43844cae6f112309e5772/stock_barcode/static/src/models/barcode_picking_model.js#L2123-L2132 and will send us to ```_putPackInPack```: https://github.com/odoo/enterprise/blob/7cd9834d1d918f12dec43844cae6f112309e5772/stock_barcode/static/src/models/barcode_picking_model.js#L2133-L2136 Where we will avoid the empty packageIds since we checked on the source package and not the destination package: https://github.com/odoo/enterprise/blob/2b887d094c66be7aebd92fbf735b1852f5dde4b5/stock_barcode/static/src/models/barcode_picking_model.js#L2296-L2299 and will call ```action_put_in_pack``` from the packaging model: https://github.com/odoo/enterprise/blob/2b887d094c66be7aebd92fbf735b1852f5dde4b5/stock_barcode/static/src/models/barcode_picking_model.js#L2301-L2306 In ```action_put_in_pack``` will create a new packaging and put it as a the new destination package, but since the ```previous_dest_package``` (saved in db) was itself, he will [erase the link](https://github.com/odoo/odoo/blob/cda011dc8590773f6c3a26f4ae9d5242a3147024/addons/stock/models/stock_package.py#L354-L363) he just made. Which means that in our case, we created a package without linking it to anything. Even if we avoid the function to erase the destination package, since the destination package shown in barcode is the one from move line : https://github.com/odoo/enterprise/blob/d0d0a3cf4a02bf24cf502b533e494fe7ca155eb3/stock_barcode/static/src/components/line.js#L115-L117 It will not show the new package in barcode opw-5449729 Forward-Port-Of: odoo/enterprise#120335 Forward-Port-Of: odoo/enterprise#104876
The website generator now links products to categories using unique identifiers instead of category names. This prevents products from being assigned to the wrong category when different categories share the same name, improving storefront accuracy.
Original PR description
Before we matched categories with products but names but this was less reliable in the case that we had multiple categories with the same name. e.g. Accessories (for men) and Accessories (for women). This new method allows for this and makes the matching more reliable. Forward-Port-Of: odoo/enterprise#122143
Belgian payroll no longer applies a special public holiday eligibility rule for time credit contracts because that rule had no legal basis. This keeps payroll calculations aligned with Belgian legal requirements and reduces the risk of incorrect payslip handling.
Original PR description
The specific code related to the eligibility to public holiday for time credit contracts has no legal base. This commit removes it. task-6370653 Forward-Port-Of: odoo/enterprise#123303
The attendance Gantt view now includes employees who are currently checked in when calculating worked hours. This ensures progress information is accurate even before an employee checks out, helping managers see up-to-date attendance totals.
Original PR description
Isuue =========== If the `check_out` field on an attendance is not set, we don't take it into consideration in the computed worked hours, as we defined domains to retrieve attendances whose `check_out` ends before a certain limit, assuming `check_out` is set for all attendance records, and thus missing the worked hours that are still ongoing. Fix =========== - Update the domain of the employees' progress bar data to account for attendances with a `False` `check_out`. TaskID-6121547
The timesheet grid now marks public holidays, weekends, and approved personal time off according to the employee's own working schedule instead of always using the company default. This helps employees and managers see accurate unavailable days and keeps Timesheets aligned with Time Off behavior.
Original PR description
Steps to Reproduce --- - Create two different working schedules with different public holidays - Assign employees to specific working schedules - Set company default working schedule to a different…
Steps to Reproduce --- - Create two different working schedules with different public holidays - Assign employees to specific working schedules - Set company default working schedule to a different schedule - Login as employee with specific working schedule - Navigate to Timesheets app -> My Timesheets - Observe public holidays and personal time-off displayed in the timesheet grid Issue --- - The timesheet grid displays unavailable dates (public holidays, weekends) from the company's default working schedule instead of the employee's assigned working schedule. - Personal time-off requests are not reflected as unavailable dates in the timesheet grid. Current Behaviour --- - Public holidays shown are always from the company's default working schedule, ignoring employee-specific working schedule assignments. - Employee's approved time-off requests don't appear as unavailable in the timesheet. Expected Behaviour --- - Public holidays should display based on the employee's assigned working schedule, with company schedule as fallback only when no specific schedule is assigned. - Employee's personal time-off requests should appear as unavailable dates. - This should align with Time Off app behavior. Fix --- - Included employee-specific work interval calculation with personal time-off requests. - Added support for contract-based calendar changes and calendar validity periods. - Implemented proper fallback when valid intervals are not found. task-4997080 Forward-Port-Of: odoo/enterprise#123331 Forward-Port-Of: odoo/enterprise#95458
Employees with flexible or missing working schedules will no longer see misleading expected hours in the Timesheet Assistant or systray. The change keeps total logged hours visible while only showing expected hours when a fixed or average schedule makes them meaningful.
Original PR description
**Steps to reproduce:** 1. Create an employee without a fixed working schedule. 2. Configure the employee with variable hours per day, per week, or no working hours at all. 3. Open the Timesheet Assistant or the Timesheet systray. 4. Observe that expected hours are displayed (over 0h 00m or over 24h 00m). **Cause:** Expected working hours were always computed and displayed, even for resources without a fixed schedule. **Fix:** Only compute expected working hours when the employee has a fixed or average schedule, and rely on the computed working hours to control the display of expected hours while keeping total hours always visible. task-6321760 Forward-Port-Of: odoo/enterprise#123068 Forward-Port-Of: odoo/enterprise#122232
Helpdesk closing reminder emails are now sent only for tickets in stages that are actually configured for automatic closure. This prevents customers from receiving misleading warnings for tickets that will not be closed automatically.
Original PR description
**Problem:** When a team restricts automatic closing to specific stages (from_stage_ids), the closing-reminder email is still sent to every inactive ticket in the team, including tickets in stages…
**Problem:** When a team restricts automatic closing to specific stages (from_stage_ids), the closing-reminder email is still sent to every inactive ticket in the team, including tickets in stages that are never auto-closed. **Steps to reproduce:** 1. On a helpdesk team, enable Automatic Closing with a reminder and set "In Stages" (from_stage_ids) to one specific stage 2. Leave a ticket inactive in a different, non-folded stage until it reaches the reminder threshold (auto_close_day - reminder_delay) **Current behavior:** The ticket gets a "your ticket will be closed soon" reminder even though it is not in an auto-close stage and will never be closed. **Expected behavior:** Only tickets that would actually be auto-closed (those in from_stage_ids) should receive the reminder. **Cause of the issue:** The reminder selection filters on auto_close_ticket_reminder and the reminder date only; unlike the auto-close selection, it does not apply the team's from_stage_ids condition. **Fix:** Reuse the same stage condition used to select tickets for closing when selecting tickets for the reminder, so the reminded set stays consistent with the set that will be auto-closed. opw-6291237 Forward-Port-Of: odoo/enterprise#120732
GIFs in Facebook feed comments now show a preview image instead of appearing missing. Users can click the preview to open the animated version on Facebook, making comment content easier to review from Odoo.
Original PR description
Bug === When opening the comments modal of the feed view, the GIF images are not visible. Technical ========= The API does not return the GIF, it only returns the MP4 and the JPG. So we show the fixed image, and when clicking on it, it opens the video on Facebook. Task-6241607 Forward-Port-Of: odoo/enterprise#123181 Forward-Port-Of: odoo/enterprise#118619
The Sign template screen now adapts better when header text becomes longer, such as in translated interfaces. This prevents tag fields from visually overlapping the header, making the page easier to read and use.
Original PR description
Description: - The `.o_sign_template_tags_and_save` container relied on a hardcoded vertical offset (`top: 65px`) while being absolutely positioned. This assumed a fixed control panel height and…
Description: - The `.o_sign_template_tags_and_save` container relied on a hardcoded vertical offset (`top: 65px`) while being absolutely positioned. This assumed a fixed control panel height and caused the tags container to overlap with the header content when the neutralized red header bar expanded to multiple lines due to longer translated strings. - Replaced `top: 65px` with `top: auto` to remove the dependency on a fixed vertical offset and allow the element to be positioned according to its computed static position. - Reduced the height of `.o_field_widget.o_field_many2many_tags` from `50px` to `35px` to better fit the available space within the header area and prevent visual overlap between tag rows and surrounding elements. - This change preserves the existing positioning strategy while making the layout resilient to variable header heights caused by translations and other content-dependent UI variations. 19 - https://github.com/odoo/enterprise/blob/3db8db2eac3dff1485c6a1c977c80e573bfe6cab/sign/static/src/scss/sign_backend.scss#L486 Before fix: <img width="1874" height="443" alt="image" src="https://github.com/user-attachments/assets/196feab3-3460-4ed9-9f57-d7744e9c4e4b" /> After fix: <img width="1319" height="412" alt="image" src="https://github.com/user-attachments/assets/93ae5bcd-f0f0-4999-9cf7-f83b82d689ac" /> Forward-Port-Of: odoo/enterprise#120590 Forward-Port-Of: odoo/enterprise#118937
Lazada order syncing no longer adjusts individual item statuses in a way that can reduce ordered quantities below already delivered amounts. This prevents sync interruptions for orders with delivered items that later show item-level cancellations, improving reliability for Lazada sales operations.
Original PR description
Lazada stores order statuses at the item level. When an item is canceled, we mirrored this by decreasing the ordered quantity on the sale order line. But if the item was already delivered, decreasing the quantity below the delivered amount is forbidden and raises a `UserError`, which aborts the whole order sync:
```python
File ".../sale_stock/models/sale_order_line.py", line 420, in _update_line_quantity
raise UserError(_('The ordered quantity of a sale order line cannot be decreased below the amount already delivered. [...]'))
```
In practice, item-level statuses only differ from the order status in exceptional cases. Stop syncing statuses at the item level and assume the entire order shares a single status, which avoids the quantity decrease and the resulting traceback.
opw-6267730
Forward-Port-Of: odoo/enterprise#123365
Forward-Port-Of: odoo/enterprise#122851Auto Plan will no longer assign someone to a project planning slot just because they previously worked on the same project. It now also checks that the person matches the role requested for the slot, preventing incorrect staffing suggestions.
Original PR description
## Issue When using the *Auto Plan* feature on a planning slot with a Role and a Project set, a resource which operated on the same project will be chosen if available, without taking into account…
## Issue
When using the *Auto Plan* feature on a planning slot with a Role and a Project set, a resource which operated on the same project will be chosen if available, without taking into account the Role set on the slot.
## Steps to reproduce
1. Install Project Planning (`project_forecast`)
2. In Planning > Configuration > Roles, create two planning roles A and B
- Role A: Assign a resource R
- Role B: No resource
3. Open Planning (Schedule by Resource), and go back a few weeks (to prevent overlaps with potential demo data)
4. Create two new slots:
1. Set Role B and a random Project P, then click Auto Plan: there should be no available resource (because we didn't set any resource for Role B)
2. Set Role A and the same Project P, then click Auto Plan: it should assign the resource R assigned to Role A
5. After assigning a resource to the slot for Role A, edit the Open Shift for Role B again and click Auto Plan: **it assigns the same resource R, even though that resource is not assigned to Role B.**
## Cause
The `_get_open_shifts_resources` override in `project_forecast` looks for resources that were assigned to slots related to the same project. It does not filter resources based on the requested role.
https://github.com/odoo/enterprise/blob/885edbc270a86ab76e0a6eff4acb5767c0fe29d1/project_forecast/models/planning_slot.py#L104-L116
This means that resources that are not part of the requested role can be assigned to the slot, as long as the resource operated on another slot for the same project.
opw-6325744
Forward-Port-Of: odoo/enterprise#122813
Forward-Port-Of: odoo/enterprise#122035The point of sale payment screen now only runs India-specific invoice logic when the company is in India. This prevents unnecessary errors in other countries and keeps invoice toggling reliable for affected users.
Original PR description
Toggle invoice button was making a call in IN localization even when not in a IN country. This was causing an error in runbot 940146. This commit fixes the issue by checking if the country is IN before making the call. In `pos_settle_due` the method signature was not correct. Forward-Port-Of: odoo/enterprise#123539
Fixes an issue where selecting restricted users or resources on an appointment slot could crash the form. This keeps appointment slot setup usable and ensures choices are limited to the users and resources configured for the appointment type.
Original PR description
Clicking the "Restrict to User" or "Restrict to Resources" field on a slot crashed with:
invalid input syntax for type integer: "appointment_type_id.staff_user_ids"
The field domain was a quoted string instead of a list, so it was passed through as a literal value. Remove the domain: it never filtered anything and only broke the form.
opw-6349497
Forward-Port-Of: odoo/enterprise#122651The SEPA Direct Debit payment option no longer shows the backend-oriented “(provider)” label to customers. This keeps the checkout and payment experience clearer and more professional for end users.
Original PR description
Commit e90e1cd0 mistakenly suffixed the name of the SEPA Direct Debit `payment.method` record with "(provider)" while making payment methods provider-specific, aligning it with the `account.payment.method` record. However, `payment.method` records are customer-facing and should therefore not display hints intended for backend users. Forward-Port-Of: odoo/enterprise#123507
The Frontdesk app now correctly includes the component it needs to display scheduling information. This helps prevent errors when using Frontdesk features that rely on the planning timeline view.
Original PR description
runbot-237869 Forward-Port-Of: odoo/enterprise#123613 Forward-Port-Of: odoo/enterprise#122292
This fix prevents the grid view from crashing when a user hovers or edits a cell while the underlying data is refreshed. It improves reliability for users working with grid-based screens by safely ignoring outdated cell references and adds coverage to prevent the issue from returning.
Original PR description
Follow-up to PR https://github.com/odoo/enterprise/pull/122948, which
replaced the useGridCell useLayoutEffect with onMounted+onPatched. The
migration introduced an undeterministic bug, sometimes logging:
TypeError: Cannot read properties of undefined (reading 'row')
at updateGridCell -> onPatched
CAUSE: In the migration we dropped the dep-array: the effect now runs on
EVERY patch, not only when reactive.cell changes. When a cell is hovered
/edited and the model data is then rebuilt, reactive.cell still points at
the old cellEl whose dataset.row/column no longer resolve, so getCell()
returns undefined and `state.cell.row` throws the error above.
FIX: Introduce a new guard that was not required beofre
Link the underterministic error:
https://runbot.odoo.com/odoo/runbot.build.error/941501?menu_id=405Merging manufacturing orders now removes pending quality checks from the cancelled source orders. This prevents outdated quality tasks from remaining visible and avoids confusion for manufacturing and quality teams.
Original PR description
Version: -------- - 18.0+ Steps to reproduce: ------------------- - Install `quality_mrp` - Create a manufactured product with a BoM - Create a Quality Point for the `Manufacturing` operation of that…
Version: -------- - 18.0+ Steps to reproduce: ------------------- - Install `quality_mrp` - Create a manufactured product with a BoM - Create a Quality Point for the `Manufacturing` operation of that product - Create and confirm multiple Manufacturing Orders - Verify that each MO generates a quality check - From the MO list view, select the MOs and merge them from the gear menu(merge) Issue: ------ When Manufacturing Orders are merged, All MOs are cancelled but it keep their quality checks in the 'To Do' state. As a result: - The quality checks remain linked to cancelled MOs - The 'Quality Checks' smart button is still displayed on cancelled MOs Expected behavior: ------------------ - Pending quality checks should be deleted when the MO is cancelled - The 'Quality Checks' smart button should no longer be displayed Cause: ------ A previous fix introduced logic to remove pending quality checks when a Manufacturing Order is cancelled: odoo-dev@db93bd2 This logic was implemented in `action_cancel()` by unlinking quality checks associated with the cancelled MO: https://github.com/odoo/enterprise/blob/20bc0eb5c2cec67eecd3b44450934e23370b48f2/quality_mrp/models/mrp_production.py#L94-L97 However, when MOs are merged, the merge flow does not call `action_cancel()`. Instead, it directly invokes `_action_cancel()` on the source Manufacturing Orders: https://github.com/odoo/odoo/blob/aca0b7289c68fc7a75d47ab313f5f791ebf30f7d/addons/mrp/models/mrp_production.py#L2480 Since the quality check cleanup is implemented only in `action_cancel()`, it is bypassed during the merge process. As a result, the source MOs are cancelled but their pending quality checks remain in place. --- opw-6260735 Forward-Port-Of: odoo/enterprise#121809 Forward-Port-Of: odoo/enterprise#119525
Canadian check printing now hides check numbers on payment stubs when pre-numbered checks are used. This keeps the stub layout consistent with the actual check and avoids showing duplicate or unwanted numbering.
Original PR description
The check itself respected the check_manual_sequencing field, but the stubs did not. Hide the numbers on stubs as well, exactly like on US checks. task-6343701 Forward-Port-Of: odoo/enterprise#122565
Bank reconciliation entries that use tax models now correctly show the taxable base amount instead of $0.00. This helps accounting teams review tax-related journal entries accurately without needing to reset entries to draft to refresh the value.
Original PR description
### Steps to reproduce the issue: 1. Download Accounting 2. Go to Journal entries and create a new one 3. Click Toggle Studio button and go to the view to add the tax_base_amount field to the list of…
### Steps to reproduce the issue: 1. Download Accounting 2. Go to Journal entries and create a new one 3. Click Toggle Studio button and go to the view to add the tax_base_amount field to the list of existing fields 4. Add 2 lines (example): 1. account Product Sales with 1000 dollars credit and 15% tax under Tax column 2. account Bank with 1000 dollars debit 5. Go to Dashboard > Bank > Click the 3 dots of one random bank matching line and click on Manage Models 6. Go to bank fees and add the 15% tax 7. Go back to bank reconciliation and create a new one of 2000 dollars with label bank fees (it will associate the tax automatically) 8. Go back to Journal Entries, group by Journal and search for the transaction of 2000 sollars for account Bank 9. Problem: see that the Base Amount for the 15% bank fees lines (251000 Tax Received account) is 0. Clicking on Reset to draft button the base amount column is automatically updated but this should happen automatically ### Cause of the issue: This occurs because the _lines_prepare_tax_line method in account.bank.statement.line fails to map this field in its return dictionary. ### Reason to introduce the fix: Currently, when applying a reconciliation model with taxes the generated tax lines incorrectly record a tax_base_amount of $0.00. Instead, it should be displayed and calculated. opw-6220948 Forward-Port-Of: odoo/enterprise#123603 Forward-Port-Of: odoo/enterprise#122139
Fixes an issue where quotations created from a sales opportunity could be hidden when viewing the opportunity's quotation list. This ensures rental-related filtering correctly recognizes standard quotations, helping sales teams find and manage all relevant quotes.
Original PR description
Steps to reproduce: 1. Install sale_crm and sale_renting_crm 2. Create an opportunity 3. On this opportunity, create two quotations from the `New quotation` button 4. From the opportunity's form…
Steps to reproduce:
1. Install sale_crm and sale_renting_crm
2. Create an opportunity
3. On this opportunity, create two quotations from the `New quotation` button
4. From the opportunity's form view, click on the `Quotation` smart button
Issue:
- The quotations are not visible in the list view
Why?
- In module `sale_renting_crm`, we override the domain to exclude rental quotations.
https://github.com/odoo/enterprise/blob/fda037c62a6661665611fb061718c01aec39ac1b/sale_renting_crm/models/crm_lead.py#L33-L36 But from the saas-19.3 `is_rental_order` field is no longer stored in the DB, It is computed now and filtered through `_search_is_rental_order`.
https://github.com/odoo/enterprise/blob/fda037c62a6661665611fb061718c01aec39ac1b/sale_renting/models/sale_order.py#L223-L227 The search method did not properly handle the Boolean search shape used by the ORM, so the quotations were incorrectly filtered out. In our case, we gave the domain `("is_rental_order", "=", False)` but the operator is translated to `not in` and value to `Orderedset([True])` by the domain optimiser
Solution:
- Update `_search_is_rental_order()` to handle the ORM-normalized boolean search correctly for rental and non-rental quotations.
opw-6304696
Forward-Port-Of: odoo/enterprise#120869Code cleanup and technical improvements
Spreadsheet-related screens were updated to use the newer Owl 3 framework patterns. This is an internal modernization that helps keep spreadsheet features maintainable and compatible without changing expected user workflows.
Original PR description
*=spreadsheet_sale_management As part of the Owl 3 migration, replace onWillUpdateProps hook with the appropriate Owl 3 alternatives.
This change updates several Odoo Enterprise apps to use a newer shared method for detecting small screens, preparing the product for the next version of its interface framework. It should not change day-to-day behavior, but helps keep mobile and responsive views reliable as the underlying technology evolves.
Original PR description
This commit is a step to remove the env. The env does not exist in owl3 anymore but still exists in odoo. In this commit, `isSmall` is removed from the env, we can get it from the ui service.
The web enterprise home menu was updated as part of the Owl 3 migration, replacing older internal update handling with the newer supported approach. This helps keep the interface maintainable and ready for future platform improvements without changing business workflows.
Original PR description
As part of the Owl 3 migration, replace onWillUpdateProps hook with the appropriate Owl 3 alternatives.