Monday, September 14, 2026
32 changes · saas-19.4
Enhancements to existing features
Accounting reports can now use a consolidation availability setting so they only appear when multiple companies are selected and the report is affected by more than one company. This helps business users see consolidation-related reports only in relevant multi-company contexts, reducing clutter in normal reporting.
Original PR description
With the related enterpise pr, add a new variant availability "consolidation" which makes the report visible only if it is impacted by several companies (company selector has at least 2 companies selected and options['companies'] is more than 1. This new type of variant should prioritize the other types in the selection. task-6398453 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286730
Financial reports now better adapt when users work across multiple companies, showing consolidation-specific variants only when several companies are selected. This helps multi-company users see the most relevant reports while avoiding variants that only match secondary companies.
Original PR description
1) Add a new variant availability "consolidation" which makes the report visible only if it is impacted by several companies (company selector has at least 2 companies selected and options['companies'] is more than 1. This new type of variant should prioritize the other types in the selection. 2) Activate by default the "consolidation" filter in multi-company. 3) In multi-company, the variants of availability type "Coa match" or "Country match" should only be visible if they match the main company, not the secondary ones. task-6398453 Forward-Port-Of: odoo/enterprise#130484
Resolved issues and error corrections
This fixes an issue where unused database connections could remain open longer than intended during busy periods. The change helps keep connection usage under control and reduces the risk of the pool filling up unnecessarily.
Original PR description
Every `borrow()` used to push `_check_free_at` forward, so a busy pool never ran the periodic full idle scan. Oldest idle connections then stayed open until the pool filled. Reset the timer only when that full scan actually runs. I think it is the reason that we have to REV the code here https://github.com/odoo/odoo/pull/287008 for non-blocking connection pool Forward-Port-Of: odoo/odoo#288067
Maintenance requests must now have both a start and end date for scheduled work, or neither. This prevents the manufacturing planning view from failing when an incomplete maintenance schedule is entered, helping teams keep work order planning accessible.
Original PR description
#### Issue: Opening the MRP planning view could raise a traceback when a maintenance request had a `schedule_end` but no `schedule_date`. `TypeError: '<' not supported between instances of 'NoneType'…
#### Issue: Opening the MRP planning view could raise a traceback when a maintenance request had a `schedule_end` but no `schedule_date`. `TypeError: '<' not supported between instances of 'NoneType' and 'datetime.datetime'` #### Steps to reproduce: 1. Install maintenance, mrp, and mrp_maintenance. 2. Create a work center. 3. Create a maintenance request linked to that work center. 4. set a `Scheduled end` and Leave `Scheduled Date` empty. 5. Go to MRP > Planning > Work Orders. #### Cause: `maintenance.request` stores `schedule_end` as a writable field, but no constraint enforces that `schedule_date` and `schedule_end` must be set together. Later, `mrp_maintenance` in `_get_maintenances_intervals` fetches maintenance intervals for the gantt view without filtering null bounds. If a request has `(schedule_date, schedule_end)` = `(False, datetime)`, that interval is passed to `Intervals(...)`, which crashes when comparing `None` with a `datetime`. #### Fix: Add a constraint on `maintenance.request` to require `schedule_date` and `schedule_end` to either both be set or both be empty. Also filter out incomplete intervals in the MRP maintenance gantt query in this enterprise PR: https://github.com/odoo/enterprise/pull/117710 opw-6225772 enterprise PR: https://github.com/odoo/enterprise/pull/117710 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#265838 Forward-Port-Of: odoo/odoo#265208
The MRP planning view now ignores maintenance entries that have only part of their scheduled time filled in. This prevents errors when opening the planning calendar and keeps manufacturing planning accessible even when older or incomplete maintenance data exists.
Original PR description
#### Issue: Opening the MRP planning view could raise a traceback when a maintenance request had a ``Scheduled End`` but no ``Scheduled Date``. ```TypeError: '<' not supported between instances of 'NoneType' and 'datetime.datetime'``` #### Cause: In `_get_maintenances_intervals`, `mrp_maintenance` loaded maintenance intervals for gantt unavailability without filtering out incomplete rows. If an interval like False, datetime reached Intervals, it crashed when comparing None with a datetime. #### Fix: Filter out incomplete maintenance intervals in the gantt query. Also added a constraint on `maintenance.request` to require `schedule_date` and `schedule_end` to either both be set or both be empty in this community PR: https://github.com/odoo/odoo/pull/265208 opw-6225772 Forward-Port-Of: odoo/enterprise#118050 Forward-Port-Of: odoo/enterprise#117710
This fix prevents an error when users open Studio's list editor for sales order lines on an existing sales order. Businesses can now customize columns and add fields to the order line list without interruption.
Original PR description
Before this change: When opening Studio on a Sales Order with existing line items, clicking "Edit List View" on the order lines component triggered a JavaScript error. This prevented users from customizing columns or adding custom fields to the sale order line list view. To reproduce: 1. Open the Sales app and create a new Sales Order with at least one product line. 2. Toggle Studio on. 3. Select the Sale Order Lines list component and click "Edit List View". After this change: Clicking "Edit List View" on sale order lines in Studio works as intended without throwing errors, allowing standard view customizations. opw-6545970
This fixes an issue where users could not open the list editor for sales order lines in Studio when a sales order already had products. Businesses can now customize sale order line columns and add fields without interruption.
Original PR description
Before this change: When opening Studio on a Sales Order with existing line items, clicking "Edit List View" on the order lines component triggered a JavaScript error. This prevented users from customizing columns or adding custom fields to the sale order line list view. To reproduce: 1. Open the Sales app and create a new Sales Order with at least one product line. 2. Toggle Studio on. 3. Select the Sale Order Lines list component and click "Edit List View". After this change: Clicking "Edit List View" on sale order lines in Studio works as intended without throwing errors, allowing standard view customizations. opw-6545970
This update prevents crashes when users edit or select product images through the media dialog. It restores a smooth image-editing flow after recent editor changes caused errors in places such as Point of Sale product setup.
Original PR description
**Description of the issue/feature this PR addresses:** When opening the media dialog to edit an image or when saving a selected image, the UI crashes with strict prop validation and undefined…
**Description of the issue/feature this PR addresses:** When opening the media dialog to edit an image or when saving a selected image, the UI crashes with strict prop validation and undefined property errors. This occurs due to recent refactoring in the `html_editor` framework. First, the base `MediaDialog` now strictly requires the `document` object as a prop. Because it was omitted in the payload, Owl's validation rejected the component. Second, the dialog's state management was updated, meaning `activeTab` is no longer accessed via `this.state.activeTab`, but rather via the `this.activeTab()` method. This commit fixes these issues by passing `window.document` into the dialog's initial props and when calling `renderMedia`. It also updates how we access activeTab. **Steps to reproduce:** - POS > Products > Products > choose any product > click the ‘edit’ button in the image > search something, e.g. ‘burger’ > select one of the resulting images **Current behavior before PR:** - Errors either after clicking the 'edit' button or after selecting one of the resulting images **Desired behavior after PR is merged:** - No errors when editing or saving images opw-6445843
The media tools now handle empty or incomplete image attachments without crashing. This keeps the Media Dialog and Chatter usable even when an upload is interrupted or an email creates a malformed attachment.
Original PR description
Problem: Interrupted uploads or malformed email payloads can create 0-byte binary `ir.attachment` records where the `checksum` is `False`. Accessing the computed `image_src` field on these records…
Problem:
Interrupted uploads or malformed email payloads can create 0-byte binary `ir.attachment` records where the `checksum` is `False`. Accessing the computed `image_src` field on these records triggers a `TypeError: 'bool' object is not subscriptable` when attempting to slice `attachment.checksum[:8]`. This crashes the Media Dialog and Chatter.
Purpose:
Add a fallback boolean guard to `attachment.checksum` inside `_compute_image_src` so that empty attachments evaluate safely to a string ('0') instead of raising a traceback, allowing the UI to render gracefully.
Steps to Reproduce on Runbot:
1. Go to Settings > Technical > Database Structure > Attachments.
2. Create a new record: Name: `test.png`, Type: `File` (Binary), File Content: [leave empty], Is public document: Checked.
3. Open any record with a Chatter (e.g., Contact or CRM Lead) and click "Insert Image" to open the Media Dialog.
4. The system attempts to evaluate `image_src` and throws the `TypeError`.
Notes:
A test (`test_compute_image_src_empty_checksum`) was added to `test_ir_attachment.py`
opw-6482674
Forward-Port-Of: odoo/odoo#287758
Forward-Port-Of: odoo/odoo#287444Fixed a stock delivery issue where items packed into separate packages could appear under the same package on the final delivery when related moves were merged. This helps warehouse teams keep package tracking accurate during multi-step deliveries and avoids confusion at shipment time.
Original PR description
Steps to reproduce --- 1. Set the warehouse to deliver in 3 steps. 2. Create a delivery pick not tied to a procurement group (not from a sale order) with a consumable product, and validate it. 3. On…
Steps to reproduce --- 1. Set the warehouse to deliver in 3 steps. 2. Create a delivery pick not tied to a procurement group (not from a sale order) with a consumable product, and validate it. 3. On the pack transfer, put the goods in a package and validate. 4. Duplicate the pick, validate it, put its goods in a second package on the pack transfer, and validate. 5. Open the final delivery: both lines sit in the same package instead of one line per package. Issue --- The two picks share no procurement group, so their delivery moves merge onto a single move keyed by partner. Validating the second pack tops up that already partially reserved move: for a consumable, `_action_assign` builds its lines from `_get_available_move_lines`, which reports the availability of every upstream package without discounting what the move already reserved. https://github.com/odoo/odoo/blob/05af9e6877fd0f044bb46c983fe7300eb1db9307/addons/stock/models/stock_move.py#L1907-L1909 The package already reserved on the first line is therefore offered again and reused, collapsing both lines onto one package. The reserved-product branch below already subtracts the move's own reservation before allocating; doing the same here leaves each package on its own line. opw-6498532 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287935 Forward-Port-Of: odoo/odoo#284956
This fix prevents an error in Manufacturing when users switch from sample work orders to real planning records by changing filters. The planning list now transitions cleanly, improving reliability for teams reviewing manufacturing work orders.
Original PR description
Go to Manufacturing > Planning > Workorders > Planning > list view. Sample data are displayed. Remove a filter such that real records match the domain. Tracebacks are displayed because we call…
Go to Manufacturing > Planning > Workorders > Planning > list view. Sample data are displayed. Remove a filter such that real records match the domain. Tracebacks are displayed because we call `get_duration` on records that don't exist. The `useRecordObserver` of MrpTimerField subscribes the callback to the `useSampleModel` flag and to the `record`. When the filter is removed, the model is reloaded and, atomically, both the flag and the root and updated on the model. As the flag is toggled, the callback is executed. However, the props of the MrpTimerField aren't updated yet, so the `record` used in the callback is still the old, sample, one. One could argue that there's a design flaw in the model as at some point, a `record` could contain sample data while it's model states that we're not in sample mode (`record.model.useSampleModel` is false). That's true and that's something we'll change in the future, but in master. We fix this issue with an easier patch, which consists in accessing the `useSampleModel` flag with `untrack`, i.e. to not subscribe to that flag's changes, as in that case, the component will be destroyed anyway. 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
Blog pages now count only real visitor discussions, not internal staff chatter logs. This prevents inflated comment totals and gives readers and editors an accurate view of engagement on blog posts.
Original PR description
Issue: The internal chatter logs were being counted as regular comments in the blog. Steps to reproduce: Create a website with a blog. Create a page for the blog and activate comments. While editing go into blog post. Send a log in the chatter, and the blog will show one more message than it should. Cause: Both logs and comments have the same type: `Comment` and when doing the counting of comments we used this broader type, encompassing all of them. Fix: Corrected it to use the subtype `Discussions` as this one seems to be more relevant to actual blog post comments. opw-6287196 Forward-Port-Of: odoo/odoo#270998
Delivery pricing rules based on quantity no longer display the word "False" where a unit would normally appear. This makes rule names clearer for users configuring delivery methods and avoids confusing labels in shipping setup.
Original PR description
Quantity-based delivery pricing rules have no unit. The computed name formatted the empty value directly, displaying `False` in the rule name. Use an empty string when the computed variable unit is not defined. Steps to reproduce: 1. Open a delivery method configured as Based on Rules. 2. Add a pricing rule using Quantity as its condition. 3. Observe `False` after the quantity in the generated rule name. Before this commit: Quantity-based pricing rules displayed `False` as their unit. After this commit: Quantity-based pricing rules no longer display an invalid unit. 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
Hong Kong payroll and batch payment exports now handle missing employee ID details without crashing and validate required AutoPay information before generating files. This helps users catch missing bank reference or identification data early, reducing failed or incomplete HSBC/Hang Seng payment submissions.
Original PR description
When both identification_id and passport_id are empty (False), re.sub() receives a bool and raises: TypeError: expected string or bytes-like object, got 'bool'. Fall back to an empty string and normalize the passport fallback the same way as the HKID. The HSBC/Hang Seng (l10n_hk_mri) AutoPay file format requires a Payment Set Code, a First Party Reference and a per-payment identifier (HKID or passport number); without them the file was silently generated with missing data. Validate these in l10n_hk.bank.format._validate() so the check is shared by both consumers of the format: the payroll payment report and the generic batch payment export. Add the matching Party Reference check to l10n_hk_payment_autopay's journal validation so batch payments get a proper RedirectWarning to the journal instead of a bare error. Task-6536846
This update prevents an error when users set a partner's country to Saudi Arabia after entering a Company ID as an additional identifier. It helps keep partner creation and updates working smoothly for Saudi Arabia localization users.
Original PR description
Currently, an error occurs when the user sets the partner's country to Saudi Arabia. **Steps to Reproduce:** - Install the `l10n_sa` module with demo data. - Switch to `My Saudi Arabia Company`. -…
Currently, an error occurs when the user sets the partner's country to Saudi Arabia. **Steps to Reproduce:** - Install the `l10n_sa` module with demo data. - Switch to `My Saudi Arabia Company`. - Create a `partner` and click the `+` icon next to the VAT Number. - Select `Company ID`, set any `value`. - Set the partner's country to `Saudi Arabia`. `KeyError: 'OTHER'` After the [recent commit], OTHER is removed from vals [1] when at least one other EN identifier, excluding OTHER, is available. If a user selects OTHER (Company ID) as an additional identifier and then changes the partner's country to Saudi Arabia, the available additional identifier metadata is recomputed. With the [second commit], it checks whether the stored additional identifier is applicable to Saudi Arabia by looking up its metadata [2]. However, since OTHER was removed from the available additional identifier metadata because another EN identifier is available, directly accessing the metadata for OTHER raises a KeyError. This commit ensures that the additional identifier is safely accessed in the metadata. [recent commit]: https://github.com/odoo/odoo/commit/9087c2ddc1de3e9ef9431188a9b6dddbd6b58552 [second commit]: https://github.com/odoo/odoo/commit/fddf7653ba898f5db9d97ae3cd9f885c6c5c658a [1]- https://github.com/odoo/odoo/blob/1d50ff71a1edf2c4226cb2f68cf3bbe4e39485f6/odoo/addons/base/models/res_partner.py#L1423-L1425 [2]- https://github.com/odoo/odoo/blob/1d50ff71a1edf2c4226cb2f68cf3bbe4e39485f6/addons/l10n_sa/models/res_partner.py#L17-L18 sentry-7717445803 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Error logs now include the missing attachment's filename, making it easier for support teams to identify what went wrong. This helps speed up troubleshooting when attachment IDs are unavailable or not useful.
Original PR description
When an attachment is not found, we should log the filename as well as often the attachment id is None and tells us nothing.
Mexican electronic payment complements now report tax amounts using the correct decimal precision for the payment currency. This prevents valid payments from being rejected by the PAC/SAT validation, especially for MXN payments and foreign-currency invoice settlements.
Original PR description
The 'ImpuestosP' node of the payment complement (Pagos 2.0) is reported with 6 decimals while the SAT expects the amounts to be expressed with the number of decimals supported by the currency of the…
The 'ImpuestosP' node of the payment complement (Pagos 2.0) is reported with 6 decimals while the SAT expects the amounts to be expressed with the number of decimals supported by the currency of the payment ('MonedaP'), as published in the 'c_Moneda' catalog, for example 2 decimals for MXN.
Steps to reproduce:
- Have an MX Company setup with Quadrum as PAC.
- Create and sign a customer invoice in MXN with a 16% IVA tax.
- Register a full payment and send the payment complement to the PAC.
Issue:
Payment will be rejected
```
Code : CRPER654
Message : El importe del campo BaseP que corresponde a Traslado, no tiene la cantidad de decimales que soporta la moneda (MonedaP)
```
Analysis:
Quadrum recently aligned its validation on that rule and now rejects the document having fields with too much decimals and, currently, fields like BaseP, ImporteP are pinned to 6 decimals in the template.
Reporting them with the decimals of the payment currency is not enough when the payment settles a document expressed in another currency: those amounts are also compared with the ones of the related documents converted with 'EquivalenciaDR', and the PAC expects the values truncated or rounded
```
Code : CRP20274
Extra Info : Traslados: La sumatoria de ImporteDR es mayor al ImporteP 1.30.
Valores minimos permitidos: Truncado: 1.29 o redondeado: 1.3
```
opw-6561617
Forward-Port-Of: odoo/enterprise#131343
Forward-Port-Of: odoo/enterprise#131267This fixes an issue where some Belgian customers or suppliers could no longer be reached through Peppol after their identifier type changed. Odoo now rechecks the alternative Belgian Peppol identifier when sending, improving the chances that electronic invoices reach the correct recipient.
Original PR description
Some partners were registered on Peppol with EAS 9925 (Belgian VAT) but have since moved to 0208. They became unreachable via Peppol because we never check if they exist on the network with EAS 0208, which makes their status `not_valid`. This fix forces the re-checking of the status with EAS 0208 for partners having EAS 9925 and a `not_valid` status. task-6296017 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278919 Forward-Port-Of: odoo/odoo#270742
Large blog imports could fail or finish incomplete when many links needed updating. This change processes link replacements in smaller batches, helping imports complete reliably without timing out.
Original PR description
This commit fixes an issue where huge blog requests were timing out due to large replacements for links that weren't controlled with our batch creation wrapper. This resulted in incomplete imports. The fix is to put the text replacements in the batch create wrapper which will avoid timeouts and let it continue reliably.
Odoo now keeps its HTTP error handling reliable when a request address is too long and rejected early by the server. This prevents an additional internal error during the response process, helping keep server behavior stable in edge cases.
Original PR description
- When the request URI is too long, the HTTP server rejects the request before parsing the headers. As a result, `self.headers` is not available when the WebSocket compatibility code in `send_header()` and `end_headers()` is executed. - Access `self.headers` safely to avoid an AttributeError while handling the 414 response. **opw-6501275** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286494 Forward-Port-Of: odoo/odoo#285870
This fix ensures that when a past point-of-sale order is later invoiced, the Spanish VeriFactu tax report cancels the original simplified receipt rather than the newly created full invoice. This prevents incorrect cancellation data from being sent to AEAT and keeps fiscal records aligned with the actual sale flow.
Original PR description
When creating an invoice for a previous POS order, the data sent to AEAT cancels the full invoice instead of the order's simplified invoice. Steps to reproduce: - Open a POS and make a sale without invoicing it; - In the POS, go to the Order tab; - Select the order and fully invoice it. Issue: The AEAT cancellation line added to the pos order actually cancels the full invoice just created [opw-6471927](https://www.odoo.com/odoo/project/49/tasks/6471927) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284277
General Ledger exports now use the same search behavior as the on-screen report. This ensures that when users filter account lines, the exported file includes the same results they see in the interface, reducing confusion and reconciliation errors.
Original PR description
When applying a search filter in the General Ledger, the lines displayed in the UI differ from the ones exported. The discrepancy comes from the fact that the UI search bar filters lines using a simple "contains" logic on the displayed line name, while the backend export relies on the account model’s `_name_search` behavior, just as in the chart of accounts. For example, searching for "40" displays the accounts 400000, 400010, and 124000 but the last one (124000) is not is in the export results. task: 5917435 Forward-Port-Of: odoo/enterprise#131011 Forward-Port-Of: odoo/enterprise#107928
This change cleans up references to an old developer option that no longer exists. It reduces confusion for administrators and developers by ensuring configuration and routing code no longer mention unsupported behavior.
Original PR description
The feature was removed in odoo/odoo#115076 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#287515 Forward-Port-Of: odoo/odoo#283352
This fix prevents Taiwan B2B invoices with down payments from being rejected by ECPay because of small tax rounding differences. E-invoices now report the same tax amounts as the posted invoice, reducing failed submissions and mismatched tax records.
Original PR description
Current behavior: -- Sending a B2B invoice that deducts a down payment is rejected by ECPay with "(item tax discrepancy exceeds 1 NT$)", so the invoice cannot be issued at all. When it is accepted,…
Current behavior: -- Sending a B2B invoice that deducts a down payment is rejected by ECPay with "(item tax discrepancy exceeds 1 NT$)", so the invoice cannot be issued at all. When it is accepted, the tax on the e-invoice can still differ from the tax the invoice books. Expected behavior: -- The invoice is accepted, and the tax reported on the e-invoice is the one the invoice booked. Steps to reproduce: -- - Set a company up in Taiwan (TWD) with the ECPay credentials filled in - Create a sale order of 190,630 for a customer with a VAT number - Invoice a 50% down payment through the down payment wizard, then a 30% one, and post both - Invoice the remainder and post it - Send the final invoice to ECPay Cause of the issue: -- _l10n_tw_edi_prepare_item_list rebuilt the tax from the raw amount of every line and rounded that total once. Both steps also disagree with the invoice. Negative lines resulting from downpayments seem to be more strictly checked on ECPay and taxes cannot be re-derived easily by ECPay's system. There is a also a relevant but slightly different issue where the invoice amount is calculated differently but the ECPay page will show a different value. e.g. the invoice rounds each computation key on its own: 50.00 - 16.50 = 33.50 rounds to 34 where the invoice books 50 - 17 = 33. No issue was detected for purely positive lines (a transaction with different products but no downpayment) Fix: -- Use the tax amount the line carries when it has one, and fall back to the raw amount otherwise, so the payload reports what the invoice booked. Send the tax of each line in the ItemTax field. Let ECPay derive its own per-item tax and checks it against the declared total for purely positive lines, and recalculate them for negative so the rounding difference between them is spread one unit at a time across the lines, the way ECPay distributes it. opw-6424237 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281928
This fix improves copy and paste behavior in the HTML editor when working with list items that contain nested lists. Users can now copy either a full list item or selected parts of it without accidentally losing the outer list or including unselected nested content.
Original PR description
Problem: Copying content from a list item containing a nested list can either include the unselected nested list or lose part of the copied content. Solution: - Detect whether the whole `<li>` was selected before copying the full list item with its nested lists. - When only part of the list item is selected, copy only the selected content and rebuild the required `<li>` wrapper. - Apply this logic only to list items with multiple top-level children. Steps to reproduce: - Add bullet list with nested list. - CTRL+A - Press Enter twice to create new paragraph. - Paste. - Observe the outer list is lost. task-6438347 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281205
Belgian payroll now checks that remuneration codes are entered as whole numbers. This helps prevent invalid payroll configuration data and reduces the risk of reporting or processing issues.
Original PR description
Task: 6536560 Forward-Port-Of: odoo/enterprise#130425
Creating multiple helpdesk teams with website forms now reuses the same website Help menu instead of adding duplicate menu entries. This keeps the website navigation clean and prevents confusion for visitors and administrators.
Original PR description
Currently on creating new helpdesk team everytime a new website menu is created. ### **Steps to Reproduce:** 1) Install website_helpdesk 2) Navigate to `Helpdesk>Configuration>Helpdesk Team`. 3)…
Currently on creating new helpdesk team everytime a new website menu is created. ### **Steps to Reproduce:** 1) Install website_helpdesk 2) Navigate to `Helpdesk>Configuration>Helpdesk Team`. 3) Create 2 helpdesk team with `Website Form` option enable. 4) Navigate to Website. ### **Observed Behavior:** Two Help menus are created. ### **Expected Behavior:** Multiple menus should not be created. ### **Root Cause:** The menu creation logic relies on the following [condition](https://github.com/odoo/enterprise/blob/b66097122ba3a758734ac6fb2b26579c35cb72c2/website_helpdesk/models/helpdesk.py#L111-L112) `team_count_by_website` is built from `_read_group(..., ['website_id'], ...)`, which keys its result by the `website_id` *recordset*, not its id. Looking it up with `team_count_by_website.get(website.id, 0)` therefore always misses and falls back to `0`, so `team_count <= 1` is always `True` regardless of how many teams already exist for that website. The only thing left guarding menu creation is `any(team.website_menu_id for team in teams)`, which only looks at the teams in the current create/write call, not every team on that website. So saving a second team in a separate call always creates another menu. ### Fix: Make the website menu a resource shared by every team with the website form enabled on a given website, instead of "owned" by whichever team created it: - Before creating a new menu, look up other teams (active or archived) that already point to a menu, matched through the `website_menu_id` relation between teams rather than a hardcoded `/helpdesk` URL, so a customized menu URL doesn't cause a duplicate to be created. Reuse that menu when found. - Only delete a menu once no team (active or archived) still references it, checked before removing a team's own reference. **opw-6303846** Forward-Port-Of: odoo/enterprise#130401 Forward-Port-Of: odoo/enterprise#121120
This fix prevents the Project app from crashing when users open a saved My Tasks favorite in the Pivot view. It ensures personal task stages are handled correctly in pivot reporting, so users can continue analyzing their tasks without interruption.
Original PR description
Since the introduction of `read_grouping_sets` for Pivot views, opening the Pivot view from a saved favorite filter can crash. ### **Steps to reproduce:** - Install Project. - Open My Tasks. - Save…
Since the introduction of `read_grouping_sets` for Pivot views, opening the Pivot view from a saved favorite filter can crash. ### **Steps to reproduce:** - Install Project. - Open My Tasks. - Save the current filter as a favorite. - Switch to the Pivot view. ### **Error:** ``` ValueError: Cannot convert project.task.personal_stage_id to SQL because it is not stored. ``` ### **Root Cause:** Since [commit](https://github.com/odoo/odoo/pull/194413/changes/166a546ec52784c413f5b5d7d29af89d618d6519), Pivot views use `_read_grouping_sets` instead of `_read_group`. `project.task` only remaps `personal_stage_type_id` to the stored `personal_stage_type_ids` in [_read_group](https://github.com/odoo/odoo/blob/5f6fb63d5d7585805642c702d096b2f882e73761/addons/project/models/project_task.py#L2169-L2179), so the remapping is bypassed for Pivot views. The ORM then attempts to group by the non-stored `personal_stage_type_id` relation, leading to the SQL conversion error. ### **Fix:** Mirror the remapping logic in `_read_grouping_sets` so Pivot views use `personal_stage_type_ids` before the ORM generates the SQL query. **opw-6306389** Forward-Port-Of: odoo/odoo#272985
This fixes a mobile and tablet issue where selecting a file inside an editable list could unexpectedly trigger an autosave and close the row being edited. Users can now add files to these list rows without their in-progress edits being silently discarded.
Original PR description
The form view autosaves on 'visibilitychange' (e.g. when the user switches tab/app) to avoid losing unsaved changes. On mobile, opening the native file picker for a binary field also fires 'visibilitychange', which triggered this autosave. When that binary field was part of an editable x2many list, the autosave forced the row out of edition before the file could be selected, silently discarding the edition in progress. Skip the autosave when a x2many field of the root record currently has a row in edition. Can be reproduced in eLearning > course > content > Additional Resources, on mobile devices (must force "desktop mode" in the browser), and on tablets. opw~6517735 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#287855 Forward-Port-Of: odoo/odoo#287581
Product cards using the Chips layout now keep proper spacing when shown in dynamic product snippets outside the shop page. This prevents cramped or collapsed cards on website pages, improving the storefront presentation for visitors.
Original PR description
Steps to reproduce: --- - Install the website_sale module with demo data. - Go to /shop and switch the product layout to Chips. - Exit the editor. - On the home page, open the editor and add the…
Steps to reproduce: --- - Install the website_sale module with demo data. - Go to /shop and switch the product layout to Chips. - Exit the editor. - On the home page, open the editor and add the Dynamic Products snippet. Issue: --- The Products snippet has collapsed card padding when the Chips layout is active. Root cause: --- - The Chips card layout defines `--_padding-base` using `var(--o-wsale-products-grid-gap)` with no fallback value. https://github.com/odoo/odoo/blob/4307f657c73a860c755e1499138a878268882f7a/addons/website_sale/static/src/scss/product_tile.scss#L632 - When the Products snippet renders outside /shop, the variable is undefined, causing the `calc()` to resolve to a guaranteed-invalid value which collapses the card padding. All other layouts are unaffected because they either do not use `--o-wsale-products-grid-gap` in their padding chain, or already provide a `16px` fallback at the point of use. https://github.com/odoo/odoo/blob/4307f657c73a860c755e1499138a878268882f7a/addons/website_sale/static/src/scss/product_tile.scss#L407-L410 Solution: --- - 16px matches the default value of `shop_gap` on the website model, ensuring correct padding whenever the variable is not explicitly set. https://github.com/odoo/odoo/blob/4307f657c73a860c755e1499138a878268882f7a/addons/website_sale/models/website.py#L128 ### Before: <img width="1456" height="563" alt="image" src="https://github.com/user-attachments/assets/c28ab183-0af3-4a2a-858d-b85d9995eb07" /> ### After: <img width="1427" height="550" alt="image" src="https://github.com/user-attachments/assets/e0ba80ec-10ad-433f-bf9a-acbaffd56a76" /> opw-6511483 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286185
Blog imports now reliably match posts to the correct blog even when multiple blogs share the same name. The change uses external identifiers to avoid mix-ups, improving accuracy when generating or migrating website blog content.
Original PR description
Blogs with the same name was creating a conflict in the mapping of id to created odoo blog, which meant that the blog post matching with the blog itself was failing. This fix introduces external ids for the blogs which is the id of the foreign website, making it much easier to keep track of the mapping between the external records and the created odoo records.
The delivery method wizard now recalculates shipping charges when a user manually changes the shipment weight. This prevents rule-based delivery fees from being added at an incorrect zero price, improving quotation and order accuracy.
Original PR description
Steps to reproduce ------------------ - Install `website_sale_stock` and `sale_management` module. - Create a product. - Create a rule-based delivery method with: - In Pricing tab click add a line -…
Steps to reproduce ------------------ - Install `website_sale_stock` and `sale_management` module. - Create a product. - Create a rule-based delivery method with: - In Pricing tab click add a line - condition: `Quantity >= 0` - variable factor: `weight` - price per unit: 2 - Create a quotation containing the product. - Open the delivery method wizard by clicking into `Add Shipping` - Select the rule-based delivery method. - Change the total weight from 0 to 10. - Add the delivery method. Issue ----- - Changing the total weight does not recompute the delivery price. - The delivery line is added with a price of 0 instead of 20. Cause ----- The delivery wizard defines `_onchange_carrier_id` for both `carrier_id` and `total_weight` https://github.com/odoo/odoo/blob/9860ba5a593c5e7723494674b62890d16ae1a9a8/addons/delivery/wizard/choose_delivery_carrier.py#L41-L50 The call flow is expected to be: `total_weight` change -> `_onchange_carrier_id` -> `_get_delivery_rate` -> `rate_shipment` `_get_delivery_rate` passes the manually entered weight through the `order_weight` context key: https://github.com/odoo/odoo/blob/9860ba5a593c5e7723494674b62890d16ae1a9a8/addons/delivery/wizard/choose_delivery_carrier.py#L87-L90 The rule-based carrier gives this context value priority over the saved order weight and the weight computed from order lines: https://github.com/odoo/odoo/blob/9860ba5a593c5e7723494674b62890d16ae1a9a8/addons/delivery/models/delivery_carrier.py#L588-L594 For example, with `total_weight = 10` and a price factor of 2, the expected calculation is: `delivery_price = 0 + 2 * 10 = 20` However, the pickup-location implementation added an override in `website_sale_stock` that declared only `carrier_id` as an onchange trigger: https://github.com/odoo/odoo/blob/0da3259034ff3b2b79f417df53969fe017207195/addons/website_sale_stock/wizard/choose_delivery_carrier.py#L13-L16 Since the override uses the same method name, its decorator replaces the base onchange specification. Therefore, changing `total_weight` does not call the method and the initial `delivery_price = 0` is kept. This does not occur in saas-19.2. because `website_sale_stock` does not override the delivery wizard there. The base method remains registered for both `carrier_id` and `total_weight`: The conflicting override was introduced later in this [commit](https://github.com/odoo/odoo/commit/0da3259034ff3b2b79f417df53969fe017207195) from saas-19.3 Fix --- Add `total_weight` to the `website_sale_stock` onchange decorator so the inherited delivery-rate computation runs when the user edits the weight. --- opw-6516301 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285864