Monday, September 14, 2026
20 changes · saas-19.2
Enhancements to existing features
This update makes the Belgian payroll employee family section handle senior dependents needing care consistently with the newer payroll behavior. It avoids confusion from a field that appeared to include disabled senior dependents but did not, helping payroll data reflect the intended dependent counts.
Original PR description
In the 19.2 branch, we changed the UI to make it look like the number of other disabled senior dependents was included in the "other senior dependent" field, but this is not the case. Since the `other_disabled_senior` field will be deleted in the 19.5 branch, instead of just fixing the UI in 19.2, this commit updates the logic to match the 19.5 behavior. We will now handle this using only the remaining field. Task that fixes it in 19.5: https://www.odoo.com/odoo/project/1251/tasks/6133227 Task ID: 6526570
External tax calculations now avoid an unnecessary clearing step before applying computed tax values. This improves processing time for invoices with many lines, especially when using services such as AvaTax, while keeping the same tax calculation behavior.
Original PR description
[PERF] account_external_tax: avoid redundant tax clearing Avoid unnecessarily clearing `tax_ids` before setting the externally computed taxes, as the field is immediately replaced with the new tax…
[PERF] account_external_tax: avoid redundant tax clearing Avoid unnecessarily clearing `tax_ids` before setting the externally computed taxes, as the field is immediately replaced with the new tax values. Performance testing was performed using an invoice containing 200 lines with externally computed AvaTax taxes. Performance testing: | Metric | Before | After | |--------------------------------|--------|---------| | `_set_external_taxes()` | ~1:13 | ~43.77s | | Total external tax calculation | ~1:16 | ~46.66s | This reduces the execution time of `_set_external_taxes()` by approximately 40% for a 200-line invoice, while preserving the existing functional flow. The optimization is not specific to AvaTax and benefits the common `account.external.tax.mixin` flow when setting externally computed taxes on multiple lines. Profiler comparison: Before: <img width="1548" height="442" alt="image" src="https://github.com/user-attachments/assets/a5f2553c-a926-4324-88b2-743ed9214bf5" /> After: <img width="1429" height="440" alt="image" src="https://github.com/user-attachments/assets/c9c9c673-4654-4e11-b5f2-ffa4ecc87038" /> **opw-6472692** Forward-Port-Of: odoo/enterprise#130982
Resolved issues and error corrections
This fixes a Point of Sale issue where removing a coupon reward could prevent the customer list from opening. The system now ignores deleted loyalty card records, allowing staff to continue selecting customers without interruption.
Original PR description
Steps to reproduce: - A coupon program with a coupon assigned to a customer - In the PoS, set that customer on the order - Enter the coupon code, its reward line is added - Remove the reward line -…
Steps to reproduce: - A coupon program with a coupon assigned to a customer - In the PoS, set that customer on the order - Enter the coupon code, its reward line is added - Remove the reward line - Click the customer button Issue: The customer list does not open. The PoS crashes with "TypeError: Cannot read properties of undefined (reading 'id')" raised while rendering PartnerLine. Cause: `partnerId2CouponIds` maps a partner to the ids of its `loyalty.card` records. It is filled at boot and on every `loyalty.card` create, but nothing ever removes an id from it: the models only trigger a create event. Removing the reward line of a code activated coupon deletes that card from the local models (`_setValue` in the order summary), so its id stays in the map while the record is gone. `getLoyaltyCards` pushed `models["loyalty.card"].get(id)` unconditionally, hence an `undefined` entry in the list the PartnerLine template iterates over with `t-key="_loyaltyCard.id"`. Fix: Skip the ids whose record no longer exists. The partner keeps its remaining cards, and the path where no card was deleted is unchanged. The stale id is not pruned from the map: it is reached through the reactive store proxy, and mutating it there would notify subscribers in the middle of a render. opw-6517564 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287503 Forward-Port-Of: odoo/odoo#286971
The Navarra SII tax agency connection now uses the current web service address after the previous one stopped working. This helps Spanish electronic tax reporting continue to connect reliably for companies using the Navarra SII integration.
Original PR description
The WSDL URL used for the Navarra tax agency SII web service was no longer working. It has been replaced with the updated endpoint 'ssii_1_1'. task-6457647 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285049
This update switches PINT electronic invoice generation away from the older BIS 2.0 export path to the newer UBL export. This helps keep Peppol and electronic invoicing formats aligned with current standards and supports the planned removal of legacy export logic.
Original PR description
Problem --------- Currently, PINT uses the old BIS2.0 export. Objective --------- Decouple the exports as an effort to remove the old BIS implementation. 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#287982 Forward-Port-Of: odoo/odoo#283585
Restaurant orders are now saved when the bill is printed, reducing the risk of losing order details if the system reloads. This helps staff keep accurate orders and avoids service disruptions or re-entry work.
Original PR description
We now sync the order when printing bill, to avoid loosing it in case of reload data. task-6527207 Forward-Port-Of: odoo/odoo#286157
Portal users can now submit product reviews with file attachments without hitting a generic Not Found error. This keeps the review experience working as expected when product discussions and ratings are enabled on the website.
Original PR description
A portal user cannot add an attachment when posting a review on a product page: submitting the review with a file attached fails with a generic "Not Found" error, while posting the exact same review…
A portal user cannot add an attachment when posting a review on a product page: submitting the review with a file attached fails with a generic "Not Found" error, while posting the exact same review without an attachment works fine.
Steps to reproduce:
-------------------
* Enable "Discussion and Rating" on a product page (Website > Customize)
* Log in as a portal user and open that product page
* Write a review, attach a file, then submit
> Observation:
"Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."
Why the fix:
------------
`product.template._get_mail_message_access()` demotes a portal user's create access to 'write' whenever
`env['website'].is_view_active('website_sale.product_comment')` is False, since 'write' access is a deliberate way to block posting when the feature is toggled off for the website. `is_view_active` only picks the correct, website-specific view when `website_id` is present in `self.env.context`; that key is injected by the website frontend only for routes declared `website=True`.
`/mail/attachment/upload` is not `website=True` (attachments used to go through the dedicated, `website=True` `/portal/attachment/add` route, removed when portal's attachment uploader was unified with mail's), so `website_id` is missing from context on that route, `is_view_active` falls back to the generic, shipped-`active="False"` view, and always reports the feature as disabled - even when it is actually enabled for the current website. Create access is then wrongly demoted to 'write', which a portal user never has on `product.template`, so the thread lookup fails and the controller raises `NotFound()`.
Resolve the current website from the request itself (`env['website'].get_current_website()`) and inject its id into context before checking `is_view_active`, instead of relying on `website_id` already being in context. This makes the check accurate regardless of which route triggered it.
opw-6539184
Forward-Port-Of: odoo/odoo#287674
Forward-Port-Of: odoo/odoo#287345Overtime worked during public holidays or days off is now calculated using the actual time worked instead of the employee's regular schedule. This ensures payslips reflect the correct extra hours and pay rate when employees work during non-working periods.
Original PR description
__ ## Error description When we configure overtimes based on timing for an employee whose work entry source is based on a working schedule. We set an overtime for this employee during a public…
__ ## Error description When we configure overtimes based on timing for an employee whose work entry source is based on a working schedule. We set an overtime for this employee during a public holiday. When computing the payslip, the overtime hours are computed wrongly. ## Reproduction steps 1. Create a new Work Entry Type. Set the rate at 150%, the shortcut behavior on Add, considered as Working time. Check Added to Monthly Pay. 2. Create an overtime ruleset. Add a line and make it based on timing, on any non-working day, between 5 and 20 hours. Check Pay Extra Hours, and select as work entry type the type you created at #1. 3. Create an employee. Make sure he has a current version, and that his work entry source is based on Working Schedule. Set the overtime ruleset that you just created. 4. Create a public holiday on September 14th from midnight to 23h45. Make sure to select under Working Hours the same schedule as the employee you just created. As Work Entry type, set the type you just created. 5. Create an attendance for this employee on September 14th from 6am to 1pm. You should see 7 validated extra hours, and in the tab Overtime Details, see the applied rule you just created. 6. Go to payroll and create a New Off-Cycle. Then generate a payslip for your employee. ## Expected behavior We should see 6 extra hours on the payslip. ## Unexpected behavior The obtained hours and days are wrong: we can only see 2 hours overtime (based on the schedule you set for your employee). ## Origin of the issue This is a weird case where an employee's work entry source is based on a working schedule (so we're not supposed to care about what time this employee works), but the time on which they work overtime during days off matters. We want such a configuration because we would want, for example, to pay an employee 200% if they work between midnight and 5 am, but pay them 150% if they do so during 5 am to 8 pm. As a result, we end up getting attendance intervals batch for an employee based on a working schedule, which requires a time start and a time end. Depending on the hours per day, it will start at 8am and end at 4pm. This isn't an issue for overtime worked on days not in the schedule, but for public holidays occurring during a day included in the schedule, it is: attendance interval batch will retrieve every day that is included in the employee's schedule, including leaves, which we don't want. After talking with the PO, the case shouldn't only be corrected for public holidays, but also for days off: if an employee takes a day off but is called to work during it nonetheless. __ taskid-6475865 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
Fixed a scheduling issue where one task that could not be placed could incorrectly affect other tasks assigned to the same person. This helps project plans keep dependent tasks in the next available slot instead of pushing them far into the future.
Original PR description
Steps to reproduce: 1. create three tasks A,B & C with the same assignee 2. make tasks B and C depend on A and start on the `date_deadline` of task A 3. set the duration of task B (processed before C) to be longer than the 53-week search window 4. reschedule task A to end after task C starts Problem: A candidate that couldn't be scheduled was putting its assignee in conflict, subtracting the inspected availability while failing from the shared pool. Consequently, every later candidate sharing that assignee got force-placed into the same forward reschedule fallback that lands near the tail of the 53-week search window instead of the next available slot. Solution: Each candidate should be evaluated on its own ability to fit, and the time it occupies should count against the shared pool. opw-6380163 --- Forward-Port-Of: odoo/enterprise#131351 Forward-Port-Of: odoo/enterprise#129326
This fix prevents users from opening another gear-menu dialog while a manufacturing order is loading from the Shop Floor view. It avoids disruptive errors on slower connections and makes navigation from work orders more reliable.
Original PR description
**Steps to reproduce:** * Install the **Manufacturing** module with **Work Orders** enabled. * Create and confirm a Manufacturing Order with at least one Work Order. * Open the **Shop Floor** view. *…
**Steps to reproduce:** * Install the **Manufacturing** module with **Work Orders** enabled. * Create and confirm a Manufacturing Order with at least one Work Order. * Open the **Shop Floor** view. * On a work order card, click the **gear** icon to open the menu dialog. * Click **Open Manufacturing Order** on a slow network connection. * Before the MO form view finishes loading, quickly click the **gear** icon again and open another dialog (e.g. Log Note). * The MO form view loads, destroying the shop floor component. * Close the Log Note dialog. **Observed behavior:** * An `UncaughtPromiseError: Component is destroyed` error is thrown because the dialog tries to interact with the shop floor component that has already been destroyed by the navigation to the MO form view. **Cause:** * When the user clicks "Open Manufacturing Order", `doAction` is called to navigate to the MO form view, and `props.close()` immediately closes the menu dialog. However, the shop floor component is still visible while the new view is loading. * During this gap, the gear button remains clickable. If the user opens another dialog (e.g. Log Note), that dialog holds a reference to the shop floor component. When the MO form view finishes mounting, the shop floor is destroyed, and closing the stale dialog triggers operations on the destroyed component. **Fix:** * Add an `actionPending` state flag to `MrpDisplayRecord`. When the user selects "Open Manufacturing Order" from the menu dialog, an `onSelect` callback sets `actionPending` to `true`, which disables the gear button and prevents any new dialog from being opened. * The flag is only set for `openMO` (which navigates away and destroys the component), not for other menu actions like Scrap, Add Component, or Log Note which open wizard dialogs and return to the shop floor. opw-6107579 Forward-Port-Of: odoo/enterprise#130921 Forward-Port-Of: odoo/enterprise#123490
Payment complements for Mexican electronic invoices now report tax amounts using the decimal precision required for the payment currency. This prevents valid payments from being rejected by the certification provider, especially for MXN payments and foreign-currency document 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#131267General Ledger exports now use the same search behavior as the on-screen results. This prevents missing accounts in exported files when users filter by text, improving consistency and trust in reporting.
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
Users with Invoicing & Banks access can now undo bank reconciliations when the related entry has not been reviewed. This removes an incorrect access error while keeping the stricter protection in place for reviewed accounting entries.
Original PR description
Steps to reproduce: - Install `Accounting` module - Change group of current user for "Accounting" to `Invoicing & Banks` - Accounting > Dashboard > Bank > Any reconciled bank statement line > Undo…
Steps to reproduce: - Install `Accounting` module - Change group of current user for "Accounting" to `Invoicing & Banks` - Accounting > Dashboard > Bank > Any reconciled bank statement line > Undo Reconciliation (<img width="38" height="48" alt="image" src="https://github.com/user-attachments/assets/b637e4f3-c43b-47d4-9de1-2f0e14d1efc9" />) Problem: Users with "Invoicing & Banks" access encounter an "AccessError" when undo a bank reconciliation when account move is not checked/reviewed. Cause: Upon undoing, `action_undo_reconciliation` method is called and recreates the statement move lines with `checked=True`. This value is forwarded to `account.move.write()`, where the `_is_user_able_to_review()` check requires `account.group_account_user`. As Invoicing & Banks users only have `account.group_account_basic`, therefor access check raises an AccessError. Solution: Preserve the existing `checked` state when resetting the statement line so that unchecked lines can be unreconciled while the access restriction remains for checked lines. opw-6409216 Forward-Port-Of: odoo/enterprise#129671 Forward-Port-Of: odoo/enterprise#127895
Users with Invoicing & Banks access can now undo bank reconciliations for items that have not yet been reviewed, without hitting an access error. The fix keeps the existing review status during the undo process, so stricter permissions still apply to already reviewed items.
Original PR description
Steps to reproduce: - Install `Accounting` module - Change group of current user for "Accounting" to `Invoicing & Banks` - Accounting > Dashboard > Bank > Any reconciled bank statement line > Undo…
Steps to reproduce: - Install `Accounting` module - Change group of current user for "Accounting" to `Invoicing & Banks` - Accounting > Dashboard > Bank > Any reconciled bank statement line > Undo Reconciliation (<img width="38" height="48" alt="image" src="https://github.com/user-attachments/assets/b637e4f3-c43b-47d4-9de1-2f0e14d1efc9" />) Problem: Users with "Invoicing & Banks" access encounter an "AccessError" when undo a bank reconciliation when account move is not checked/reviewed. Cause: Upon undoing, `action_undo_reconciliation` method is called and recreates the statement move lines with `checked=True`. This value is forwarded to `account.move.write()`, where the `_is_user_able_to_review()` check requires `account.group_account_user`. As Invoicing & Banks users only have `account.group_account_basic`, therefor access check raises an AccessError. Solution: Preserve the existing `checked` state when resetting the statement line so that unchecked lines can be unreconciled while the access restriction remains for checked lines. opw-6409216 Enterprise PR: https://github.com/odoo/enterprise/pull/127895 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285253 Forward-Port-Of: odoo/odoo#282411
This fix ensures that when a previous point-of-sale order is later invoiced, the data sent to the Spanish tax authority cancels the original simplified receipt rather than the newly created full invoice. This prevents incorrect tax reporting and helps businesses keep Verifactu submissions accurate.
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
Fixed an inventory issue where separate packages could be incorrectly combined during multi-step deliveries when related delivery moves were merged. This helps warehouse teams keep accurate package tracking through picking, packing, and shipping.
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#287820 Forward-Port-Of: odoo/odoo#284956
Copying and pasting list items that contain nested lists now preserves the intended content more accurately. This prevents users from accidentally losing the outer list structure or copying nested items they did not select, improving editing reliability in the HTML editor.
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
Taiwan B2B e-invoices sent through ECPay now use the tax amounts recorded on the invoice, preventing rejection when down payments create negative lines. This keeps the submitted e-invoice tax aligned with the booked invoice and reduces manual correction or failed issuance risk.
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 fixes an issue where selecting a file on mobile or tablet could accidentally save the main form and close an editable list row. Users can now add files to editable list entries without losing the changes they were making.
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
Fixed an issue where users could encounter an error when opening the Project task Pivot view from a saved favorite filter. This keeps task reporting accessible and reliable when using personal task stages.
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