Friday, September 18, 2026
21 changes · saas-19.3
Resolved issues and error corrections
Fixed an issue where opening Point of Sale orders for a company could show a blank screen if one of its delivery addresses had no name. The order list now uses the parent company name as a fallback, so staff can view related orders without disruption.
Original PR description
Steps to reproduce: - Create a company contact with a delivery address that has no name - Make a PoS order for the delivery address and pay it - Open the PoS, open the customer list, and click…
Steps to reproduce: - Create a company contact with a delivery address that has no name - Make a PoS order for the delivery address and pay it - Open the PoS, open the customer list, and click "Orders" on the company Issue: The screen goes blank. Cause: The ticket screen is opened with the company name as search term. The server domain searches on `partner_id.complete_name`, so the orders of the address contact are returned too. They are then fuzzy matched on `getPartnerName()`, which returns `false` for a partner without a name, and `fuzzyLookup` calls a string method on it. The error is raised during rendering, so the whole app is destroyed. Fix: Make `getPartnerName()` always return a string, and fall back on the parent name, like the complete name does. This way the orders of the address contact are still listed when searching on the company name, instead of being filtered out by an empty name. opw-6578541 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288880
Google Merchant Center product feeds now exclude video thumbnails from extra product images. This also avoids loading full image files just to check them, reducing memory usage and preventing feed generation failures for catalogs with many images.
Original PR description
Description of the issue/feature this PR addresses: The Google Merchant Center feed builds the extra image URL list of each product, and must skip the `product.image` records holding a video, as…
Description of the issue/feature this PR addresses:
The Google Merchant Center feed builds the extra image URL list of each product, and must skip the `product.image` records holding a video, as their image is only a thumbnail of that video. It filters those out by accessing `image_128`, which is wrong on two counts:
- A video record does have an `image_128`: the thumbnail, fetched from the video URL or uploaded by the user. Video thumbnails were therefore listed in the feed as if they were product images.
- Binary fields are read and base64-encoded in full by default, so the binary content of every extra product image was loaded into memory just to evaluate a truthiness check. On a database with ~4261 products with images, rendering the feed exhausts the worker memory limit and raises an out-of-memory error.
Current behavior before PR:
`_get_extra_image_1920_urls()` keeps every extra image whose `image_128` is set, including video thumbnails, and forces the ORM to fetch and base64-encode the full content of every extra image attachment.
<img width="2038" height="1462" alt="image" src="https://github.com/user-attachments/assets/e3b375e5-ac17-4b5c-b0c3-59264d7e36f7"/>
Desired behavior after PR is merged:
The records are filtered on `video_url`, the field that actually flags a video, so videos are properly excluded and no image binary is read at all.
opw-6513194
Forward-Port-Of: odoo/odoo#288323
Forward-Port-Of: odoo/odoo#286782This fixes an issue where sending a Peppol invoice with an invoice line missing both product and label caused a technical crash. Users will now see the expected validation message so they can correct the invoice instead of being blocked by an error traceback.
Original PR description
### Steps to Reproduce: 1. Activate Peppol 2. Create invoice for customer with Peppol 3. Add line without product name or label 4. Send invoice through Peppol and observe the Traceback error ###…
### Steps to Reproduce: 1. Activate Peppol 2. Create invoice for customer with Peppol 3. Add line without product name or label 4. Send invoice through Peppol and observe the Traceback error ### Issue: When generating a Peppol invoice, there will be a Traceback error if an invoice line is missing both a product and a label. The XML builder evaluates the missing `cbc:Name` element as `None` instead of an empty dictionary. Therefore, attempting to directly subscript `['_text']` on it throws a TypeError traceback. This prevents the user from seeing the standard validation warning about the missing item data. ### Solution: We can update the document node constraint check to safely access the dictionary keys using `.get()` with an empty dictionary fallback. This prevents the traceback and ensures that the system will correctly display the intended validation error to the user. opw-6577441 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288713
The spreadsheet component was updated to a newer version with fixes for pivot table totals, printing, and demo content. This helps users get more accurate spreadsheet reports and avoids blank pages when printing.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/6577e5987e [REL] 19.3.21 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/6577e5987e [REL] 19.3.21 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/3974135626 [IMP] demo: debounce xml template build [Task: 6574005](https://www.odoo.com/odoo/2328/tasks/6574005) https://github.com/odoo/o-spreadsheet/commit/a37a388ba4 [FIX] demo: fix scorecard demo definition [Task: 6573109](https://www.odoo.com/odoo/2328/tasks/6573109) https://github.com/odoo/o-spreadsheet/commit/73d0a81048 [FIX] pivot: wrong running total with collapsed/hidden dimensions [Task: 6569607](https://www.odoo.com/odoo/2328/tasks/6569607) https://github.com/odoo/o-spreadsheet/commit/b5b9f4d2e8 [FIX] pivot: fix scope of `pivot_html_renderer` css [Task: 6523521](https://www.odoo.com/odoo/2328/tasks/6523521) https://github.com/odoo/o-spreadsheet/commit/f03414c527 [FIX] print: empty pages when printing [Task: 6559815](https://www.odoo.com/odoo/2328/tasks/6559815) Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya (rmbh) <rmbh@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com> Co-authored-by: Marceline Thomas (matho) <matho@odoo.com>
This fixes a display issue where large grid views could appear empty after part of the page was refreshed or recreated. The grid now recalculates immediately, reducing confusing blank screens and avoiding the need for users to scroll or resize the window to restore content.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#289039 Forward-Port-Of: odoo/odoo#281721
Starting a manufacturing work order now only consumes the components assigned to that specific step. This prevents materials for later work orders from being used too early, improving inventory accuracy and production tracking.
Original PR description
Version: -------- - saas-19.3+ Steps to reproduce: ------------------- 1. Install `mrp` module. 2. Enable Work Orders in Manufacturing settings. 3. Create a product with a Bill of Materials…
Version:
--------
- saas-19.3+
Steps to reproduce:
-------------------
1. Install `mrp` module.
2. Enable Work Orders in Manufacturing settings.
3. Create a product with a Bill of Materials containing two operations:
- Operation 1
- Operation 2
4. Add two components to the BoM:
- Component A, assigned to Operation 1 in consumed in Operation field(optional hidden),
with some onhand quantity
- Component B, assigned to Operation 2 In consumed in Operation field(optional hidden),
without onhand quantity
5. Create and confirm a Manufacturing Order for the product.
6. Click into Work Orders Tab and "Start" first operation
7. Click into Smart button "Product Moves" .
Issue:
------
Starting Work Order 1 also sets the consumed quantity of Component B, even though
Component B belongs to Work Order 2 and that work order has not been started.
Expected behavior:
------------------
Only components belonging to the work order being started should be auto-consumed.
Components assigned to future work orders must remain untouched until their respective
work order becomes active.
Cause:
------
Before saas-19.3 , `mrp_workorder` override `stock.move._should_bypass_set_qty_producing()`
and bypassed moves having an `operation_id`.
This prevented `mrp.production._set_qty_producing()` from updating operation-specific component moves.
from saas-19.3, `manual_consumption` was removed from `stock.move` as part of the consumption-flow simplification. The enterprise override of `_should_bypass_set_qty_producing` was removed in this [commit](https://github.com/odoo/enterprise/commit/f5c22231853fde1082fe2dec0fe286521677dfbc
)
The base implementation now only bypasses moves that are done, cancelled, or have a zero demanded quantity:
https://github.com/odoo/odoo/blob/d1867ed4299d20f870da587e8711ccb6da5bbdfd/addons/mrp/models/stock_move.py#L553-L557
However, the inverse method of `mrp.workorder.qty_producing` calls `mrp.production._set_qty_producing()`
without indicating which work order initiated the update:
https://github.com/odoo/odoo/blob/d1867ed4299d20f870da587e8711ccb6da5bbdfd/addons/mrp/models/mrp_workorder.py#L196-L205
When a work order is started, `button_start()` sets its `qty_producing` to its remaining quantity:
https://github.com/odoo/odoo/blob/d1867ed4299d20f870da587e8711ccb6da5bbdfd/addons/mrp/models/mrp_workorder.py#L655-L667
The call chain is:
mrp.workorder.button_start()
|
| wo.qty_producing = wo.qty_remaining
v
mrp.workorder._set_qty_producing()
|
| production.qty_producing = wo.qty_producing
v
mrp.production._set_qty_producing(False)
|
| iterates production.move_raw_ids
|
+--> Component A / Work Order 1
| |
| +--> quantity is updated as expected
|
+--> Component B / Work Order 2
|
| move is not picked
| _should_bypass_set_qty_producing() returns False
v
move._set_quantity_done(new_qty)
|
+--> Component B is consumed prematurely
`mrp.production._set_qty_producing()` processes all raw and relevant finished moves of the
Manufacturing Order without filtering them by
work order:
https://github.com/odoo/odoo/blob/d1867ed4299d20f870da587e8711ccb6da5bbdfd/addons/mrp/models/mrp_production.py#L1456-L1489
Consequently, the move for Component B passes the existing bypass conditions.
Its quantity is set according to the Manufacturing Order's producing quantity despite
its linked work order still being in the "To Do" state.
Fix:
----
Pass the work order initiating the quantity update to `mrp.production._set_qty_producing()`.
When the method is called from a work order, skip moves explicitly linked to a different work order.
Moves belonging to the active work order and moves without a work-order assignment continue to be
processed normally.
The new argument is optional, so existing callers such as the standard Manufacturing Order
form keep the current MO-wide behavior.
---
opw-6439638
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThe mail plugin now allows administrators to set how long its login tokens remain valid, with a default of seven days. This reduces the need for users to sign in every day while keeping the tokens limited to the Outlook-related plugin access points.
Original PR description
Purpose ======= Allow customizing the expiration time of tokens, so users don't need to login everyday in the plugin. This is customized with a system parameter, with a default of 7 days. Those tokens are limited to endpoints `auth="outlook"`. Task-6466253 Forward-Port-Of: odoo/odoo#288572 Forward-Port-Of: odoo/odoo#287767
Fixed an issue where some saved values in quotation header or footer PDFs could disappear when generating a PDF Quote. This ensures sales teams and customers see the complete quote content as intended, especially when using PDFs with structured form fields.
Original PR description
Issue: --- When a quotation header/footer PDF has a hierarchical AcroForm field, the value set for that field is silently dropped from the generated PDF Quote when running on pypdf 5.4.0. Steps to…
Issue: --- When a quotation header/footer PDF has a hierarchical AcroForm field, the value set for that field is silently dropped from the generated PDF Quote when running on pypdf 5.4.0. Steps to reproduce: 1- Using a python 3.13 env, install requirements.txt (or otherwise run with pypdf==5.4.0 instead of PyPDF2). 2- Upload a header/footer PDF whose form field is a hierarchical field (`/T`/`/FT`/`/V` on the parent, not on the widget itself). The attachment from the ticket can be used as a sample to reproduce the bug. 3- Create a SO and select that document in the Quote Builder tab. 4- Print -> PDF Quote. 5- The value bound to that field does not appear in the printed PDF. Cause: --- After https://github.com/odoo/odoo/commit/4b02fbd717f62dd5345dad3ffb8d428c1c180007 `_add_pages_to_writer` renames the parent `/Field` object's `/T` when the widget itself has none. PyPDF2's `addPage` inserted the reader's page as is, keeping the widget's `/Parent`. pypdf 5.4.0 deep clones the page instead and ignores `/Parent` at every depth, so the widget loses the link to that field. It ends up with neither `/T` nor `/FT`, hence nothing matches the value mapping. Fix: --- Merge the field into its widget annotations instead: copy the prefixed `/T` and the inheritable keys onto each of them, then drop `/Parent`. The field's own `/T` is left untouched, so a field owning several widgets is filled on all of them. opw-6508728 Forward-Port-Of: odoo/odoo#287676 Forward-Port-Of: odoo/odoo#286186
This fixes an issue where users could not split an already approved expense if it included a receipt or attachment. Odoo now allows the split process to copy the original receipt to the new expense lines while still preventing normal attachment changes on approved expenses.
Original PR description
Steps to reproduce: ---------------------------------------- 1. Install the Expense module. 2. Create an expense with a receipt/attachment and approve it. 3. Try to split the approved expense using…
Steps to reproduce: ---------------------------------------- 1. Install the Expense module. 2. Create an expense with a receipt/attachment and approve it. 3. Try to split the approved expense using the "Split Expense" button. Observation: ---------------------------------------- An Access Error is raised: "You can't add attachments to an expense once it has been approved." Issue: ---------------------------------------- When splitting an approved expense, Odoo duplicates the original expense into multiple split parts. Since the original expense is already in the `approved` state, the newly created duplicate records also have `state == 'approved'`. During the split process, Odoo copies the attachments from the original expense to the newly created split records: https://github.com/odoo/odoo/blob/e696bc516c97bc7157d52c5dba0b42e7cb8bab48/addons/hr_expense/wizard/hr_expense_split_wizard.py#L59-L61 Because `copied_expense.state` is 'approved', the create method of `ir.attachment` triggers an AccessError via the security validation https://github.com/odoo/odoo/blob/e696bc516c97bc7157d52c5dba0b42e7cb8bab48/addons/hr_expense/models/ir_attachment.py#L23-L27 Solution: ---------------------------------------- Bypass the attachment restriction if the creation is initiated from the split wizard. It only bypasses the validation during the split operation, preserving the security constraints for normal user uploads to approved expenses opw-6373579 Forward-Port-Of: odoo/odoo#276139
Bank synchronization no longer removes payment options that were already configured on a bank journal. This protects customized incoming and outgoing payment setups while still adding any missing default options needed after sync.
Original PR description
**Steps to reproduce:** - Install Accounting - Configure "Bank" journal: * Add several incoming payments * Add several outgoing payments - From Accounting dashboard, connect Bank (e.g. Odoo Bank Sync Demo) **Issue:** After bank sync, all the incoming/outgoing payments added on the Bank journal are removed. Only the default ones are re-created. **Solution:** Keep all the existing incoming/outgoing payments (i.e. payment method lines) and only create the default ones for the payment method types that don't exist. opw-6424407 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281658
This fix ensures accounting totals stay accurate when external tax data changes without other invoice line changes. It prevents mismatches between product lines and tax lines, reducing the risk of incorrect invoice or accounting totals.
Original PR description
The account_external_tax module can modify extra_tax_data without modifying anything else on the lines. This results in: - a desync between the product lines and tax lines, - incorrect totals This makes sure we regenerate the appropriate tax lines and recompute the totals fields. opw-6547387
This fixes an issue where mobile Point of Sale users could not see the search field options on the Orders screen. Users can now reliably search orders by reference, receipt, invoice, date, or customer on small screens.
Original PR description
Steps to reproduce: - Open a PoS session on a small screen (mobile app or mobile browser) - Register at least one order, so the order list is not empty - Go to the Orders screen and type a term in…
Steps to reproduce: - Open a PoS session on a small screen (mobile app or mobile browser) - Register at least one order, so the order list is not empty - Go to the Orders screen and type a term in the search bar Issue: On a desktop the search bar drops down the list of fields to search on (Reference, Receipt Number, Invoice Number, Date, Customer). On a small screen that list never shows up, so the search silently falls back to the first field and there is no way to search by Date or by Customer. Cause: The list is rendered, but painted behind the order list. Under the media-breakpoint-down(sm) block of ticket_screen.scss the order list becomes `position: sticky; z-index: 1`, so a sibling rule raised `.search .fields` to `z-index: 2` to keep the dropdown on top. The `z-1` utility class put on that dropdown in 07f743843830 compiles to `z-index: 1 !important` and overrides the rule. Both elements end up at `z-index: 1` in the same stacking context, and the order list wins the paint order because it comes later in the DOM. Fix: Drop the `z-1` utility and declare `z-index: 2` on `.fields` in the search bar's own stylesheet, which makes the small-screen override in ticket_screen.scss redundant. The stacking of the dropdown now lives in a single place, next to the rest of its styling, so a utility class added to that element cannot silently disable it again. A tour clicks its target element directly and so cannot see a purely visual overlap, which is why the existing MobileTestUi runs of TicketScreen.search() never caught this. The added assertion checks that a suggestion is the topmost element at its own center. opw-6540466 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287930 Forward-Port-Of: odoo/odoo#286983
Accounting prediction logic now uses the most recent previous entries instead of older records. This helps predictive suggestions reflect current business activity and improves the relevance of automated accounting assistance.
Original PR description
This commit: https://github.com/odoo/enterprise/pull/38830/changes#diff-6f6931855e0903ff0d3f2b39bd5703ceaef9bdf9a516862b83f38d2d5b21a232 change the order of the predictive queries, removing the sorting order by date. Based on the current docstring: https://github.com/odoo/enterprise/blob/66682012145e5116ebec0183102bc5e930c2c343/account_accountant/models/account_move.py#L676 this is not correct, as we expect to retrieve the previous 100 entries, rather than the oldest ones. Correcting the query order ensures that the most recent entries are considered for predictive purposes. opw-6558929 Forward-Port-Of: odoo/enterprise#132022 Forward-Port-Of: odoo/enterprise#131731
AI image editing no longer fails when a user selects an unsupported image type such as SVG. Instead, the AI is told that the image cannot be read in its current format, allowing it to guide the user or continue with requests that do not require the original image.
Original PR description
Prior to this commit, the ai image tools did not check the format of the provided image before sending it to the AI provider. While editing a website, selecting an image in a format unsupported by AI…
Prior to this commit, the ai image tools did not check the format of the provided image before sending it to the AI provider. While editing a website, selecting an image in a format unsupported by AI providers (such as an SVG, e.g. the 'Your Logo' image shown in the top left) and choosing to edit it with AI would open a chat window, but the request to the provider would fail once the file was sent, since AI providers only support: {'png', 'jpg', 'jpeg', 'webp', 'gif'}.
This commit adds a format check to the image tools. When the referenced image is in an unsupported format, its raw data is no longer sent to the provider; instead, a text note describing the situation (path and format) is added to the AI's context. This lets the agent handle the request appropriately instead of the call failing outright: it can ask the user to provide the image in a supported format (or a description to recreate it), or proceed normally if the request doesn't actually require reading that image (e.g. generating a new image from scratch).
How to reproduce:
- enable the Website and AI modules.
- open the website, and enter edit mode.
- double click the website logo in the top left ('Your Logo'), then click 'AI'.
- a chat window opens; ask the AI to modify the image.
Current behavior:
- An error is raised, warning of an unsupported file format ('image/svg+xml').
Expected behavior:
- No error. The AI agent recognizes it cannot read the image in its current format and responds accordingly instead of the request failing.
task: 6432373Customer payments in Mexican electronic invoicing now inherit the payment method configured on the selected bank journal instead of always defaulting to electronic transfer. This helps payment complements sent to the SAT reflect the intended payment method, reducing reporting errors and manual corrections.
Original PR description
Currently, payment way configured on a bank journal is not taken into account, payments will default to "03 Transferencia electrónica de fondos". Steps to reproduce: - Set the "Payment Way" of a bank journal to "04 Tarjeta de Crédito". - Manually create a customer payment in that journal - Look at the "Payment Way" of the payment, then send the payment complement (REP) to the SAT. Issue: The payment way is "03 Transferencia electrónica de fondos" and the REP carries FormaDePagoP="03" The one set on the journal is ignored. Analysis: We should evaluate the journal before the transferencia default so a payment inherits the payment way, and keep transferencia as the last possible value. opw-6493514 Forward-Port-Of: odoo/enterprise#130863 Forward-Port-Of: odoo/enterprise#130133
Renewal and upsell quotations for cancelled subscriptions can now be confirmed even when the original subscription no longer has a recurring plan. This prevents an unexpected error and helps sales teams complete subscription changes without manual workarounds.
Original PR description
## Steps to Reproduce: - Install the Subscriptions module with demo data. - Create a quotation containing a subscription product. - Set a recurring plan and confirm the quotation. - Create an upsell…
## Steps to Reproduce: - Install the Subscriptions module with demo data. - Create a quotation containing a subscription product. - Set a recurring plan and confirm the quotation. - Create an upsell quotation or a renewal quotation. - Cancel the original subscription. - Remove the recurring plan from the cancelled subscription. - Open either the upsell or renewal quotation and confirm it. ## Error: `TypeError - '>=' not supported between instances of 'datetime.date' and 'bool'` ## Cause: Since Commit https://github.com/odoo/enterprise/commit/315be581a4212b46191e0c4f82b02a2c3fde51dc#diff-07cf1dda5423f99452a763a54fb6e7fdbb861e19b1a9dca00cab093a832490a9, `plan_id` is no longer required when a subscription is in the cancelled state. During the confirmation of an upsell or renewal quotation, the parent subscription's next invoice date is used for several date validations. However, if the parent subscription is cancelled and its plan is removed, the `next_invoice_date` is computed as False. Comparing a date object with a boolean value leads to an error. ## Fix: This commit adds an extra check before using the next invoice date. sentry-7661150764 Forward-Port-Of: odoo/enterprise#128093
The Ecuador ATS tax export now consolidates data from a company and its branches when they file under the same RUC. This prevents branch invoices and totals from being omitted, helping businesses submit complete and accurate tax reports.
Original PR description
In Ecuador, a company and its branches file under a single RUC, so the ATS is expected to consolidate all of them. However, currently the system exports only the active company report. Steps to…
In Ecuador, a company and its branches file under a single RUC, so the ATS is expected to consolidate all of them. However, currently the system exports only the active company report. Steps to reproduce: - Install the Ecuadorian localization - Create a parent company and a branch, assign the RUC of the parent to the branch, and set the legal name of the branch in Settings - Post a customer invoice with taxes in the parent (e.g. 750) and another one in the branch (e.g. 250) - Activate both companies in the company selector - Go to Accounting > Reporting > Tax return - Select "Report: 104 (EC)", the dashboard shows the consolidated values - Click on the gear icon next to "Tax Return" and select ATS Issue: The exported XML only contains the documents and the totals of the parent company (750). The branch (250) is omitted. Analysis: Currently the ATS export use self.env.company for all searches, which only retrieve the data of the first company set opw-6469807 Forward-Port-Of: odoo/enterprise#128430
This fix corrects how long accounting reports scroll on iPhones and iPads, preventing the scroll indicator from being hidden behind report content. It improves usability for users viewing tax and other scrollable reports on mobile Apple devices while keeping desktop behavior unchanged.
Original PR description
### Issue: On iPhone and iPad (reduced window), the scrollbar is hidden behind the report on long scrollable pages This affects all browsers on iOS and iPadOS — Apple forces the use of WebKit (its…
### Issue: On iPhone and iPad (reduced window), the scrollbar is hidden behind the report on long scrollable pages This affects all browsers on iOS and iPadOS — Apple forces the use of WebKit (its rendering engine) on all of them, including Chrome and Firefox ### Steps to reproduce (on iPhone): - Install `l10n_es` (contains scrollable reports by default) - Switch to the ES company - Open the Tax Report and try to scroll Before the fix, the scrollbar renders behind the report content ### Cause: `o_content` was added unconditionally in commit https://github.com/odoo/enterprise/commit/d60ea6e0f3245e394fd0cee5f22f52aff2a79e2e But its role differs between desktop and mobile, and its presence on mobile triggers a WebKit compositor bug On desktop, `o_content` is required: `.o_action` stays `overflow: hidden`, so only `.o_content` (`overflow: auto`) can scroll the report Per the CSS flexbox spec, a flex item won't shrink below its content size unless its `overflow` is not `visible` Without `o_content`, the div keeps `overflow: visible`, refuses to shrink, overflows `.o_action`, and the excess is silently clipped — content becomes unreachable, not just visually different On mobile, the framework flips scroll responsibility to `.o_action` (`overflow: auto`) and forces `.o_content` back to `overflow: initial` `o_content` is therefore not needed on mobile On WebKit (iOS/iPadOS), keeping `o_content` on mobile is harmful: it sits as a non-scrolling `position: relative` node between the real scroll ancestor (`.o_action`) and descendants that require special compositing — the sticky `thead` and the fixed-position mobile chatter This configuration causes WebKit's compositor to miscalculate the Root layer bounding box This geometry mismatch is the most likely explanation for why the native scroll indicator renders behind the report instead of on top of it Removing `o_content` on mobile avoids this node entirely and restores correct compositor geometry ### Notes: Tested on Android (Blink) with and without `o_content`: no visual difference and identical compositor layer geometry confirmed via Chrome DevTools — no regression introduced The `padding-bottom` on `.o_account_report_scroll_container` is unrelated — it is applied unconditionally and exists for a separate bug (last row clipped on scroll) opw-6191827 Forward-Port-Of: odoo/enterprise#128528
One-time purchases of products that can also be sold by subscription are no longer treated as ongoing subscriptions in stock forecasts. This prevents inflated future demand and helps replenishment decisions reflect actual sales commitments.
Original PR description
When a recurring product (with `allow_one_time_sale = True`) is sold as a one-time purchase (no subscription plan), the stock forecast report and replenishment logic incorrectly treat it as an active…
When a recurring product (with `allow_one_time_sale = True`) is sold as a one-time purchase (no subscription plan), the stock forecast report and replenishment logic incorrectly treat it as an active subscription. This results in infinite projected future outgoing moves for standard sales. This occurs because the logic only checks if `recurring_invoice` is True on the product, ignoring whether the parent order actually has a `plan_id`. This commit fixes the issue by: 1. Updating `_get_stock_subscription_lines` in `sale.order.line` to filter out lines using `_subscription_is_one_time_sale()`. 2. Updating the domains in `stock.forecasted_product_product` to require `order_id.plan_id != False` for subscription forecasts, while correctly routing one-time sales (`order_id.plan_id == False`) back to the standard sale domain. 3. Adapting existing tests to verify that one-time sales do not generate future subscription stock forecasts. Task-6193648 Forward-Port-Of: odoo/enterprise#128018 Forward-Port-Of: odoo/enterprise#116889
Submitting a draft Denmark VAT report no longer fails because the report now receives the expected prior settings when calculating lines. This helps Danish businesses complete VAT filing workflows without interruption.
Original PR description
Currently, an error occurs when the user submits the draft Denmark VAT report. ``` TypeError: AccountReport.get_options() missing 1 required positional argument: 'previous_options' ``` When the user submits the draft Denmark VAT report, it gets the calculated lines of the current report by calling get_options method. However, get_options() requires the previous_options argument [1]. Since this argument is not passed [2], it raises the error. This commit ensures that an empty dictionary is passed as the previous_options argument when getting the report lines. [1]- https://github.com/odoo/enterprise/blob/e2aa3073dafa9377654c761e371a660415db1e88/account_reports/models/account_report.py#L2126 [2]- https://github.com/odoo/enterprise/blob/e2aa3073dafa9377654c761e371a660415db1e88/l10n_dk_reports/wizard/tax_report_wizard.py#L216 sentry-7380293202 Forward-Port-Of: odoo/enterprise#130320
Fixes a crash in Planning Analysis when users group results by customer while Sales Planning and Field Service Planning are both installed. This keeps the report usable for customer-based analysis and prevents an error from interrupting reporting workflows.
Original PR description
Currently, when both `sale_planning` and `planning_field_service` are installed, grouping the Planning Analysis report by Customer raises a ValueError and crashes the view. ### **Steps to…
Currently, when both `sale_planning` and `planning_field_service` are installed, grouping the Planning Analysis report by Customer raises a ValueError and crashes the view. ### **Steps to reproduce:** 1) Install `sale_planning` and `planning_field_service`. 2) Go to Planning > Reporting > Planning Analysis. 3) Click on any month to drill down. 4) Group by Customer. Error: ``` ValueError: Cannot convert planning.analysis.report.partner_id to SQL because it is not stored ``` ### **Root Cause:** Both `sale_planning` and `planning_field_service` extend `planning.analysis.report` and define `partner_id` differently. **sale_planning** Defination: https://github.com/odoo/enterprise/blob/778309d6f575be2074ea48aa253433563de1aa7c/sale_planning/report/planning_analysis_report.py#L13 **planning_field_service** Defination: https://github.com/odoo/enterprise/blob/778309d6f575be2074ea48aa253433563de1aa7c/planning_field_service/report/planning_analysis_report.py#L7 Because they don't depend on each other, they load alphabetically, meaning `sale_planning` (which defines it as a non-stored computed field) overrides `planning_field_service` (which expects it to be stored). Thus, the ORM treats `partner_id` as non-stored. When the web client attempts to group by this non-stored field via `_read_group` or `_read_grouping_sets`, the ORM fails to convert it to SQL and raises a ValueError. ### **Fix:** This commit overrides `_read_group` and `_read_grouping_sets`. If `partner_id` is non-stored and present in the `groupby` lists, we dynamically replace it with `sale_order_id.partner_id` (which is a valid stored column in the SQL view). We also apply this same remapping to the `order` parameter. This prevents the SQL conversion crash while successfully returning the grouped results. ### **Note:** As an alternative approach, the same fix can be applied once, at a lower level, by overriding `_read_group_groupby` and `_read_group_orderby` instead of `_read_group` and `_read_grouping_sets` separately. Both `_read_group` and `_read_grouping_sets` internally call these two helper methods to convert each groupby spec to SQL, so patching them there would cover every calls from a single pair of overrides, instead of duplicating the remap logic per entry point. But I chose to apply the following solution because we already have a reference of such a fix in the `project` module (**personal_stage_type_id** remapping, [commit](https://github.com/odoo/odoo/pull/163300/changes/191ac027dd1e5133b0bcc72ab44358431c508a1c#diff-93ba226020add6481cfeab916e69980a59163e2925a5c2c9a3bc0aaceb484cdfR1987-R1998)), and it's more consistent to follow that established pattern. **opw-6346701** Forward-Port-Of: odoo/enterprise#124052