Friday, September 4, 2026
108 changes · master
Resolved issues and error corrections
Portal navigation breadcrumbs were standardized across several customer-facing pages, including the quotes page. This makes the portal experience more consistent and easier for customers to navigate.
Original PR description
Breadcrumbs were added to most portal pages [here][1]. This commit adds breadcrumbs to `/my/quotes` and fixes UI issues to ensure all portal pages with breadcrumbs look the same. [1]: https://github.com/odoo/odoo/commit/123d5876900a73f674a2286e891b2e442f63d93c task-6365169
This update fixes reliability issues in guided onboarding tours, especially when tours switch modes, open the editor, or move across pages. Users should experience fewer interrupted or incorrectly validated tour steps in areas such as website forum onboarding.
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The stock replenishment wizard now has clearer help text, visible tooltips, a slightly larger input field, and smoother refresh behavior. These small usability fixes make replenishment tasks easier and less disruptive for users.
Original PR description
bunch of small fixes that can be merged fast - show tooltips - reword tooltip - remove unused libraries - use soft reload - make the input field slightly larger task 6304907 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where Odoo live chat embeds could block browser keyboard shortcuts such as Alt+D on external websites. The shortcut overlay now only intercepts the Alt key when there are actual Odoo shortcut hints to show, preserving normal browser behavior otherwise.
Original PR description
Description of the issue/feature this PR addresses: When `im_livechat` (or any page) boots the OWL web stack with no `[data-hotkey]` / `withOverlay` targets, pressing Alt still called…
Description of the issue/feature this PR addresses: When `im_livechat` (or any page) boots the OWL web stack with no `[data-hotkey]` / `withOverlay` targets, pressing Alt still called `preventDefault()` in `hotkey_service`. That blocked browser shortcuts such as Alt+D (focus address bar) on websites that embed the livechat scripts. See https://github.com/odoo/odoo/issues/267928 Current behavior before PR: - Pressing the overlay modifier (Alt, or Ctrl on macOS mapped to `"alt"`) always set `overlaysVisible = true` and called `preventDefault()`, even when there were no hotkeys to overlay. - A follow-up key (e.g. D while Alt is held) then also hit `preventDefault()` because overlays were considered visible. - Loading `/im_livechat/loader/...` + `assets_embed.js` on an external site therefore broke browser Alt shortcuts. Desired behavior after PR is merged: - `addHotkeyOverlays` returns whether overlays were actually displayed. - `preventDefault` on the overlay modifier runs only when there is at least one overlay target. - Pages with no hotkeys (typical livechat embed) leave browser shortcuts alone. - When hotkeys exist, Alt still shows overlays and cancels the default, same as before. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284145
This fixes a Point of Sale issue where the cash drawer could fail silently after refreshing the session because the default printer was not always remembered. The system now consistently saves the printer choice and prompts staff to select one when needed, helping checkout operations run smoothly.
Original PR description
Steps to reproduce: - Set only one printer with cashdrawer - Open PoS - Try to open the casdrawer => Silently won't open Issue: defaultPrinter was only saved in localstorage when various printer was set on the config. Fix: Now the printer is always saved in the localstorage so that when the pos is refresh, defaultPrinter is always set. Also when trying to open the cashdrawer if various printer are set in the config, make sure that the select default printer popup is shown. Task-6519466 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285689
Product pages now keep multi-checkbox options unselected unless the shopper chooses them. This prevents confusing automatic selections and unwanted URL changes after refreshing a product page.
Original PR description
**Steps to reproduce:** 1. Create a product. 2. Add two attributes: multi-checkbox and any single-select type (e.g. Radio). 3. Publish the product and open its page on eCommerce. 4. Verify that no…
**Steps to reproduce:**
1. Create a product.
2. Add two attributes: multi-checkbox and any single-select type (e.g. Radio).
3. Publish the product and open its page on eCommerce.
4. Verify that no multi-checkbox option is selected by default.
5. Refresh the page twice.
**Issue:**
On the second page refresh, the first option of the multi-checkbox attribute is automatically selected, and the URL is updated with its parameter.
**Cause:**
- `_prepare_product_values` construct attribute combinations by mapping requested `attribute_values` query parameters line by line.
- When URL query parameters were present (e.g., set after the first refresh), the fallback logic `or ptal.product_template_value_ids.filtered('ptav_active')[:1]` treated unselected `multi_checkbox` attribute lines as missing required selections rather than empty selections, forcing them to default to their first active option.
**Fix:**
If no selection is provided for `multi_checkbox` line, return an empty recordset instead of falling back to the first active option.
opw-6494697
Forward-Port-Of: odoo/odoo#286492
Forward-Port-Of: odoo/odoo#284798Custom website snippet previews now display oversized responsive text more accurately in the snippet selection dialog. This helps editors recognize saved snippets without the preview being distorted, while leaving the actual page content unchanged.
Original PR description
Steps to reproduce: - Go to the website editor. - Add a snippet with editable text to the page. - Select the text and set its font size to 144. - Save the edited block as a custom snippet. - Open the…
Steps to reproduce: - Go to the website editor. - Add a snippet with editable text to the page. - Select the text and set its font size to 144. - Save the edited block as a custom snippet. - Open the snippets dialog. - Go to the Custom category. => The custom snippet preview shows the text too large. Before this commit, responsive font sizes using `clamp()` with a `vw` term were rendered too large in the block dialog. The `vw` value was based on the full preview iframe width, while snippets were displayed inside columns. After this commit, the block dialog adjusts `vw` values on cloned `.o_rfs` preview content only, so the preview matches its column width without changing the snippet dropped on the page. task-6303725 | BEFORE (font size -> 144) | AFTER (font size -> 144) | | ------------- | ------------- | | <img width="416" height="409" alt="image" src="https://github.com/user-attachments/assets/e0eb0a4e-eb7b-4ee6-b080-536ea2a75c68" /> | <img width="421" height="272" alt="image" src="https://github.com/user-attachments/assets/6468a234-0966-45c9-9435-e97d9752b794" /> | Forward-Port-Of: odoo/odoo#286228 Forward-Port-Of: odoo/odoo#273257
The website shop editor no longer crashes when users choose the Grid catalog preset in the products design panel. This makes product page customization more reliable by preventing duplicate preset controls from conflicting internally.
Original PR description
Steps to reproduce: 1. Open the website editor on /shop. 2. Select the products grid and expand Products Page in the sidebar. 3. Click the Design button to open the Products Design sliding panel. 4. Click the 4th preset (Grid catalog) in the Preset picker. Before this pr: - The page crashed with a render loop error. After this pr: - presets can be picked normally, no crash. The preset list was being drawn twice at once, and both copies were registering under the same internal ID. Now each copy gets its ownnsuffixed ID, so they don't clash anymore. Also removed a redundant duplicate t-if on BuilderSelectItem already covered by its parent t-if. Also removed a dead label.translate="Presets" attribute that ProductsDesignPanelPresets never reads. opw-6478531 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284636
Fixes a spelling mistake in the website editor’s Instagram video embed option. Users will now see “Instagram” spelled correctly when adding an Instagram reel, making the editor look more polished and professional.
Original PR description
Steps to reproduce: - Edit existing page. - Paste any Instagram reel. - In powerbox Instagram entry is listed as "Embed Intagram Video". Introduced by https://github.com/odoo/odoo/commit/2bae2abd4db704451234b115eb4942dcae7d8afa This commit fixes typo. Forward-Port-Of: odoo/odoo#286529
The demo payment provider now handles refunds correctly after a manually captured payment. This prevents users from getting stuck with a negative authorized amount and keeps refund testing flows reliable.
Original PR description
Issue: --- When using manual capture, you can refund the transaction but it will be only authorized, and you'll then be blocked with a negative authorized amount and the impossibility to refund it. This seems to be specific to demo payment provider. Steps: 1- Enable manual capture on demo provider. 2- Buy a product from shop and checkout and pay. 3- Capture the payment in backend. Then click on post process. 4- Try refund. opw-6413515 Forward-Port-Of: odoo/odoo#286625 Forward-Port-Of: odoo/odoo#282315
This fixes an issue where some already-applied website editor options could be ignored when their priority value was negative. It helps ensure the editor correctly recognizes the selected option, improving reliability for users editing page components.
Original PR description
The function `useSelectableComponent` looked for the selected option by searching for the option with the highest priority among the options that are applied. The search for highest priority implicitely excluded options with negative priority. This case happens with `composite` action when the inner actions have no definition of `getPriority`. This commit initialize the "highest priority found so far" as `-Infinity` instead of 0. task-5245362 Forward-Port-Of: odoo/odoo#286652 Forward-Port-Of: odoo/odoo#286503
Users can now download spreadsheets with inserted images as Excel files without hitting an access error. The export process now uses the image access permissions already used in the web interface, so shared spreadsheet images remain available during export.
Original PR description
Since https://github.com/odoo/enterprise/pull/97488, the images are shared across spreadsheets and the attachments are no longer related to a specific record. Due to the management of the…
Since https://github.com/odoo/enterprise/pull/97488, the images are shared across spreadsheets and the attachments are no longer related to a specific record. Due to the management of the IrAttachment access rights, it means that those attachments are not accessible by anyone by default and we rely on the access_token to display them in the webclient. However, the method that builds the final xlsx file fetches the images from the server and did not use the access token, meaning that it could never access the attachment. Such situation raised a UserError that was caught by the webclient. How to reproduce: - As admin, create a spreadsheet and insert an image inside of it - try to download the spreadsheet as an xlsx file counterpart of https://github.com/odoo/enterprise/pull/126384 Task-6432724 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285981 Forward-Port-Of: odoo/odoo#279788
This update fixes outdated internal documentation about how temporary records are accessed. It clarifies that these records follow normal access rights and record rules, reducing confusion for teams maintaining or auditing permissions.
Original PR description
Since 6d8688bb124d, TransientModel records use the regular access rights mechanisms instead of being implicitly restricted to their creator. The docstring was not updated with that change and has therefore incorrectly documented creator-only access since 14.0. Forward-Port-Of: odoo/odoo#286374 Forward-Port-Of: odoo/odoo#286251
Italian electronic invoices now list only the relevant linked down payment document instead of including unrelated past invoices or the current credit note. This helps avoid incorrect FatturaPA XML content and reduces confusion or compliance issues when issuing credit notes and final invoices.
Original PR description
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without…
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without reconciling it with anything else. - Generate the FatturaPA XML for credit note A. - Observe that DatiFattureCollegate lists both down payment invoice A and credit note A itself, instead of only down payment invoice A. On an order with several down payment invoices/credit notes over time, every one of them is listed instead of just the document the current credit note actually reverses. Cause of the issue: _l10n_it_edi_export_data built downpayment_moves from self.invoice_line_ids._get_downpayment_lines().move_id with no filtering. _get_downpayment_lines() (sale override) returns every invoice line ever created against the same down payment sale order line, across the whole life of the order, not just the invoice the current document actually relates to. The template renders DatiFattureCollegate for every one of those moves unconditionally, on top of the already-correct reversed_entry_id/reconciled_moves fallback, including the current document itself. Solution: Restrict downpayment_moves to lines with a negative price_subtotal, mirroring the existing down payment deduction-line detection a few lines above, and explicitly exclude the current document. This limits DatiFattureCollegate's down payment entries to the case they are meant for: a final invoice actually deducting a previously invoiced down payment. opw-6429716 Forward-Port-Of: odoo/odoo#285555 Forward-Port-Of: odoo/odoo#279938
The onboarding walkthroughs for Rental and Studio were adjusted so automated guided tours run correctly. This helps keep setup guidance reliable for users and prevents validation issues in tour steps.
Original PR description
rental_tour: use stepUtils.saveForm() instead of a manual save click, and add missing isActive:["manual"] twins for autocomplete selection steps. web_studio_new_app_tour: drop two timeout keys rejected by the onboarding step schema.
Belgian payroll attestations now handle employee contracts that do not have an end date. This prevents errors or incorrect occupation information for ongoing contracts, improving payroll document reliability.
Original PR description
A check was missing if the contract end date was false Forward-Port-Of: odoo/enterprise#130410 Forward-Port-Of: odoo/enterprise#130346
The UK CIS report now correctly includes payment information for receipts that use CIS taxes. This ensures businesses get a more complete and accurate view of CIS-related transactions, not just vendor bills.
Original PR description
With the l10n_uk_reports_cis module installed: - Create a vendor bills and add a CIS tax --> This vendor's bills appear correctly in the report. - Create a receipt and add a CIS tax --> This type of bill appears in the report, but the payment is not showing up. opw-6282548 Forward-Port-Of: odoo/enterprise#129395 Forward-Port-Of: odoo/enterprise#124043
This fixes an issue in Project Forecast where automatic planning could behave incorrectly when several roles were involved. Businesses using role-based forecasting should see more reliable planning results and fewer manual corrections.
Original PR description
task-6484707 Forward-Port-Of: odoo/enterprise#130166 Forward-Port-Of: odoo/enterprise#128541
DHL shipping in Odoo no longer automatically requests a package pickup. This removes the need to set pickup windows, reduces DHL configuration errors, and makes DHL behave more consistently with other shipping carriers.
Original PR description
Before this commit, the DHL REST module had the pick-up request set, which led to an unnatural use flow, needing to set up an scheduled date for pick-up, and several errors from DHL when these were not properly configured. This feature was unique to this module among the shipping carriers as we don't normally request pick-up for packages and leave it to user to decide how to do it. This commit removes the request for pick up and the logic that was needed to make it work. This will make the behavior consistent with other carriers in Odoo, and avoids the need to set scheduled pick-up windows and having to deal with unnecessary errors. opw-6148927 Forward-Port-Of: odoo/enterprise#123773
The event booth registration page now ignores outdated booth lists when visitors switch categories quickly. This prevents the page from showing booths from the wrong category and helps exhibitors complete booth selection without needing to reload.
Original PR description
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones…
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones back. The tour webooth_exhibitor_register timed out on that list: FAILED: [5/13] Tour webooth_exhibitor_register -> Step Choose Booth (trigger: .o_wbooth_booths div:contains(OpenWood Demonstrator 2) input:not(:visible)). TIMEOUT step failed to complete within 10000 ms. This happens because the page fetches the booths of the category checked on load, and clicking another category fetches its booths while that first answer is still on its way. The answer coming back last fills the list, and the widget caches it under the category active on arrival, so the booths of the first category land in the cache of the clicked one. This commit fixes the issue by caching an answer under the category it was asked for, and by filling the list only while that category is still the chosen one. https://runbot.odoo.com/odoo/error/110527 https://runbot.odoo.com/odoo/error/161834 Forward-Port-Of: odoo/odoo#286552 Forward-Port-Of: odoo/odoo#286266
French tax closing entries now correctly include VAT credits carried over from the previous period. This helps ensure VAT returns and journal entries comply with French accounting requirements and avoid missing credit balances.
Original PR description
### Issue before this commit: When generating a tax closing entry for France, the VAT credit carryover from the previous period is missing from the journal entry lines. ### Steps to reproduce the…
### Issue before this commit: When generating a tax closing entry for France, the VAT credit carryover from the previous period is missing from the journal entry lines. ### Steps to reproduce the issue: 1. Download Accounting and l10n_fr 2. Go to Vendor > Bills 3. Create a vendor bill with date in June and price > 0 (ex. 1000$) and the 20% G tax that produce a 200$ VAT tax 4. Go to Customers > Invoices 5. Create an invoice with price > 0 (ex. 9000$), the date in July and the 20% G tax that will produce a 1800$ VAT tax 6. Go to Tax Return and validate all opened months up to July and see that for June the balance is -200$ 9. Then go to View Entries of July using the 3 dots next to the "submit" button and see that there is no mentioning of the 200$ carry over of credit from the month before ### Cause of the issue: The issue stems from a structural change in the core code where the logic to evaluate and balance the tax receivable account was removed from the _add_tax_group_closing_items method. Consequently, the VAT closing entry now only processes the current period's taxes and there is no reporting of any carried-forward VAT credits. ### Reason to introduce the fix: French accounting rules strictly require the carried-forward VAT credit to be explicitly integrated into the current period's tax closing entry. opw-6438648 Forward-Port-Of: odoo/enterprise#130377 Forward-Port-Of: odoo/enterprise#129181
This update adds test coverage to ensure spreadsheets exported to Excel keep embedded images correctly. It helps reduce the risk of broken exports for users sharing or downloading spreadsheet documents.
Original PR description
Counterpart of https://github.com/odoo/odoo/pull/279788 Task-6432724 Forward-Port-Of: odoo/enterprise#130172 Forward-Port-Of: odoo/enterprise#126384
This fix removes sample planning data that could fail to load when an optional project planning feature is not installed. It helps ensure the Helpdesk, Field Service, Sales, and Timesheets integration installs reliably without requiring an unrelated module.
Original PR description
…ct on helpdesk intervention Before this commit, `project_id` field in `planning.slot` only exists if `project_forecast` module is installed. However, when `helpdesk_planning_field_service_sale_timesheet` is installed, we cannot guarranty `project_forecast` module is also installed since it is not in the dependencies of `helpdesk_planning_field_service_sale_timesheet` module. This commit just removes the demo data inside `helpdesk_planning_field_service_sale_timesheet` module. Forward-Port-Of: odoo/enterprise#130433
The French VAT reporting flow now checks for duplicate XML declarations before sending them to Aspone. This helps avoid rejected submissions and prevents unnecessary paid contacts with the service provider.
Original PR description
When sending an xml to aspone, they will check if a duplicate declaration exist, and if it's the case, then they will refuse it. Since contacting aspone cost us money we will block the sending before that. task-6420220 Forward-Port-Of: odoo/enterprise#130406 Forward-Port-Of: odoo/enterprise#127953
This fix prevents point-of-sale online payments from appearing twice in an order's payment history after confirmation. It also avoids an error when online self-ordering settings are unavailable, improving reliability for stores using POS online payments.
Original PR description
Also, bug noticed while working on task-6472188
Opening a project task in the customer portal could fail when the Timesheets app was not installed. The fix keeps time formatting available from the Project app itself, so portal task pages load reliably in more setups.
Original PR description
Before this commit, opening the portal page of a task in a database without hr_timesheet answers a 500:
AttributeError: 'account.analytic.line' object has no attribute
'_format_portal_hours'
This happens because project's portal_my_task_allocated_hours_template formats the allocated time with `_format_portal_hours`, a method hr_timesheet adds on `account.analytic.line`.
This commit moves that method to project, next to the template that calls it.
https://runbot.odoo.com/odoo/error/946944This fixes a small display issue where expanded inventory valuation lines still showed a closed-folder icon. Users now get the correct visual cue when sublines are open, reducing confusion while reviewing stock valuation details.
Original PR description
c5a40a608280 ([IMP] *: apply new icon implementation globally) introduced a typo: it replaced a working `fa-folder#{this.state.displaySublines ? '-open' : ''}-o` with the new icon API and dropped the `s` on the way. Only master carries that rewrite, so this is master-only -- saas-19.4 and older still have the FontAwesome form and are correct there.
Additionally before the commit rewrite the icon was never filled so we drop the fill condition as wellBelgian payroll meal voucher reports now correctly include postponed vouchers for employees assigned to a branch company. This prevents missing carryovers when payroll documents are created under a branch while the report is managed by the parent company.
Original PR description
Steps to reproduce: - Create a July payslip for Bernice and mark it as paid - Generate the meal voucher report for july - Create 3 time off for Bernice in July - Correct the payslip of July, in total…
Steps to reproduce: - Create a July payslip for Bernice and mark it as paid - Generate the meal voucher report for july - Create 3 time off for Bernice in July - Correct the payslip of July, in total we have 3 payslips now - Create an August payslip for Bernice - Create the meal voucher report for august Pay attention to: everything has been created under "My Belgian Company" while Bernice is in the branch "My Belgian Office" Current Behaviour: When the august mealvoucher report is not marked as done, the postponed shows 0 for Bernice. Expected Behavior: When the report is not marked as done, august should have 3 mealvoucher postponed for Bernice. The technical reasons behind this bug is that the SQL query for unreported payslips mapped to draft/ready reports filtered the payslips `company_id` on the mealvoucher `company_id`. But payslips for Bernice are under the branch "My Belgian Office" and the mealvoucher is created in "My belgian company". The SQL query should take company branches into account, same as in `_get_corrected_payslips`. task-6428719
The map view now uses the record limit defined by the action when no specific map limit is set. This makes map behavior consistent with other views and helps users see the expected number of records.
Original PR description
The map view only considered the `limit` set in the arch, ignoring the one coming from the action (`ir.actions.act_window.limit`), unlike other views (list, kanban) which fall back to it. task-6531776
Discount reward products are now created without automatically applying the company's default sales tax. This prevents discounts from being taxed incorrectly and keeps loyalty reward calculations aligned with expected untaxed discount behavior.
Original PR description
The reward's discount_line_product_id was created without an explicit taxes_id, so it silently fell back to the company's default sale tax (account_sale_tax_id) instead of staying untaxed like the rest of the program's discount/reward mechanics expect. Explicitly clear taxes_id when creating the discount product. task-6528122
This fix prevents automated accounting-related processes from failing when they run with elevated permissions on behalf of users who do not have accounting access rights. It helps modules that need accounting reports, such as localization reporting, complete setup or return creation reliably.
Original PR description
This was spotted in a dev branch for master, where we set a default account_opening_date on every company, hence trying to directly create the returns for it. Some modules need to call reports for that (like intrastat l10n), and do it in sudo(). However, even in sudo, a user without the accounting rights still doesn't have the proper group, and it raises an exception. We hence adapt the condition. Forward-Port-Of: odoo/enterprise#130448
This fixes a small visual issue where the side area of kanban cards could have slightly mismatched rounded corners. The update makes card styling more polished and consistent by accounting for the card border when applying corner rounding.
Original PR description
Ensure the aside element gets the right `border-radius` value by taking the `border-width` of the kanban card into account when computing the radius value. task-6537730 | Master (top radius is incorrect due to the border width) | This PR (take the border width into account) | |--------|--------| | <img width="122" height="186" alt="image" src="https://github.com/user-attachments/assets/ec39123d-f874-4374-805e-82371d5ed8d4" /> | <img width="125" height="191" alt="image" src="https://github.com/user-attachments/assets/25ba6513-d1b3-4f18-805d-afa83c152bff" /> |
Point of Sale screens now keep category images inside their buttons and use higher-resolution product images. This makes the sales interface cleaner and easier to recognize items quickly during checkout.
Original PR description
Category images overflowed their buttons because width-based ratio classes conflicted with the fixed button heights. Furthermore, product images appeared blurry because the low-resolution `image_128` was stretched to fit modern product cards. This ensures category images respect parent boundaries and fetches higher resolution product images. task-6479160
Time entries recorded outside an employee's normal schedule now behave correctly. Working time is counted as requested, while absences outside the schedule now show a clear message instead of silently recording zero time.
Original PR description
…dule Encoding a time type outside an employee's working schedule silently did nothing: 0 duration, no feedback, for both working time and absence types. Working time entries now count the requested time instead of 0. Absences still can't be taken outside the schedule, but now say so instead of silently doing nothing. Task-6501553
Fixes visual spacing problems introduced by the Frost design in list, kanban, and search panel views. This keeps the Community interface cleaner and more consistent while moving edition-specific styling to the right place.
Original PR description
Since the introduction of the Frost design, some spacing customizations for the List, Kanban, and Search Panel views have been defined in Community instead of Enterprise, causing spacing issues in…
Since the introduction of the Frost design, some spacing customizations for the List, Kanban, and Search Panel views have been defined in Community instead of Enterprise, causing spacing issues in Community. To fix this, this commit moves the relevant customizations to Enterprise and adapts them accordingly. task-6527607 Requires: - https://github.com/odoo/enterprise/pull/130335 | Before | After | |--------|--------| | <img width="1914" height="769" alt="Screenshot 2026-09-03 at 16 41 22" src="https://github.com/user-attachments/assets/9fa1be40-e3ff-4679-a739-dc86de516607" /> | <img width="1916" height="756" alt="Screenshot 2026-09-03 at 16 39 55" src="https://github.com/user-attachments/assets/6c6530f6-b20f-4339-b1ce-2ac4d7f8b837" /> | | <img width="1915" height="723" alt="Screenshot 2026-09-03 at 16 41 20" src="https://github.com/user-attachments/assets/0f7abbea-d9ab-4850-9d7f-7aae0995321b" /> | <img width="1918" height="753" alt="Screenshot 2026-09-03 at 16 39 46" src="https://github.com/user-attachments/assets/03855cf2-28b5-4b26-9fe2-30a9f9eec3d5" /> | | <img width="1918" height="550" alt="Screenshot 2026-09-03 at 16 41 05" src="https://github.com/user-attachments/assets/c4c6c703-55e9-4653-90c1-c6ce93610c0a" /> | <img width="1917" height="598" alt="Screenshot 2026-09-03 at 16 40 59" src="https://github.com/user-attachments/assets/02af42f0-84ed-457a-870c-8afd3efb0bcd" /> | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change restores the correct table layout in the inventory report after a previous update caused extra columns to appear in the report body. It helps ensure inventory information is displayed clearly and consistently for users reviewing stock reports.
Original PR description
This reverts commit 43add3f72f29c35280869010b897c3c5656f5120. It was adding too many columns in table body after columns were removed from the header in 19.0. opw-6307728 Forward-Port-Of: odoo/odoo#286294
This fixes a visual spacing issue in the control panel actions that could appear when custom actions were added. It helps keep the interface aligned and consistent after recent UI updates.
Original PR description
After the new ui improvements the control panel actions had some styling issues when xpath is used to add new actions. no task id
Accounting now correctly flags a draft journal entry as creating a numbering gap when a later entry is posted after it. This helps businesses maintain clearer audit trails and avoids unnoticed gaps in journal entry sequences.
Original PR description
To reproduce: * create and post 2 journal entries in the same journal * reset to draft the entry with the highest number * create and post a third entry in the same journal The draft entry is not flagged as having made a gap, because at the time of resetting it to draft, it was the last entry and therefore didn't really make a gap. 3 options to solve were considered: * flag all moves when reseting to draft even if they were the last of the chain * if we reset the last move of the sequence to draft, also remove its sequence and put it back to `/` * when posting, check if the previous number was draft. If it was the case, flag it. The last options was taken in this fix to avoid changing the previous behavior while fixing the current issue. Forward-Port-Of: odoo/odoo#286204
The VoIP sound upload area now opens the file selector when users click anywhere inside the upload zone, not just on the icon or label. This makes the form behave as users expect and reduces confusion when uploading or recording sounds.
Original PR description
In a sound form, the file selector only opened when clicking directly on the Upload icon or label. Clicking elsewhere inside the drop zone had no effect, although the entire area looked interactive. Use the complete drop zone as the FileUploader toggler and render it as a button. Also show the pointer cursor consistently on the Upload and Record zones.
Creating a salary contract offer for Belgian employees no longer triggers an unintended Dimona update. This prevents incorrect or meaningless data from being sent to the government service during salary simulations.
Original PR description
### Issue When creating a salary contract offer (smart button 'New Offer' in the employee form), a dimona action can be triggered, sending no-sense value to the government api. ### Reproducing steps…
### Issue
When creating a salary contract offer (smart button 'New Offer' in the employee form), a dimona action can be triggered, sending no-sense value to the government api.
### Reproducing steps
I've only been able to observe that by placing a breakpoint in the `hr.version.write` of the `hr_version.py` of `l10n_be_hr_payroll`:
- Create a master (1 sept. 2026) database with demo data and the following modules installed: `l10n_be_hr_contract_salary,test_l10n_be_hr_payroll_account`
- Set the dimona environment of the demo belgian company to 'Sandbox'
- Go to the employee Laurie Poiret
- Set the current contract end date to 1 day before today
- Create a dimona IN declaration for the last contract of Laurie Poiret (the one that has just been modified) (ctrl + k / DIMONA)
- On employee form: click on 'Check Dimona' and apply the response, the state of the dimona should appear ('Done')
- Create a new contract ('New Contract' button on the employee payroll tab) and set it to today
- Change the contract start date to tomorrow so that the dimona state become 'In progress'
- Click on the smart button 'New Offer'
- See that the `hr.version.action_update_dimona` is executed (but it shouldn't)
task-6521357This fix restores the intended visual spacing in key Enterprise views after design-related styles were placed in the wrong edition. Users should see more consistent layout spacing in list, kanban, and search panel areas, while Community no longer inherits Enterprise-specific spacing behavior.
Original PR description
Since the introduction of the Frost design, some spacing customizations for the List, Kanban, and Search Panel views have been defined in Community instead of Enterprise, causing spacing issues in Community. To fix this, this commit moves the relevant customizations to Enterprise and adapts them accordingly. task-6527607 Requires: - https://github.com/odoo/odoo/pull/286518 | Before | After | |--------|--------| | <img width="400" height="302" alt="Screenshot 2026-09-03 at 16 44 42" src="https://github.com/user-attachments/assets/4872fb70-cc75-4d8b-80d2-6d5ff44fe1b0" /> | <img width="399" height="301" alt="Screenshot 2026-09-03 at 16 44 45" src="https://github.com/user-attachments/assets/92ff245a-7416-4652-98b1-1a90951cc8c3" /> |
This fix prevents Belgian payroll payslips from creating duplicate input lines when a payslip is recalculated. It keeps payroll records cleaner and helps avoid incorrect or confusing payroll calculations after edits.
Original PR description
Steps to reproduce: - Create a December BE payslip so SIMPLE_DECEMBER/DOUBLE_DECEMBER_BASIC get seeded (or any struct feeding a BE-specific input code). - Trigger a recompute (edit date_from and save again). - Input line for that code is duplicated instead of replaced. _compute_input_line_ids's BE override only appended input lines, never unlinking the one it created last pass. Unlink existing line for a code before recreating it Task 6516068
Hourly and half-day time off requests on weekends or public holidays will no longer disappear without explanation. The system now sends these requests to the server so valid working-time entries are created and invalid absence requests return a clear message.
Original PR description
Issue: Creating an hourly or half-day (AM/PM) time off entry on a day flagged as a weekend/public holiday for the employee did nothing: no entry, no error. Cause: multiCreateRecords() pre-filtered out any such day client side via get_unusual_days(), regardless of the work entry type. Fix: Remove the client-side filter and let every selected day go through create(), with multi_leave_request set in the context so the server decides and notifies. working time entries get a real duration, absences get dropped with a clear message (see community PR). Task-6501553
Expense-created vendor receipts in Mexico now correctly include and display their CFDI XML attachment. This helps users access required tax documents directly from the bill and ensures these receipts can be checked with SAT services when needed.
Original PR description
**Current behavior:** Currently, account moves created from expenses (type receipt) don't include the XML when it is a CFDI. Causing users cannot see their attachment even though it is created on DB. https://docs.google.com/videos/d/1eFSAA-wvUzPDwIJDeiS2dkne94lGM7QBxRfjN3HxaLw/play **Versions:** 19+ **Fix:** Implementing a new helper to identify those moves that can actually hold a CFDI document (for now, all `is_invoice()` documents + vendor bill receipt, `in_receipt`), so now, we include 'in_receipts' in _compute_l10n_mx_edi_cfdi_state_and_attachment, _compute_l10n_mx_edi_document_ids, _compute_l10n_mx_edi_update_sat_needed and l10n_mx_edi_cfdi_try_sat. As these documents might need to fetch SAT services as well. Task-id: [6397080](https://www.odoo.com/odoo/project/49/tasks/6397080) Forward-Port-Of: odoo/enterprise#130045 Forward-Port-Of: odoo/enterprise#126493
Uploading a refund from bank transactions now creates a vendor credit note in the correct purchase journal instead of a customer credit note. This helps refunds reconcile properly against vendor payables and prevents accounting errors during bank reconciliation.
Original PR description
**Steps to reproduce:** * Install **Accounting** module. * Go to **Accounting → Bank → Transactions** (bank reconciliation widget). * Open a transaction with a **positive** amount (e.g. a vendor…
**Steps to reproduce:** * Install **Accounting** module. * Go to **Accounting → Bank → Transactions** (bank reconciliation widget). * Open a transaction with a **positive** amount (e.g. a vendor sending money back). * Click the three-dot menu on the transaction line and choose **Upload a Refund**. * Upload any document (XML or PDF). **Observed behavior:** * A **Customer Credit Note** (`out_refund`) is created in a **sale** journal instead of a **Vendor Credit Note** (`in_refund`) in a **purchase** journal. * The wrong document type means the reconciliation fails to link the refund against the correct payable account. **Cause:** * In `create_document_from_attachment` (`account_bank_statement.py`), the JS widget sends `type='sale'` in context when the transaction amount is positive (JS: `amount > 0 ? "sale" : "purchase"`). * The original code mapped `type='sale'` → `default_move_type='out_refund'` (customer credit note) and searched for a `sale` journal — both wrong. * Uploading from a bank statement is always a **vendor-side** operation: negative amount = vendor bill (`in_invoice`), positive amount = vendor refund (`in_refund`). The `type` context key from JS reflects transaction direction, not the accounting document type. * Additionally, `in_refund` is a purchase document; Odoo's `_check_journal_move_type` constraint raises a `ValidationError` if a purchase document is created in a non-purchase journal, meaning the old code would crash at the ORM level for the refund path. **Fix:** * Map `type='sale'` → `default_move_type='in_refund'` (vendor credit note) instead of `out_refund`. * Always search for a **purchase** journal regardless of the `type` context value, since both `in_invoice` and `in_refund` are purchase-side documents. opw-6468779 Forward-Port-Of: odoo/enterprise#129385 Forward-Port-Of: odoo/enterprise#127912
This update adjusts how dropdown menus track their target elements as part of the ongoing web platform migration. It prevents pivot table dropdowns from losing required styling or failing to open correctly, improving reliability without changing the user experience.
Original PR description
Remove useLayoutEffect from dropdown.js as part of OWL3 migration.
Odoo now calculates Mexican CFDI payment complements using the same rounded amounts that appear in the XML. This prevents valid USD invoices with MXN payments from being rejected by the tax certification provider with error CRP20268.
Original PR description
**Steps to reproduce:** * Install the **l10n_mx** localization. * Enable **USD** and fetch the latest currency exchange rate from the settings. * Configure **Quadrum** as the **PAC** in the settings.…
**Steps to reproduce:**
* Install the **l10n_mx** localization.
* Enable **USD** and fetch the latest currency exchange rate from the settings.
* Configure **Quadrum** as the **PAC** in the settings.
* Create and sign a USD invoice with **16% IVA** (e.g. 4,500 USD + 720 USD tax = 5,220 USD total).
* Send the invoice to **CFDI**.
* Register a **partial MXN payment** that does not convert to a round USD amount (e.g. 30,000 MXN = 1,762.45 USD).
* Send the payment complement to the PAC by clicking **Update Payments** on the invoice.
**Observed behavior:**
The PAC rejects the CFDI with error **CRP20268**:
> El campo BaseP que corresponde a Traslado, no es igual a la suma de
> los importes de las bases registrados en los documentos relacionados
> donde el impuesto del documento relacionado sea igual al campo
> ImpuestoP de este elemento y la TasaOCuotaDR del documento
> relacionado sea igual al campo TasaOCuotaP de este elemento.
**Cause:**
* The SAT validator enforces a strict arithmetic relationship between three fields that are printed in the payment complement XML:
```
BaseP == round(BaseDR / EquivalenciaDR, 6)
```
* When `percentage_paid` is a non-terminating decimal (which happens for any partial MXN payment against a USD invoice), the internal `raw_base` float carries more precision than the 6-decimal-place `BaseDR` that is actually written to the XML:
```
percentage_paid = 1762.45 / 5220 = 0.33763409961685825...
raw_base = 4500 × 0.33763... = 1519.353448275862...
BaseDR (XML) = float_round(raw_base, 6) = 1519.353448
```
* The old code then used `raw_base` (the unrounded internal value) as the dividend when computing BaseP:
```
BaseP (old) = float_round(1519.353448275862... / 0.0587483333, 6)
= 25862.068980 ← written to <TrasladoP BaseP="...">
```
* The PAC performs the same division using only what it can read from the XML. The already-rounded BaseDR:
```
BaseP (PAC) = round(1519.353448 / 0.0587483333, 6)
= 25862.068975
```
* The 6th-decimal mismatch (25862.068980 ≠ 25862.068975) triggers CRP20268 and the document is rejected.
* The same issue occurs with a full MXN payment on a different date than the invoice when multiple invoice lines cause the rounded aggregate to diverge from the sum of per-line raw values.
**Fix:**
In `_l10n_mx_edi_add_payment_cfdi_values` (`account_move.py`), the block that builds the BaseP aggregation list was changed from iterating over raw per-`base_line` amounts to building a single synthetic entry per invoice using the already-rounded document-level `BaseDR` values (`tax_details['base']`) as the dividend:
- Before : wrong: raw_base ≠ BaseDR printed in the XML
'raw_base': tax_details['raw_base'] / inv_rate
- After : correct: 'base' == BaseDR, the exact value in the XML
'raw_base': tax_details['base'] / inv_rate
This guarantees that Odoo and the PAC divide the identical value, producing the identical 6-decimal result.
The `base_line_cfdi_values_mx_curr_list` path (used only for the `Totales` summary fields rounded to 2 dp) is left unchanged because the CRP20268 rule does not apply to that block.
opw-6468077
Forward-Port-Of: odoo/enterprise#128357The website scroll button now keeps a visible focus indicator when people navigate with a keyboard. This improves accessibility by making it clearer which page control is currently selected.
Original PR description
Scroll button had no outline, which is an issue for people navigating with their keyboards. Now, outline is removed with :focus, but not :focus-visible Task-6009931
Consolidated Malaysian e-invoice reports now group point-of-sale receipts only when they are truly consecutive on the same device. This prevents unrelated receipts or refund-only transactions from being hidden inside misleading ranges, making reports easier to verify and more accurate for compliance.
Original PR description
A consolidated invoice reports a range of PoS receipts per line, so every line claims that the receipts between its two endpoints follow each other. That claim was only loosely enforced: lines were…
A consolidated invoice reports a range of PoS receipts per line, so every line claims that the receipts between its two endpoints follow each other. That claim was only loosely enforced: lines were built by walking every order of the sessions involved and breaking whenever one was not part of the batch. Two receipts that were both in the batch were therefore always merged, whatever sat between them. This breaks down as soon as several devices sell under one config. Receipt numbers come from a counter local to each device, so two orders taken on two devices can carry adjacent numbers without being consecutive receipts, and were reported as a range covering receipts that were never part of it. Lines are now built from an explicit continuity test on both `sequence_number`, gapless within a config, and the receipt reference read from `pos_reference`, which must name the same device and the next receipt number. Neither is sufficient alone: an order can reach the database later than its ticket was opened, so following sequence numbers do not imply consecutive receipts either. A receipt made exclusively of refund lines is no longer merged into the line of the sales it follows. Refunds are usually rung up shortly after the sale they cancel, which made them contiguous with it and hid both inside a netted total - two sales and the two refunds cancelling them were reported as a single line of 0.00. An order mixing refund lines with new sales remains a receipt of its own, reported like any other with the amounts it refunded already deducted from it. The orders linked to a consolidated invoice are also listed in the order in which they are reported on it, rather than in the reverse chronological one used by default for PoS orders, so that the two can be read together. [task-6166533](https://www.odoo.com/odoo/my-tasks/6166533)
Fixes a billing issue where manually increasing a timesheet invoice could prevent later time entries from being invoiced. Businesses can now bill future timesheet periods correctly while keeping refund-related safeguards intact.
Original PR description
## Issue When a use rmanually increases the invoiced quantity on a timesheet invoice, subsequent timesheets logged in future periods can no longer be invoiced. The system assumes that the most recent…
## Issue
When a use rmanually increases the invoiced quantity on a timesheet invoice, subsequent timesheets logged in future periods can no longer be invoiced. The system assumes that the most recent logged hours are already covered by the previously over-invoiced amount, blocking the billing of the most recent timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P
- Product Type: Service
- Invoicing Policy: Based on Timesheets
- Create on Order: (Project &) Task
3. Create an SO:
- Customer: Any
- Product: P (any quantity)
- Confirm
4. Record hours on the task created:
- 06/01/2026 (June 1st): 1 hour
- 07/01/2026 (July 1st): 1 hour
5. Create the invoice for the June timesheet entry (by setting a timesheets period when creating the invoice), then **change the quantity to any value strictly greater than 2** and confirm.
6. Create the invoice for July
7. **An "Invalid Operation" error appears, stating that there's nothing to invoice, even though the timesheet entry from July was never invoiced.**
## Cause
Since https://github.com/odoo/odoo/commit/3b86ac3d180993239b63fd305ee0ba1f17f7eb20, the computation of the quantity to invoice changed to include the difference between the quantity delivered and the quantity already invoiced. In the flow described by the steps to reproduce above, the quantity to invoice is larger than the quantity delivered, making the `qty_to_invoice` equal to `0.0`.
https://github.com/odoo/odoo/blob/626d31fa0191bfe7ca8e1fcf177357eeeb60f2c7/addons/sale_timesheet/models/sale_order.py#L331-L334
The reason for the fix above being the partial refunding of timesheet-related invoices, we can keep that solution when working with refunded invoices, and keep the previous behavior for other cases.
This solution solves the issue in the steps to reproduce above, but was also manually tested on the issues from https://github.com/odoo/odoo/commit/3b86ac3d180993239b63fd305ee0ba1f17f7eb20 and https://github.com/odoo/odoo/commit/64cf4afabd0c5ef040cf87fc6f3125fe0bb81bbb.
opw-6485674
Forward-Port-Of: odoo/odoo#286301
Forward-Port-Of: odoo/odoo#284470This fix ensures Adyen payment information is read from the correct part of the payment notification. It helps prevent payment records from being updated with wrong or missing values, improving transaction reliability for businesses using Adyen.
Original PR description
opw-6512723 Forward-Port-Of: odoo/odoo#286391 Forward-Port-Of: odoo/odoo#284773
Website theme installation now correctly applies the selected theme's layout changes, such as headers and footers. This prevents customers from seeing an incomplete or unchanged website design after using the website configurator.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286407 Forward-Port-Of: odoo/odoo#283174
Selecting a company or contact suggestion now correctly returns the form to its saved state after the record is updated. This prevents users from seeing inactive save or discard buttons after autocomplete has already saved the enriched partner details.
Original PR description
Steps to reproduce: 1) open partner form view 2) type in the name field 3) select a suggestion from the autocomplete dropdown Issue: The record is enriched and saved, but the form still displays the save/discard buttons, and clicking them does nothing. The record dirty indicator is driven by 2 signals 1) `model.root.dirty`, which is cleared by save() call earlier in the onSelect() 2) the state `fieldIsDirty` of the `FormStatusIndicator` The second indicator is set to true when the user types in an input field, and selecting an option never clears it. The `setDirty` prop no longer exists, and therefore was deadcode. This commit emits `FIELD_IS_DIRTY` bus event, which is the only way to update the second indicator. With that, the indicator goes back to saved state once the record is updated. task-6475332 Forward-Port-Of: odoo/odoo#286651 Forward-Port-Of: odoo/odoo#285897
This fixes a crash when generating electronic invoice data in Community Edition without the Enterprise accounting add-on installed. The system now checks whether optional deferred billing date fields are available before using them, helping electronic invoicing work reliably across editions.
Original PR description
The fields `deferred_start_date` and `deferred_end_date` are created by the enterprise addon `account_accountant`, so not having it installed, this crashes with:
```
File "/opt/odoo/auto/addons/account_edi_ubl_cii/models/account_edi_cii.py", line 684, in <listcomp>
billing_start_dates += [move_line.deferred_start_date for move_line in invoice.invoice_line_ids if move_line.deferred_start_date]
AttributeError: 'account.move.line' object has no attribute 'deferred_start_date'
```
This PR protects the access to these fields checking first if they exist.
Bug introduced in the refactoring in #261572.
@Tecnativa TT64359
Forward-Port-Of: odoo/odoo#286245Portal users who follow a project can now reliably open the tasks they are allowed to see, instead of sometimes getting a “not found” error. This improves the customer portal experience by aligning task page access with the task list permissions.
Original PR description
Before this commit, the portal user could have a request not found when he wants to access to a task from a project he follows even if he can access to the task in /my/tasks route. This commit makes sure the read access are checked instead of checking if the user can access to the task thanks to the token since the token if the one of the project. Forward-Port-Of: odoo/odoo#285878
This fix prevents restaurant preparation tickets from failing during installation when the point of sale module has not yet been upgraded. It uses a more stable receipt section that already exists across versions, reducing manual upgrade steps and avoiding issues for customized setups.
Original PR description
The template for the preparation tickets was using an xpath targeting a newly added div element. This raised an error when installing the `pos_restaurant` module while an old version of `point_of_sale` was still in place, since the customer would need to manually upgrade `point_of_sale` first to have that new div element available. We now use receipt-header as the xpath target, which was always present in the template. We also refill `pos_self_order.pos_order_change_receipt` to prevent breaks with custo. --- Report: https://github.com/odoo/odoo/pull/267161#discussion_r3758115362 Forward-Port-Of: odoo/odoo#281768
Live chat visitors will now see the chatbot typing animation while the bot pauses between scripted steps. This makes automated conversations feel more responsive and reduces confusion during short waits.
Original PR description
Before this commit, a chatbot never shows that it is typing: the animated dots between two steps of its script never appear in the livechat. This happens because typingMessage tests this.isTypingUi on the Chatbot record, a getter of discuss.channel.member that Chatbot does not have, so the read is always undefined and no typing message is inserted. This comes from "[IMP] mail: disable isTyping when muted", which renamed the reads of the member field and took the read of the chatbot's own isTyping attribute along. This commit tests isTyping again, so the typing message shows while the script waits between two steps. Forward-Port-Of: odoo/odoo#285930
This fixes a mobile usability issue in the HTML editor where users could not drag and drop table cells inside Todo items. The change prevents the browser's touch handling from interrupting the drag action, making table editing work as expected on phones and tablets.
Original PR description
Steps to Reproduce - Insert a table inside a Todo item. - Long-press the table menu to open the drag-and-drop overlay. - Try to drag and drop table cells. Issue: - Table cells cannot be dragged and dropped on mobile devices. Cause: - On mobile devices, the browser fires `pointercancel`/`pointerleave` during a drag operation, which ends the drag operation prematurely. As a result, subsequent `pointermove` events are not triggered causing the drag-and-drop operation to fail. Solution: - Add `touch-action: none` to the table menu element. This prevents the browser default touch handling from interfering with the drag operation, allowing `pointermove` events to continue and drag-and-drop to work correctly on mobile devices. task-6201176 Forward-Port-Of: odoo/odoo#283866 Forward-Port-Of: odoo/odoo#267680
The Belgian payroll DMFA check no longer fails for flexible employees who do not have a standard work calendar. It now uses their expected weekly hours to validate quarterly work days, helping payroll teams avoid incorrect warnings or blocked processing.
Original PR description
In this other PR (https://github.com/odoo/enterprise/pull/120063) we added a DMFA warning to check that every employee included in a DMFA has worked the correct number of days in the quarter. Since the calendar can change between employees, we were calling a function to tell us for each employee how many days was he supposed to work. However, if an employee is flexible he has no calendar, the function fails. In that case we have the number of hours it's supposed to work per week and we can fallback to that since we know there are exactly 13 weeks in a quarter. Task: 6497142
Odoo now records a VoIP call more accurately when it is answered or rejected in another phone application such as Linphone. This prevents calls from being incorrectly shown as missed and gives users a clearer call history when multiple VoIP tools are open.
Original PR description
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and…
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and Linphone ring - Answer or reject using Linphone => The VoIP call record in Odoo immediately switches from "Trying to call" to "Missed". While there was no guarantee for our VoIP integration to work alongside Linphone in 19.0, we decided this should be an easy safe enough fix. Starting 19.2 (with [1]), the fix will be simplified and hopefully prettier thanks to the ameliorations that were made. After this fix, provided Odoo is open while Linphone is used, the call records will now switch to the right terminated / rejected status, still immediately once Linphone answers / rejects. In future versions and especially 20.0+, the system will be different and will allow way more features like this one to work better (e.g. here the call record only even exists if Odoo is opened while using Linphone and we won't have any information about the call duration). [1]: https://github.com/odoo/enterprise/commit/942f32316ab02d8c739fe7fdd5ec2bdde472a68e task-6449259 Forward-Port-Of: odoo/enterprise#130047 Forward-Port-Of: odoo/enterprise#127077
This fixes a visual inconsistency in the VoIP sound form when dark mode is enabled. The form background and its surrounding header now use matching colors, creating a cleaner and less distracting experience for users.
Original PR description
In dark mode, the sound form background and the header of the node containing it used inconsistent colors.
Financial reports no longer show the unallocated earnings or losses line when its balance is zero across all columns. This keeps trial balance reports cleaner and helps users focus on meaningful figures.
Original PR description
… zero The unallocated earnings/losses line was displayed even when its balance was zero in every column group, cluttering the report with uninformative rows. We therefore filter out lines whose balance is zero across all column groups. Forward-Port-Of: odoo/enterprise#129666 Forward-Port-Of: odoo/enterprise#129129
The VoIP call flow editor now displays correctly when dark mode is enabled. This improves readability and creates a more consistent experience for users working with call flows in darker interface settings.
Original PR description
Before this commit, the call flow editor kept its light background and node colors when dark mode was enabled, resulting in poor contrast and inconsistent styling. This commit adds dark mode styles for the canvas, grid, nodes, connections, ports, selection states, and location indicator.
This fix stops users from creating order boxes directly from printer settings. Order boxes must be linked to a real physical device, helping avoid incorrect setup and operational confusion in point-of-sale self-order flows.
Original PR description
We prevent users from creating oboxes from pos.printer model, as oboxes should be paired with an actual device. Forward-Port-Of: odoo/enterprise#130197 Forward-Port-Of: odoo/enterprise#129960
Refund payslips are now recalculated correctly whenever worked days or payslip lines are recomputed, not only after a reset. This helps ensure payroll corrections remain accurate and reduces the risk of incorrect refund amounts.
Original PR description
Instead of only resetting correctly the refund payslip in the reset, ensure that anytime we recompute worked days or lines, the refund is correctly computed. Forward-Port-Of: odoo/enterprise#129332
Added automated checks to ensure time-tracking assistant suggestions are correctly matched to helpdesk tickets and related calendar entries. This reduces the risk of incorrect timesheet links and helps maintain reliable support reporting.
Original PR description
task: 6475133 Forward-Port-Of: odoo/enterprise#130157
Belgian payroll now correctly treats public holidays as unpaid when they fall after an employee's guaranteed sick pay period has ended, even if a new medical certificate starts that same day. This prevents accidental overpayment and improves payroll accuracy for long-term sickness cases.
Original PR description
Steps to reproduce: - Employee on full-time sickness certified month by month (one hr.leave per medical certificate), guaranteed salary period already exhausted. - Compute payroll for the month whose public holiday falls on the first day of a new certificate. - Public holiday work entry stays paid, every other day that month is correctly unpaid. Cause: the 30-day lookback compared exact datetimes instead of calendar dates, so a certificate starting the same day as the holiday but later in clock-time got excluded. Also ignored timezone: date_from is stored in UTC and needs localizing before taking .date(). Fix: compare local calendar dates via hr.leave's own request_date_from/request_date_to instead of raw UTC datetimes. Added a regression test for the split-certificate case. Task 6512860 Forward-Port-Of: odoo/enterprise#129889
Dark mode now uses the full expected color palette and avoids mixing light-mode colors into dark-mode styling. This prevents missing or incorrect colors in screens and labels that rely on automatic color selection.
Original PR description
1) The "$o-colors" css variable was rebuilt in "secondary_variables.dark.scss", which loads after community's "primary_variables.scss" already assigned it via !default. The dark "$o-colors: ()!default;" reset was silently skipped, so dark colors were appended onto the light ones instead of replacing them, doubling "$o-colors" to 24 entries. => Moving this logic to "primary_variables.dark.scss", which correctly loads first. 2) "$o-colors-secondary-original" only listed 18 colors instead of the 44 used in the original "$o-colors-secondary" of light mode, meaning the dark mode's total palette ($o-colors-complete) had far fewer entries than the 56 that the JS helper "getColor()" assumes leading to missing coloring. => Extending the list so that the dark mode "$o-colors-secondary-original" matches the original "$o-colors-secondary" light mode's 44 colors.
This update corrects icon-related issues across the application to improve visual consistency and usability. Users should see clearer, more reliable interface elements, with no expected workflow changes.
This fixes a timing issue in the self-order interface where closing or changing a carousel during a slide could trigger errors in automated flows. The change improves reliability of the self-order experience without altering user-facing features.
Original PR description
Option A (guard in the hook). Disposing a Carousel mid-slide left its queued transition callback running against a nulled `_element`, throwing `TypeError: Illegal invocation` in unrelated self-order tours. Option B. The self-order bundle ships Bootstrap without `web/static/src/libs/bootstrap.js`, so the fix skipping a transition callback whose element is gone never applied here. Costs ~89kB: the patch file needs Tooltip/Dropdown/Modal. runbot-946931 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Opening the generate lot dialog during receiving could show an error because the system tried to use missing information. The update adds safeguards so warehouse users can open the dialog without the warning interrupting their workflow.
Original PR description
When opening the dialog in stock delivery there is an error warning about reading from undefined. This commit adds extra checks to prevent this.
Analytic plan applicability now falls back to the default setting when a screen does not provide a business context, even if a company-specific rule exists for invoices. This prevents unrelated areas like Work Centers or Employee views from incorrectly requiring analytic distribution.
Original PR description
### Issue: When an analytic plan has applicability lines with a company filter, the applicability is incorrectly applied on views that do not define a `business_domain`, such as Work Centers or…
### Issue: When an analytic plan has applicability lines with a company filter, the applicability is incorrectly applied on views that do not define a `business_domain`, such as Work Centers or Employee views For example, if a plan has: - Default Applicability: Unavailable - A line with Domain: Invoice, Company: My Company, Applicability: Mandatory Opening the analytic distribution on a Work Center shows `Mandatory` instead of the default `Unavailable` ### Cause: In commit https://github.com/odoo/odoo/commit/ffcf2ee1a3185ef73db93bfd95625844506692c5 `_get_score` was updated to return `0.5` when the applicability line's company matches the caller's company, even when no `business_domain` is provided In `_get_applicability`, the loop selects the first rule whose score exceeds the current minimum, which starts at `0`: https://github.com/odoo/odoo/blob/710e056e5171af2ab72d7d7793da3518f12faf5e/addons/analytic/models/analytic_plan.py#L255-L264 A score of `0.5` is enough to win over the default applicability, so a company-only match on a domain-specific rule incorrectly overrides the default when no `business_domain` is passed ### Steps to reproduce: - Install `mrp` and `accountant` with demo data - Enable Analytic Accounting in Settings - Open the Internal analytic plan and edit its applicability line: -- Remove the account prefix -- Default Applicability: Unavailable -- Domain: Invoice, Company: My Company (SF), Applicability: Mandatory - Go to Manufacturing > Configuration > Work Centers - Open any work center and click on Analytic Distribution Before the fix, Internal is shown as Mandatory instead of Unavailable Removing the company from the applicability line confirms the issue opw-6404884 Forward-Port-Of: odoo/odoo#280312
This fixes French electronic invoice exports so that paid invoices automatically include the required due date, matching the payment date. It helps businesses comply with the latest French invoicing validation rules and reduces the risk of rejected invoice files.
Original PR description
According the schematron v1.4, the cbc:DueDate is required when the move is PAID. "[BR-FR-CO-09/BT-23] : Si le cadre de facturation (BT-23) est B2, S2 ou M2, alors la date d’échéance (BT-9) doit être renseignée et correspondre à la date de paiement." no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286263
Accountants without company access rights can now generate BOE files for Spanish Modelo 115 tax reports without receiving an access error. The change prevents the export wizard from attempting an unnecessary company update, keeping the workflow available to accounting users as intended.
Original PR description
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax…
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax reports, even though exporting a BOE file has nothing to do with editing company configuration and should be available to any accountant. Steps to reproduce: ------------------- * Log in as a user with accounting rights only (not part of the Companies > Access Rights group) * Go to Accounting > Reporting > Tax Return, open the Mod 115 report * Click the gear icon > BOE > Generate BOE > Observation: An AccessError is raised: "You are not allowed to modify 'Companies' (res.company) ... This operation is allowed for the following groups: Access Rights", even though the user is not trying to edit the company. Why the fix: ------------ The BOE wizard shared by Mod 111/115/303 declares a `company_partner_id` field, related to `company_id.partner_id`, with `readonly=False`. That field is invisible in every view and only exists to compute the domain of `partner_bank_id`; it was never meant to be edited by the user. Because it is declared writable, the ORM attaches an inverse to the related field, so saving the wizard (which happens when generating the BOE, since the field, though invisible, is still part of the view and thus of the saved values) writes `company.partner_id` back onto `res.company`, even though the value never actually changes. That implicit write requires write access on res.company, which is only granted to the Access Rights group, causing the error for regular accountants. Dropping `readonly=False` keeps the field as a plain readonly related field, still usable for the bank account domain, without ever triggering that spurious write. opw-6388869 Forward-Port-Of: odoo/enterprise#130168 Forward-Port-Of: odoo/enterprise#126661
Sales order lines for timesheet-based services now update remaining hours when relevant unit or availability details change. This helps keep project and service billing information accurate without relying on unrelated timesheet triggers.
Original PR description
The dependencies of _compute_remaining_hours do not match the fields actually used for the computation: it lists analytic_line_ids, which it never uses, and omits both remaining_hours_available, and product_uom. _compute_remaining_hours_available has the same issue: it uses product_uom but only depends on product_id.service_policy. analytic_line_ids, on the other hand, can be dropped: qty_delivered already depends on it, along with its so_line, unit_amount, product_uom_id and project_id, so the timesheet flow keeps triggering the recomputation. This PR fixes the dependencies for both aforementioned compute methods. Task-4748521 Forward-Port-Of: odoo/odoo#285685 Forward-Port-Of: odoo/odoo#284750
Product thumbnails on ecommerce product pages now stay neatly aligned when automatic image cropping is turned off. This improves the shopping experience by keeping thumbnail rows tidy and ensuring product images are centered properly, even when images have very different shapes.
Original PR description
Steps to reproduce: =================== 1. Add several images to a product, one of them much wider than tall. 2. On the product page, set the image ratio to "Disabled". 3. Move the thumbnails below…
Steps to reproduce: =================== 1. Add several images to a product, one of them much wider than tall. 2. On the product page, set the image ratio to "Disabled". 3. Move the thumbnails below the image. => The wide thumbnail sits at the top of its slot, with blank space under it. Root cause: =========== Thumbnails are given a fixed width of 64px and take their height from `aspect-ratio: var(--o-wsale-product-image-ratio)` [1]. With cropping disabled that variable is `auto`, so each thumbnail keeps the shape of its own image and they no longer share a height. They sit in a flex row, which stretches every slot to the height of the tallest one. The image inside keeps its own height and stays at the top of the slot, so a wide image leaves the rest of its slot empty. The slots are only stretched when the images differ in height, which is why the problem needs cropping to be disabled, and why it does not appear when every image is a landscape one. - [1] sized the thumbnails from the image ratio. Fix: ==== Center the thumbnails in the row so each one keeps the height of its own image instead of being stretched to the tallest. Their width stays at 64px, so a row of wide images still takes the same space as before and none of them is pushed out of the container. [1]: 670b1daa2254 opw-6472484 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283246
This fixes an issue where certain changed and recombined manufacturing orders could incorrectly produce double the intended quantity or fail during valuation. Manufacturing validation now correctly splits quantities across related finished product lines and values them together, helping avoid inventory and costing errors.
Original PR description
When the quantity of a make-to-order manufacturing order is changed, its finished move is copied to propagate the extra quantity downstream. In some cases (after splitting then merging back…
When the quantity of a make-to-order manufacturing order is changed, its finished move is copied to propagate the extra quantity downstream. In some cases (after splitting then merging back productions) that copy is not merged back, so the order ends up with two finished moves for the same product. On validation, two things then go wrong: - _post_inventory writes the produced quantity on each finished move, so both get the full quantity and the production is doubled - mrp_account._cal_price prices the finished move and calls ensure_one(), which raises "Expected singleton" for an average/fifo product, so "Produce All" fails Split the produced quantity across the finished moves with unit_factor (like _set_qty_producing already does), and price them as a whole instead of expecting a single finished move. Steps to reproduce: - Create a BoM for product A with the MTO route, and a component B - Create a Sale Order for 30 units of A, confirm it - Split the MO into 3 productions of 10, merge two of them - On the third, Update Quantity 10 -> 15, then Produce All - The product should be produced once (15, not 30), with A valued in average/fifo it instead of an error. opw-6242504 opw-6310972 opw-6307025 opw-6354739 Forward-Port-Of: odoo/odoo#286173 Forward-Port-Of: odoo/odoo#269254
This fixes date-related tests so they use the same timezone as the Odoo environment. It prevents occasional test failures around midnight in Belgium, improving reliability without changing business functionality.
Original PR description
## Issue By default in Odoo, `datetime.now()` returns the UTC time, which is two hours behind the local time in Belgium. This leads to two tests failing when executed between 00:00 and 02:00 Belgian…
## Issue By default in Odoo, `datetime.now()` returns the UTC time, which is two hours behind the local time in Belgium. This leads to two tests failing when executed between 00:00 and 02:00 Belgian time: `test_ir_sequence_interpolation_dict` and `test_ir_sequence_iso_directives`. The `_interpolate_dict` method (responsible for interpolating the prefix/suffix from the sequences) specifies the tzinfo when calling `datetime.now()`: https://github.com/odoo/odoo/blob/9c67949be529eb86886b3d5bde08e81e048ecfe7/odoo/addons/base/models/ir_sequence.py#L211-L212 Since this is not the case in the tests, the tests evaluate the date using UTC. This creates a two hours difference between the time expected and the time actually used by `next_by_code`. The tests thus fail between 00:00 and 02:00 because the evaluate dates from both `datetime.now` calls differ, leading to a mismatch in the expected prefixes. ## Fix We force the `env.tz` on the `datetime.now()` call, to mimic the behavior from the `_interpolate_dict`. runbot-242662 Forward-Port-Of: odoo/odoo#284955
This fixes a display issue in the website editor where resize controls could be hidden behind the sidebar when editing animated content. Users can now clearly see and resize selected page elements, improving editing accuracy and reducing confusion.
Original PR description
Steps to reproduce: - Drop a few snippets to make the page scrollable - At the bottom, drop the `s_three_columns` snippet - Click on the last Card - Add an animation "onScroll" (Effect - Slide, Intensity - 100) - Scroll top slightly to hide a part of the card behind the sidebar => The resize overlay is partially hidden The elements `.hb-row` have a z-index of 2, so they appear in front of the overlay which has a z-index of 1. It was decided to fully show the overlay to allow resizing. Keeping the overlay visible in front of the sidebar also allow the user to see where animated element is. task-6476269 Forward-Port-Of: odoo/odoo#283842 Forward-Port-Of: odoo/odoo#282796
This fixes the import of Factur-X e-invoices received through Peppol by correctly reading the embedded XML inside the PDF. It prevents missing or empty invoice records and improves detection of self-billed documents, helping French e-invoicing flows process documents reliably.
Original PR description
When importing new documents from Peppol into the database, we determine whether they are self-billed by checking a Type Code in the XML file. Factur-X is an hybrid format where the XML is embedded inside a PDF. Currently, we are not extracting the XML before searching for that Type Code, and it leads to an error that prevents the document from being imported correctly: - V17, V18: An empty invoice is created and linked with the attachment. - V19+: Only the attachment is created. Additionnaly, we only check for InvoiceTypeCode or CreditNoteTypeCode, but the CII XML format embedded inside the hybrid Factur-X format use TypeCode instead. This PR aims at fixing both these issues. Ticket: opw-6417682 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285552 Forward-Port-Of: odoo/odoo#280714
This fixes a website editor issue where deleting a card's cover image could leave the card in an inconsistent state. Users will no longer encounter broken cover image options or related errors when editing card-based website snippets.
Original PR description
It was possible to remove the image inside a card cover while keeping the figure wrapper. The card option would then still consider that there was a cover image even though the image was gone, which could also lead to a traceback. Steps to reproduce: - Insert the `s_three_columns` snippet - Click on the image of one card - Either press "Enter", "Delete", "Backspace" - Hover the "Cover Image" options => The image is removed but the `<figure>` is still there, so the option is still considered active (leading to a traceback) task-6081728 Forward-Port-Of: odoo/odoo#285131 Forward-Port-Of: odoo/odoo#280086
This fix updates an internal test so it consistently includes the required tax information when checking Indonesian e-Faktur behavior. It helps prevent false build failures and supports more reliable delivery of the localization feature, without changing day-to-day user workflows.
Original PR description
Issue: In some build, when creating the invoice line it did not assign the default tax so it raise an error when downloading efaktur Fix: Assign the tax line manually in the unit test instead of relying on default taxes issue-[946227](https://runbot.odoo.com/odoo/error/946227) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285902
The editor no longer shows a non-working magic wand icon when users open the link popover for an image with a link. This removes a confusing control and makes editing linked images clearer.
Original PR description
**Current behavior before PR:** Steps to reproduce the issue: - Add an image - Add a link to the image - Put cursor just right after the image link so that link popover is opened - Notice that there is a wand icon in link popover to replace title, clicking on it does nothing **Desired behavior after PR:** There should be no replace title icon in popover for image-link. task-6420902 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286119 Forward-Port-Of: odoo/odoo#279076
Fixes an issue where the website builder showed an inaccurate preview when changing header width for a specific boxed header style. This makes the setting apply more reliably and avoids misleading previews for website editors.
Original PR description
The header width option is not previewed properly on the header template `template_header_boxed`. This happens because this template is not compatible with the action `previewableWebsiteConfig` (its width can't be previewed by adding a single class). This commit fixes the problem by using the action `websiteConfig` instead of `previewableWebsiteConfig` when this template is set. task-6420611 Forward-Port-Of: odoo/odoo#286292 Forward-Port-Of: odoo/odoo#282311
This fixes a mismatch between SMS delivery error handling and mass SMS mailings. Mass SMS campaigns now recognize the newer failure reason, preventing affected flows from crashing when that error occurs.
Original PR description
This commit fixes an issue with the addition of a new failure_type in the SMS module via [1]. The corresponding failure_type wasn't added in mass_mailing_sms meaning that some flows could crash if the specific error was set. Now, the new failure_type is added to the module. [1]:https://github.com/odoo/odoo/commit/06bab9a82dae911c26fd5dd329cb43a466d13569 Forward-Port-Of: odoo/odoo#286510
The Vietnam accounting report variants now keep the search bar available when users switch to the VAS general journal or general ledger. This lets users filter account lines by name consistently, matching the standard general ledger behavior.
Original PR description
The standard general ledger enables the search bar, but the VAS general journal (S03a-DN) and general ledger (S03b-DN) variants do not, so the search field disappears as soon as the user switches to one of them and the account lines can no longer be filtered by name. Enable the search bar on both variants to match their root report.
This fixes an issue where signatures could disappear from downloaded signed PDFs when the original file had unusual page positioning. Signed documents now place fields within the visible page area, so users can trust that completed PDFs match the preview.
Original PR description
Steps to reproduce (version 16+): 1) Obtain a pdf with a negative origin point: This can occur when a customer exports a pdf from another software, or it can be made manually using a python script 2) In the sign app, upload the pdf and create a new template, add a signature field to the document. 3) Sign the document. The preview will load correctly and the signature will be visible 4) Download and open the signed pdf. The signature is not on the document Notes: Issue occurs because the signature was added to the pdf outside of the visible area. The preview works because the signature is rendered on top of the unsigned document in the correct location. The issue can be fixed applying a translation to the canvas. Ticket: [6317223](https://www.odoo.com/odoo/project/49/tasks/6317223?debug=assets) Forward-Port-Of: odoo/enterprise#127711 Forward-Port-Of: odoo/enterprise#121960
Appraisals now keep the generic template chosen by the user when they are confirmed or reset. This prevents records from being silently reassigned to a different template, so reporting and filtering by appraisal template remain accurate.
Original PR description
Issue: When a user selects a generic appraisal template other than the first one, confirming or resetting the appraisal silently replaces that selection with the first generic template. Filtering…
Issue: When a user selects a generic appraisal template other than the first one, confirming or resetting the appraisal silently replaces that selection with the first generic template. Filtering appraisals by the originally selected template then fails to return the appraisal. Steps to reproduce: * Configure multiple appraisal templates without department restrictions. * Create an appraisal and select a template other than the first one. * Confirm the appraisal. * Filter appraisals by the selected template. Cause: `_compute_appraisal_template()` only preserved templates directly linked to the appraisal's department. Generic templates have no department relation, so a valid selected template was discarded whenever the computation was triggered by a state dependent department recomputation. The generic fallback then stored the first template instead. https://github.com/odoo/enterprise/blob/5c57ccbb13269af28de0a6c7f35454be52424f43/hr_appraisal/models/hr_appraisal.py#L195-L209 Solution: We need to distinguish the generic default loaded on an unsaved form from a compatible generic template already stored on an appraisal. Preserve the latter across recomputations while retaining department template priority during creation and rejecting templates that no longer match the appraisal's department or company. opw-6449041 Forward-Port-Of: odoo/enterprise#129635 Forward-Port-Of: odoo/enterprise#127566
This fix makes an automated restaurant appointment test wait until a cancellation dialog fully closes before ending. It helps prevent intermittent false test failures, improving confidence in release validation without changing user-facing behavior.
Original PR description
Following commit b6a7991a6aaef1be15a27852c2c76737322cdcab, the tour clicks the cancel button (.o_form_button_cancel) to discard unsaved changes. However, as it was the last step of the tour, the test could terminate before the asynchronous discard/dialog closure completed. This caused intermittent test failures with: `AssertionError: Tour finished with a dirty form view being open.` We now add a final step that waits for the dialog to close and the form to no longer be marked as dirty (`body:not(:has(.o_dialog)):not(:has(.o_form_dirty))`) before completing the tour. Forward-Port-Of: odoo/enterprise#129375
This fixes a navigation issue where opening Helpdesk tickets from an email alias could crash because the system reused the wrong background context. Users can now move from an alias to its related Helpdesk team and view tickets normally, improving reliability for support workflows.
Original PR description
### Steps to Reproduce: 1. In Debug mode, go to Aliases 2. Click on any active Alias, ex. customer-care 3. Click on "Open Parent Document" smart button 4. Click on "Tickets" smart button and observe…
### Steps to Reproduce: 1. In Debug mode, go to Aliases 2. Click on any active Alias, ex. customer-care 3. Click on "Open Parent Document" smart button 4. Click on "Tickets" smart button and observe error ### Description of the issue/feature this PR addresses: **Issue:** When navigating from an email alias to its parent document (e.g., a Helpdesk Team), the web client incorrectly retains the `active_id` and `active_model` of the alias in the context. **Solution:** We updated the `action_view_ticket` method in `helpdesk.team` to explicitly inject the correct `active_model` and `active_id` into the context before calling `_for_xml_id`. This overwrites the polluted Alias data before the window action is evaluated. ### Current behavior before PR: Clicking the "Tickets" smart button passes the old alias context into the action. This bad data flows into the ticket view, which attempts to look up a Helpdesk Team using the Alias's ID to generate the empty list help message, resulting in a `MissingError`. ### Desired behavior after PR: The Python action sanitizes the context at the source, ensuring that the XML action and subsequent view evaluations receive the correct Helpdesk Team ID. Ultimately, the view will load normally without crashing. opw-6395638 Forward-Port-Of: odoo/enterprise#130088 Forward-Port-Of: odoo/enterprise#125232
The Helpdesk SLA Status Analysis report now measures Hours Open from ticket creation until closure, matching the main Ticket Analysis report. This prevents tickets that were assigned immediately from showing no open time and gives managers a more accurate view of service performance.
Original PR description
1. Open Helpdesk > Tickets and create a ticket on the team "Customer Care", assigned to yourself 2. More than an hour later, move it to the "Solved" stage to close it 3. Open Helpdesk > Reporting > Ticket Analysis, switch to the pivot view and pick the "Hours Open" measure -> the ticket holds the hour it stayed open 4. Open Helpdesk > Reporting > SLA Status Analysis and pick the "Hours Open" measure as well -> the ticket holds nothing, as it was assigned as soon as it was created odoo/enterprise#47454 added the "Hours Open" measure of the ticket analysis to the SLA status analysis, but computes it up to the assignment date instead of the closing date. The measure therefore holds the hours until the ticket was assigned, which the report already offers as "Working Hours to Assign". With this commit, both reports count the hours from the creation of the ticket to its closing. Forward-Port-Of: odoo/enterprise#130263 Forward-Port-Of: odoo/enterprise#130170
Freezing spreadsheet data now creates the expected data protection log entry. This helps businesses keep a clearer audit trail when spreadsheet content is locked or preserved.
Original PR description
Task: 6389096 Forward-Port-Of: odoo/enterprise#130229 Forward-Port-Of: odoo/enterprise#126461
Fixed an issue in the HTML editor where pressing Enter in a list item containing a table did not split the bullet as expected. This makes editing mixed content in bullet lists more predictable and prevents accidentally moving larger list content out of the list.
Original PR description
### Steps to reproduce: - Insert a bullet list - Inside of the list, insert a table - Write before and/or after the table (in the same list item) - Press enter before and/or after the inserted text - Notice that the bullet is not split like in a normal list ### Root Cause: - On Enter, list plugin checked whether the list item contained unsplittable element. Since the table was inside the list item, it always treated the list item as unsplittable, even when the cursor was outside the table. As a result, the list item could never be split. ### Solution: - Instead of checking the whole list item, walk up from the split target to the list item and look for an unsplittable element along the way. This allows the list item to split normally when the cursor is outside the unsplittable. task-6449843 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286028 Forward-Port-Of: odoo/odoo#280903
The web test suite now ignores assets that do not have a file-based name instead of failing unexpectedly. This keeps JavaScript regression testing reliable when websites use customized themes or when asset paths are invalid.
Original PR description
### Problem `HootCommon` in `addons/web/tests/test_js.py` calls `.endswith()` on `asset['filename']` in two places without checking it for `None`: ```python filename = asset['filename'] if not…
### Problem
`HootCommon` in `addons/web/tests/test_js.py` calls `.endswith()` on
`asset['filename']` in two places without checking it for `None`:
```python
filename = asset['filename']
if not filename.endswith('.test.js'):
```
```python
if asset['filename'].endswith('.test.js')
```
But `filename` is legitimately `None` for assets backed by an `ir.attachment`
rather than a file on disk. `ir_asset.py::_get_paths` sets it that way on
purpose (the "an attachment url most likely" branch).
### Reproduction
Customise a website theme (which creates an `ir.attachment`-backed asset), then
run the core JS suite. Four tests fail with:
```
AttributeError: 'NoneType' object has no attribute 'endswith'
```
The same happens with a simple typo in a manifest's asset path, which produces
`filename = None` with only a warning — so a one-character mistake turns the
whole JS suite red instead of reporting the typo.
### Fix
An asset with no file on disk cannot be a `.test.js`, so the correct response to
`filename is None` is the same as for any other name that does not end in
`.test.js`: skip it.
The suite is currently red permanently on any database with a customised theme,
which is exactly when it stops being useful as a regression signal.This fix prevents already-paid online orders from being reopened as abandoned carts during a short timing window after redirect payments. It helps avoid incorrect order totals and false payment mismatch warnings on the confirmation page, improving checkout reliability for customers using alternate pricelists or currencies.
Original PR description
**Steps to reproduce:** - Install the `website_sale` module. - Configure the Mollie payment provider and publish it. - Enable the PLN currency. - Create a PLN pricelist and make it selectable on the…
**Steps to reproduce:** - Install the `website_sale` module. - Configure the Mollie payment provider and publish it. - Enable the PLN currency. - Create a PLN pricelist and make it selectable on the website. - Open the Mitchell Admin customer record and, under the `Sales & Purchase` tab, assign the USD pricelist. - Go to the website shop, switch the pricelist to PLN, add a product to the cart, and proceed to checkout. - Pay through Mollie and mark the transaction as paid in Mollie. **Issue:** - After a successful redirect payment, the confirmation page displays an amount-mismatch warning, even though the payment was accepted by the provider for the correct amount. **Root cause:** - Mollie's return request and webhook can arrive within milliseconds of each other. Both requests attempt to create a `payment_data` record referencing the same `payment_transaction`. - At the same time, the cron holds a `FOR UPDATE` lock on the transaction while processing the first payload. The `FOR KEY SHARE` lock automatically acquired by PostgreSQL during the foreign-key check of the `payment_data` insertion conflicts with this `FOR UPDATE` lock. This results in a serialization failure and rolls back the post-processing job that would have confirmed the sale order (`draft` → `sale`). - This temporarily leaves the transaction in `done` state while the sale order is still in `draft`. - `sale_reset()` then clears both the session cart key and the selected- pricelist key. When `/shop/confirmation` renders, `request.cart` is resolved through `_get_and_cache_current_cart()`. The abandoned-cart recovery branch finds the still-draft sale order and calls `_update_address()` on it. - Since the selected-pricelist key is no longer present in the session, the customer's default USD pricelist is applied. `_recompute_prices()` then changes the sale order total. However, the payment transaction still contains the original PLN amount, so `_get_status_message()` detects the difference and displays the amount-mismatch warning. **Solution:** - Before calling `_update_address()` and `_verify_cart()` on an abandoned-cart candidate, check the state of its latest transaction. - If the transaction is `pending`, `authorized`, or `done`, discard the candidate and return an empty cart. - This matches the guard already present in the session-cart branch of the same method, keeping both paths consistent. - The serialization failure itself is expected and handled by Odoo's retry mechanism. This fix prevents the resulting side-effect window from allowing an already-paid order to be recovered as an abandoned cart and repriced. opw-6470325 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Fixes a storefront issue where changing options on an out-of-stock product could make the "Add to wishlist" button shift position. This keeps the shopping experience visually stable and avoids confusing customers browsing unavailable product variants.
Original PR description
On an out-of-stock product page where we prevent out-of-stock sale, changing the attribute value moves the "Add to wishlist" button Steps to reproduce: 1. Install eCommerce and Inventory 2. Go to Settings > Website > eCommerce > Inventory Defaults and disable the option "Continue Selling" for Out-of-Stock products 3. Go to Inventory > Products, open product Customizable Desk. In the eCommerce tab, disable option "Sell when Out-of-Stock". 4. In the General Information tab, click on the Quantity On Hand and set all quantities to 0 5. Open the product on the eCommerce 6. Change the Legs attribute to Aluminium 7. The "Add to wishlist" button moves Issue: Changing the combination of the product only removes the `#product_stock_availability` element. However, there can be multiple elements that we need to remove. This was introduced in https://github.com/odoo/odoo/commit/6e72f45f78055de762a24e4a24a82a5565346d7a Solution: Reset the previous behavior opw-6507088
Italian invoice generation no longer fails when a company does not use email or SDI delivery checks. The attachment selection option is also shown more reliably for Italian companies, helping users complete invoice sending without interruptions.
Original PR description
When generating an invoice with an Italian company not checking mail nor SDI, a traceback is raised This commit also update the condition to show attachment selector on `account.move.send` for Italian companies Task [link](https://www.odoo.com/odoo/project.task/6514516) task-6514516
Translated table of contents navigation now keeps plain, consistent link text even when translated headings are styled. Social and sharing snippets also reuse the same styling rules in translation mode, reducing display inconsistencies and maintenance risk.
Original PR description
### [REF] website, *: prevent style in navbar of translated table of content *: html_builder The snippet "Table of Content" copies the content of the title in its navbar, taking care of removing…
### [REF] website, *: prevent style in navbar of translated table of content *: html_builder The snippet "Table of Content" copies the content of the title in its navbar, taking care of removing style to have plain text in the navbar. In translate, to try to achieve this as well, it uses some special logic with `o_translation_without_style`, a second translation hash,... But, if one of the title has no style in the original language, but a translation adds a style, then the term with style is used in the navbar. This commit uses `o_translate_inline` on the links of the navbar. With this, they make together a single translation term which is always distinct from the terms of the titles. The copy of the translated titles is made with the same plugin as in normal mode (with some adaptation to take into account the translation spans). Steps to reproduce: - Open website builder - Drop the "Table of Content" snippet - Save - Open website builder in translate mode - Select text in a title of the "Table of Content" snippet - Change its style: make it bold - Save - Bug: the term in the navbar is bold as well task-6304267 ### [REF] website: define style for translated social snippet in main css The snippets "Social Media" and "Share" needs additional rules to appear correctly in translate mode (if they have `o_translate_inline` on their links). Those were defined in a separate file for inside the builder. This is error prone because the content of those rules needs to be kept in sync with the general rules. To avoid the duplication, this commit moves those additional rules with the normal ones, so they share their content. task-6304267
The mail app now cleans up its internal data store automatically when the app is closed, preventing leftover test subscriptions. This improves test reliability and reduces the chance of hidden side effects between mail-related tests without changing user-facing behavior.
Original PR description
Before this commit, a mail test that mounts its UI without the `start()` helper never disposes the store, so the subscriptions its records registered outlive the test: the chat hub and composer…
Before this commit, a mail test that mounts its UI without the `start()` helper never disposes the store, so the subscriptions its records registered outlive the test: the chat hub and composer service entries of the shared local storage listener, and one for each `localStorage` field of a record. `@mail/discuss/call/peer_to_peer` mounts with `mountWebClient()`. This happens because nothing in src disposes a store: a deleted record runs its dispose functions from the delete queue, and the store is a singleton nothing deletes, so its own teardown had one caller, the `after()` hook of `start()`. Note that hoot rebuilds the module set of a test file, so such a subscription is collected with its file and the memory of the suite does not grow. This commit registers the teardown on the scope of the app that builds the store, the one services start in and that `makeStore` already reads `useApp()` from, so destroying the app runs the store's dispose functions and the tests need no hook of their own.
The website editor now treats forum information links as regular links instead of buttons. This avoids confusing styling options when editing forum pages and keeps the editing experience clearer across desktop and mobile.
Original PR description
Steps to reproduce: - Go to a forum page. - Open the website editor. - Select the "About this forum" link in the sidebar. => Button styling options are shown for a regular link. Before this commit, forum information links used button classes, which made the editor expose button styling options for them. After this commit, the `btn`, `btn-sm`, and `btn-link` classes are replaced with `small` so the editor treats these elements as regular links on desktop and mobile. task-6259086 Forward-Port-Of: odoo/odoo#283156
This change removes an obsolete browser history update from spreadsheet document navigation. It keeps the routing behavior simpler after a previous change introduced a dedicated way to handle shared links with tokens, with no expected impact on normal users.
Original PR description
the replaceState after loading the router patch became useless when we changed the implementation of https://github.com/odoo/enterprise/pull/114484 in favor of a dedicated route to handle urls with a token instead of an id. Task-6485474
The ESG module now cleans up its unit links correctly during uninstall, preventing a reinstall failure. This improves system reliability for customers who remove and reinstall the ESG app or run upgrade and test workflows.
Original PR description
As `relative_uom_id` is on delete cascade, when uninstalling esg module, `uom.product_uom_kwh` is being removed when `esg.product_uom_j` is removed. When reinstalling esg module, we try to override uom.product_uom_kwh but it does not exist anymore, causing the error: Cannot update missing record. To prevent this error, we need to detach the core kWh unit from our own J unit when uninstalling esg module. runbot-error: [946474](https://runbot.odoo.com/odoo/runbot.build.error/946474) version-19.5
The Helpdesk team card now displays the email alias aligned with the team name. This small visual fix makes the card easier to read and keeps the Helpdesk interface looking consistent.
Original PR description
In this commit, we remove the margin before the mail alias, ensuring aligment within the helpdesk team card. task-6416578 Forward-Port-Of: odoo/enterprise#129865
This fix corrects how employee occupations are calculated for Belgian holiday attestations. It helps ensure payroll and departure documents reflect accurate occupation information, reducing the risk of incorrect HR payroll records.
Original PR description
This commit fixes the occupation computations which were wrong. Forward-Port-Of: odoo/enterprise#129837
Swiss payroll payment reports no longer fail when an employee is paid through a Revolut bank account. This keeps ISO20022 payment file generation working after recent bank account data model changes.
Original PR description
res.bank and res.partner.bank.bank_id were removed in saas-19.2: the bank's identity now lives directly on the bank account as bank_bic and bank_name. The Revolut detection added in fba51a6a77a still read bank_account.bank_id, raising an AttributeError when generating the ISO20022 payment report for Swiss payslips. Forward-Port-Of: odoo/enterprise#129915 Forward-Port-Of: odoo/enterprise#129156
This fixes an issue where adding delivery charges could cause Odoo to recalculate the unit of measure and then calculate shipping-related sales line amounts incorrectly. The change keeps the intended unit of measure when the delivery line is created, helping prevent wrong prices or totals on sales orders.
Original PR description
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the…
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the delivery line is created. This causes `product_uom_id` to be recomputed. This commit reintroduces `product_uom_id` in the values to prevent the field from being recomputed. **Description of the issue/feature this PR addresses:** For a strange reason, when a module inherits from `sale.order.line` and adds some computed fields with `precompute=True`. `price_unit`, `price_subtotal`, and `price_total` are computed incorrectly. I have attached a module to demonstrate the issue. https://github.com/user-attachments/assets/ebdd8695-c9d8-477b-b5cf-ba6d8d41e84a Without this change, the test fails, and Odoo incorrectly recomputes the fields, as shown in the video. <img width="1232" height="515" alt="image" src="https://github.com/user-attachments/assets/27370f1f-e7b7-4102-a606-0181b9d1a97a" /> When the ORM computes fields marked as `precompute=True`, in this function `_add_precomputed_values` https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/odoo/orm/models.py#L4836, `price_unit` is 0, but the records get `price_unit` from the product. Therefore, when [_compute_amount](https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/addons/sale/models/sale_order_line.py#L855) is called, the values are computed with an incorrect `price_unit`. <img width="1087" height="940" alt="image" src="https://github.com/user-attachments/assets/92feadf0-7f93-4acc-8f1a-931db0655fcc" /> **Steps to reproduce the issue:** - Install the attached module. [sale_precompute.zip](https://github.com/user-attachments/files/31265993/sale_precompute.zip) - Configure a delivery carrier as free for orders over 1, and set the fixed price to 5, for example. - Create a sales order and add a product with a value greater than 1. - Add the shipping method. The price should be 0. In the sales order line, `price_unit` is 0, but `price_subtotal` and `price_total` are equal to 5 (the product's sale price). For more context, this module is a simple example extracted from the OCA `product_secondary_unit` module, which adds a mixin with these fields: https://github.com/OCA/product-attribute/blob/18.0/product_secondary_unit/models/product_secondary_unit_mixin.py. In the `sale_order_secondary_unit` module, `sale.order.line` inherits from this mixin. You can see the error in this PR: https://github.com/OCA/sale-workflow/pull/4535. https://github.com/OCA/sale-workflow/actions/runs/32259842816/job/96090194021?pr=4535#step:8:509 I understand that this requires a deeper investigation into precompute to solve the underlying issue, but I propose setting `product_uom_id` in the `_prepare_delivery_line_vals` method as a temporary solution while the final solution is being investigated. I understand that this field should not have been removed from `_prepare_delivery_line_vals`; the referenced PR only renamed the field and did not intend to remove the value from this method. @Tecnativa @pedrobaeza @kcv-odoo @Feyensv coudl you please review this? --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284316 Forward-Port-Of: odoo/odoo#283551
The kitchen preparation display now correctly chooses an available point-of-sale configuration when it is shared across multiple setups. This prevents failures when no single configuration is selected and keeps shared kitchen displays working reliably, with minor visual adjustments included.
Original PR description
In this commit: ------------------- - We were passing the pos config id when loading the preparation display, but multiple configs can be configured, and no config is set when using all configs. Instead, the config is now resolved within the service from the loaded configs. task: 6512063 Related PR: https://github.com/odoo/odoo/pull/286169
Kitchen and change receipts now use the POS configuration tied to the order, even when multiple configurations share the same kitchen setup. This helps ensure printed receipts show the right store or register details without affecting standard single-configuration POS printing.
Original PR description
In this commit: ------------------- - Use the first loaded `pos_config` for kitchen when kitchen is common across multiple configs and use the order's associated config when printing a change receipt from the kitchen to ensure the correct config details are printed. - For regular POS printing, this remains unchanged since only one config is loaded. task: 6512063 Related PR: https://github.com/odoo/enterprise/pull/130117