Wednesday, September 9, 2026
27 changes · saas-19.1
Security fixes and vulnerability patches
This update prevents unauthorized changes to customer details during point-of-sale self-invoicing. It ensures invoices are only created after required customer information is validated and only allows edits by users linked to the customer record.
Original PR description
Before this commit: ------------------- - During self-invoicing, a public user could create a new customer or update the current order's customer data by submitting the self-invoicing form, without any access rights validation. - For logged-in users (portal or internal), invoice generation could proceed even when the user or the selected customer lacked the required invoicing information. After this commit: ------------------- - During self-invoicing, a public user can create a new customer for the order, but cannot modify the existing customer linked to the order. - For logged-in users (portal or internal), required customer information is validated before generating an invoice. Customer data can only be updated when the customer is the logged-in user's partner or a child contact of that partner. Task-6272660 Forward-Port-Of: odoo/odoo#286827 Forward-Port-Of: odoo/odoo#270112
Enhancements to existing features
Bank statement lines can now automatically reconcile installment-based accounting entries when the system is confident they belong together. This reduces manual reconciliation work and applies payments to installments in the expected order.
Original PR description
Moves with installments should be auto reconciled if we're sure the move is linked to the statement line. If we are sure that the installments are linked to the statement line then the installment with the lowest id should be reconciled first. task-6285410 Forward-Port-Of: odoo/enterprise#119891
Resolved issues and error corrections
Social posts now format text more accurately by tightening the rules used to detect special elements. This reduces cases where published content appears differently from what the user intended while composing the post.
Original PR description
This commit fixes an issue for the social post formatter mixin's regexes being too lenient. The rendering of some elements could be incorrect from what the user initially wanted to create as a post. Now the regexes have been narrowed down so that the resulting formatted value is more in line with what the user wanted. task-6026857 Forward-Port-Of: odoo/enterprise#110323
Italian electronic invoicing now handles cash rounding lines more safely when generating XML files. This avoids changing a shared tax calculation process, reducing the risk of side effects in other accounting flows while keeping the correct 0% exempt tax information in the invoice XML.
Original PR description
Remove the override of `_prepare_product_base_line_for_taxes_computation` since it's a low level method used by a lot of flows. Instead, we just add the 0% exempt tax on the line on-the-fly at the generation of the xml. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287016
Improves how Odoo finds related child records when moving items in large hierarchies, allowing the database to use indexes instead of scanning whole tables. This can significantly reduce waiting time for operations such as stock transfer validation in databases with many packages, locations, partners, or categories.
Original PR description
Our customer has 1.7M packages and very slow validate: the transfer took 8.6s, and 5.35s of it was the single `UPDATE` that `_parent_store_update` runs to move `parent_path` over a subtree. It looks…
Our customer has 1.7M packages and very slow validate: the transfer took 8.6s, and 5.35s of it was the single `UPDATE` that `_parent_store_update` runs to move `parent_path` over a subtree.
It looks for the descendants with `LIKE concat(node.parent_path, '%')`. The pattern comes from a column, so Postgres cannot use the index on `parent_path` and scans the whole table. The change asks for the same rows as a range, which the index does serve:
AND child.parent_path >= node.parent_path
AND child.parent_path < left(node.parent_path, -1) || '0'
`parent_path` always ends with `/` and `0` is the next character, so that closes the range on the subtree. Same rows, same order, one line of SQL.
On a table of 302000 rows, moving 62 nodes, both forms return the same 9362 rows: 3302ms before, 223ms after. On the customer database a single parent write went from 0.82s to nothing measurable.
-- before
Update on stock_package child (actual time=3175.525..3175.527)
-> Nested Loop (actual time=7.171..2987.424 rows=9362)
Join Filter: ((child.parent_path)::text ~~ concat(node.parent_path, '%'))
Rows Removed by Join Filter: 18714638
-> Seq Scan on stock_package child (rows=302000)
-> Materialize (rows=62 loops=302000)
Execution Time: 3301.796 ms
-- after
Update on stock_package child (actual time=223.040..223.041)
-> Nested Loop (actual time=7.874..22.389 rows=9362)
-> Index Scan using stock_package_pkey on stock_package node (rows=62)
-> Index Scan using stock_package__parent_path_index on stock_package child
Index Cond: ((parent_path >= node.parent_path) AND (parent_path < left(node.parent_path, -1) || '0'))
Execution Time: 223.041 ms
This is not about only `stock.package`. Every model on `_parent_store` pays it once the table grows, `res.partner` and `stock.location` included.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287180Reconciled bank statement lines now show the related account name when the original entry name is just “/”. This makes reconciliation information easier to read and reduces confusing blank or placeholder labels for accounting users.
Original PR description
This commit will treat move with "/" as their name as empty, and put the name of the account in the reconciled line name task-6424612 Forward-Port-Of: odoo/enterprise#127842
Generating sample timesheet data now skips partners that do not have an email address, preventing an error in the Timesheet Assistant. This helps users complete setup and demos smoothly even when partner records are incomplete.
Creating a new job position will now show the creation message only once in the chatter log. This removes a small source of confusion and keeps recruitment activity history cleaner for users.
Original PR description
When creating a new job position, "Job Position created" was rendered twice in the chatter log. This occurred because the mail subtype definition specified a redundant `description` field with the exact same text as the subtype's name, causing the chatter logic to display both. Removing the explicit `description` field ensures the message is only displayed once upon job creation. Task: 6486002
The accounting duplicate check now covers receipts as well as bills and invoices. This helps prevent duplicate supplier or customer documents from being missed when their type is changed.
Original PR description
Right now a duplicate is detected if it's a bill, but is not when you switch it to a receipt. This fix makes sure that both bills and purchase receipts duplicates are detected and are checked against each other. The same change is done for invoices and outgoing receipts. task-6115836 Forward-Port-Of: odoo/odoo#279455
This update keeps PDF handling compatible across supported Ubuntu and newer PDF library versions. It reduces the risk of document-related errors when generating or processing PDFs in Odoo.
Original PR description
Align pypdf usage with the PyPDF2 1.26 API used on Ubuntu Jammy, Odoo 17.0's main supported Ubuntu version, and add the missing compatibility mapping for newer pypdf versions. Forward-Port-Of: odoo/enterprise#130971
Closing an AI live chat conversation no longer triggers an unwanted chat window to appear afterward. This improves the website visitor experience by making the close action behave as expected and avoiding confusing follow-up messages.
Original PR description
Closing the chat with the ai agent on the ai_livechat snippet results in a chatwindow popping up which gives a bad user experience. Steps to reproduce: - Log in as Mitchell Admin. - Go to website. -…
Closing the chat with the ai agent on the ai_livechat snippet results in a chatwindow popping up which gives a bad user experience. Steps to reproduce: - Log in as Mitchell Admin. - Go to website. - Click on edit and choose `Contact & Forms`. - Add the AI Livechat website snippet. - From the snippet options, add an AI Agent and choose a livechat team. Make sure that Mitchell Admin is configured as an operator for that livechat team (livechat channel). - Click on save. - Open an incognito tab. Log in as Marc Demo. - Go to Website. - Type a message inside the `ASK AI` text area and press enter. - Wait until you receive a response and then click close. - A chat window will popup with the messages of the conversation with the AI along with a message saying `Visitor has left the channel`. This happens because `close` button will call `closeConversation` => `livechatService.leave()` => `visitor_leave_session` => `_close_livechat_session` that posts a message that the visitor has left the channel. This commit solves the issue by setting the user who left the channel as the author of the `visitor left chat` message instead of OdooBot. Forward-Port-Of: odoo/odoo#258836
Fixed a spelling mistake in the Helpdesk Auto Assignment group name. This ensures the setting appears correctly and avoids confusion for users managing helpdesk assignment options.
Original PR description
This commit fixes the typo in the "Auto Assignment" group. task-6542450 Forward-Port-Of: odoo/enterprise#130880 Forward-Port-Of: odoo/enterprise#130841
The Point of Sale ticket view was updated to use the current customer company reference after an older field was removed. This prevents errors when viewing or processing POS ticket information involving customer company details.
Original PR description
Since PR https://github.com/odoo/odoo/pull/211043 company_name field on partner is removed and we are using parent_name instead This commit replace company_name with parent_name to avoid traceback.
Company-paid expenses created from a project now apply the project allocation only to the actual expense line, not to balancing lines. This prevents project expense reporting from incorrectly cancelling itself out and gives businesses more accurate project cost figures.
Original PR description
### Current behavior: Creating a company-paid expense from the Project overview posts a journal entry with the project analytic on both the expense and outstanding lines, so the analytic balance nets to zero ### Expected behavior: Analytic distribution should only be on the P&L (expense) line ### Steps to reproduce: 1. Open a project overview and create a company-paid expense 2. Submit, approve, and post it 3. Open the journal entry: analytic is on debit and credit lines ### Cause of the issue: `project_id` stays in the context after `clean_context` during `_create_company_paid_moves`. With `sale_project`, AML analytic compute then applies the project distribution to outstanding/tax lines as well ### Fix: Removed `project_id` from the context when creating company-paid moves opw-6368848 Forward-Port-Of: odoo/odoo#280256
Fixed an issue where submitting a tax report opened from a return could update or submit a different return for the same period. This is especially important for Dutch VAT corrections, ensuring the correction return is handled instead of the original VAT return.
Original PR description
Opening a tax report from a return and submitting it could act on a different return than the one on screen. _get_return_from_report_options searches by company, period and report with limit=1, but…
Opening a tax report from a return and submitting it could act on a different return than the one on screen. _get_return_from_report_options searches by company, period and report with limit=1, but that combination is not unique: l10n_nl declares two return types on l10n_nl.tax_report, nl_tax_return_type and nl_tax_correction_return_type, so a VAT return and its correction both match. Which one is returned is then decided by _order (is_completed, date_deadline, name, id). For a Dutch VAT correction it resolves to the original VAT return of the same quarter, so send_xbrl submits and flags that record instead of the correction. The options already carry the return type they were built for, in the return_periodicity filter, so restrict the search to it when it is set. l10n_nl_reports kept a return_id option for the same reason when computing the already declared amount of a suppletie; it can use _get_return_from_report_options now. opw-6421300 Forward-Port-Of: odoo/enterprise#127073
This fixes an issue in the website editor where clicking inside a navigation link could move the text cursor to the beginning of the link. Editors can now place the cursor where they click, making navigation link edits more predictable and less frustrating.
Original PR description
Problem: Clicking inside a navigation link in website builder causes the caret to jump to the start of the link element. Cause: `LinkPlugin` unconditionally reset the selection to the start of non-editable link elements, ignoring whether the anchor node was inside an editable child element. Solution: Do not reset selection if the anchor node is inside a `contenteditable` element. Steps to reproduce: - Open website builder. - Click inside a navbar link to place the caret. => Caret no longer jumps to the start of the link. opw-6535386 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287224 Forward-Port-Of: odoo/odoo#286527
The Mexican point-of-sale invoicing checks were updated to match the newer self-invoicing process, where public users can no longer change customer details directly. This helps keep automated validation aligned with the corrected customer data flow and reduces the risk of false failures in future releases.
Original PR description
Before the related pr commit: - Public users could update customer data during the self-invoicing flow. - The test_qr_code_receipt_mx test relied on this behavior when updating customer data. After the ref commit: - Public users can no longer update customer data during self-invoicing. - Update test_qr_code_receipt_mx to create a new partner with the required customer data when the order is not linked to a customer. Related PR: odoo/odoo#283470 Task-6272660 Forward-Port-Of: odoo/enterprise#130561 Forward-Port-Of: odoo/enterprise#129948
Fixed a crash that could stop Factur-X/CII vendor bill imports when a matched reverse-charge tax had no eligible positive tax lines. This prevents users from seeing a vague import failure and helps affected bills import reliably.
Original PR description
Steps to reproduce: Import a Factur-X / CII bill in a company where the matched purchase tax is the negative-only sibling of a reverse-charge pair (e.g. intra-EU services in the RRIF Croatian chart).…
Steps to reproduce:
Import a Factur-X / CII bill in a company where the matched purchase tax is the negative-only sibling of a reverse-charge pair (e.g. intra-EU services in the RRIF Croatian chart). The import fails with:
Error importing attachment 'factur-x.xml' (...):
This specific error occurred during the import: list index out of range
Observation:
_distribute_delta_amount_smoothly spreads leftover rounding cents across a tax's positive-factor lines. For the negative only sibling, that list (target_factors) is empty, but delta_amount is still non-zero. The method goes straight to factors[0] and raises IndexError. account_edi_ubl_cii catches the traceback and shows only str(e), which is why the user sees the bare "list index out of range" with no file or line.
The fix:
Return early with an empty list when target_factors is empty, same as the existing early-return for a zero delta_amount. Mirrored in the JS helper.
opw-6462024
Forward-Port-Of: odoo/odoo#286163Dropshipped purchases are now excluded from average cost calculations, preventing them from changing inventory values when the goods never enter stock. This avoids incorrect negative balances in stock valuation accounts after dropshipping and later normal sales.
Original PR description
stock_*: stock_account, stock_dropshipping, stock_landed_costs **Problem:** dropship moves impact the average cost of products which can lead to negative balance in stock valuation account **Steps to…
stock_*: stock_account, stock_dropshipping, stock_landed_costs **Problem:** dropship moves impact the average cost of products which can lead to negative balance in stock valuation account **Steps to reproduce:** On a new db with no demo data and stock_dropshipping, sale_management and accountant module installed (bug also reproducible in runbot with same steps, but it's easier to see the negative impact on accounting on a new db) : 1) enable dropshipping 2) create a storable product with average perpetual category 3) in the purchase tab set a vendor with a price of 10 4) in the inventory tab select the dropship route 5) create PO for 1 unit @ 5, validate receipt and confirm bill 6) confirm a SO for 1 unit of the product 7) confirm linked PO and validate dropship move 8) confirm invoice and vendor bill -> see how the standard price is now 7.5 9) remove dropship route from the inventory tab of the product 10) confirm a SO for 1 unit of the product 11) validate delivery and confirm invoice 12) open 'inventory valuation' view **Current behavior:** the initial balance of stock valuation is -2.5 **Expected behavior:** it should be 0 (there shouldn't be a negative initial balance if all invoices and bills are confirmed) **Cause of the issue:** The issue happens after step 8) The problem is that the dropship has an impact on the average price of the product but not on the accounting. Before the dropship we have 1 unit in stock @ 5 and the stock valuation account has a balance of 5 (from the bill), so all is good. The dropship then changes the standard price to 7.5. That's because currently, in _run_average_batch() the dropship move first impacts average cost like an incoming move with a value of 10 (at this point we have 1 move @ 10 and 1 @ 5 so average cost is 7.5) https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L493-L500 https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L505-L510 and then it impacts the value as a regular outgoing move (meaning it leaves the inventory at the average cost of 7.5) and does not impact the average cost (which is the basic behaviour of outgoing moves) https://github.com/odoo/odoo/blob/bcaa8b6b00fa1f16513d680c5187fd424bc7cf8c/addons/stock_account/models/product.py#L515-L517 https://github.com/odoo/odoo/blob/60b5b99d569dbe183ef9c980217ccfe9bf243756/addons/stock_account/models/product.py#L522 Therefore after step 8), the standard price is 7.5 and we have a unit in stock so, in the inventory valuation view the ending stock is 7.5$. But the dropship did not impact the stock valuation account so the initial balance is still 5$ and we have lines with credits and debits of 2.5$ in the the stock variation section. After steps 9 to 12, both the initial balance and ending stock decrease by 7.5 (which is expected), leading to a negative initial balance in stock valuation. **fix:** We don't take into account the stock move from dropships in the avco computation **tests:** The fix requires modifications in a few tests: - test_dropship_bill_standard_price_update checks that the bill of a dropship move impacts the standard price, so we delete this test - test_lot_normal_3, the asserts on the total_value still make sense but not those on standard_price - test_dropship_kit_bom_updates_component_standard_price test_average_cost_dropship_in_negative_quantity, test_out_move_validate_as_stock_user: standard price should not be impacted by dropship Task 6515358 Forward-Port-Of: odoo/odoo#285576
Journal item labels created by reconciliation models now use the company language instead of varying by the user or automated process applying them. This prevents inconsistent or incorrect labels on accounting entries, especially after duplicating and translating reconciliation models.
Original PR description
### Problem `label` on `account.reconcile.model.line` is a **translatable** field, but its value is written onto the journal item created when the model is applied (`account.move.line.name`). That…
### Problem
`label` on `account.reconcile.model.line` is a **translatable** field, but its value is
written onto the journal item created when the model is applied (`account.move.line.name`).
That means the label is read in the language of whoever applies the model:
- a user working in another language writes the translated value;
- the auto-reconciliation cron writes the **source** value, since it runs as OdooBot.
So the very same reconcile model ends up writing two different labels on the journal items,
depending on who applied it.
### How it shows up
It becomes visible when a reconcile model is created by **duplicating** an existing one and
the label is then edited while working in a non-source language. The translation holds the
new text, while the source value silently keeps the label of the original model — and the
source value is exactly the one the cron writes. The result is a set of journal items where
some carry the intended label and some carry the label of an unrelated model.
### Fix
The journal item belongs to the company, so the label is read in the **company** language
via a small `_get_aml_label()` helper, instead of the language of the current environment.
It falls back to the current behaviour when the company has no language set.
`_prepare_aml_vals()` is the only place in 18.0 that reads `self.label` for the journal item.
### Test
Adds `TestBankRecWidget.test_auto_reconcile_model_label_uses_company_lang`: a reconcile model
whose line label is translated in the company language, applied by the auto-reconciliation
cron running in the source language, and asserts the journal item carries the company-language
label.
```
odoo -d <db> -u account_accountant --test-enable --stop-after-init \
--test-tags /account_accountant:TestBankRecWidget.test_auto_reconcile_model_label_uses_company_lang
```
Without the fix the test fails with `[{'name': 'Frais bancaires'}] != [{'name': 'Bank fees'}]`;
with the fix it passes. The full `account_accountant` suite was also run on a clean 18.0
database: 203 tests, 0 failed, 0 errors.
Forward-Port-Of: odoo/enterprise#130719
Forward-Port-Of: odoo/enterprise#128433On mobile devices, the editor toolbar is now hidden when users open a full-screen image preview. This prevents overlapping controls and makes the image preview toolbar accessible, improving the editing experience.
Original PR description
When displaying the full screen image preview lightbox on mobile, the toolbar remains displayed. Because of this, the toolbar of the lightbox cannot be accessed. This commit hides the toolbar when a lightbox is displayed. task-6370220 Forward-Port-Of: odoo/odoo#286346 Forward-Port-Of: odoo/odoo#274949
French invoices now show the VAT-on-debits note only when it is relevant for service taxes with a non-zero VAT amount. This avoids missing the note for eligible service invoices and removes unnecessary wording from 0% export or international invoices.
Original PR description
**Purpose** Follow-up to fix two issues reported in #277109 regarding the "TVA exigible d'après les débits" mention on French invoices. **Fixes Applied** 1. **Tax Scope Mismatch:** Changed `t.tax_scope == 'consu'` to `t.tax_scope == 'service'`. To trigger the exigibility mention on a service product, the user will configure a proper "service" scoped tax, not a goods tax. 2. **International/Export Invoices:** Added a check for `amount != 0`. Previously, the mention would print on international export invoices if the applied 0% tax had exigibility set to `on_invoice`. This hides the redundant mention for 0% exports. Forward-Port-Of: odoo/odoo#277468
This fix ensures pivot report measure options defined by the report are still available after users deselect a measure and refresh or filter the view. It prevents valid reporting options, such as point of sale order measures, from disappearing and keeps report configuration predictable.
Original PR description
TL;DR - we lose the measures from arch after a reload, if removed from activeMeasures Step to reproduce: - install pos, create few orders - go to reporting> orders> switch to pivot view - click the…
TL;DR - we lose the measures from arch after a reload, if removed from activeMeasures Step to reproduce: - install pos, create few orders - go to reporting> orders> switch to pivot view - click the `Measures` dropdown, `Order` is already selected - untick it, then apply some filter so that view reloads (ex order date) - reopen `Measures` dropdown, notice `Order` is missing form measures Cause: - view `view_report_pos_order_pivot` has `<field name="order_id" type="measure"/>` in its pivot view https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/point_of_sale/views/pos_order_report_view.xml#L10 - `order_id` is M2O field - Measure is compute from present `activeMeasure` and fields of type `["integer", "float", "monetary"]` https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/utils.js#L89-L120 - when the view is first loaded, `activeMeasure` all the fields with `type="measure"` which is directly passed to pivot's model as a metadata https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/pivot/pivot_arch_parser.js#L59-L60 https://github.com/odoo/odoo/blob/f5c68cf0eb2ce6ec96dd4006b28466044af10e33/addons/web/static/src/views/pivot/pivot_view.js#L41 - when we toggled the `order_id` from measure and reloaded, `order_id` is popped from `activeMeasure` and as it's field type is `many2one` it is not considered for `measures` in `computeReportMeasures` Fix: - maintain the measures from arch separately and feed it to `computeReportMeasures` opw-6416196 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286013 Forward-Port-Of: odoo/odoo#278850
The accounting logo is now shown correctly in tax return activities. This makes the activity view clearer and more consistent for users working with accounting and tax return tasks.
Original PR description
Before PR: - Accounting logo was not visible in Tax return activities. After PR: - Accounting logo is visible in Tax return activities. task-6463584 Forward-Port-Of: odoo/enterprise#130721 Forward-Port-Of: odoo/enterprise#129501
SEPA direct debit XML files now include a bank-specific identifier only for countries where it is required by Nordea. This prevents Italian banks from rejecting payment files due to an unexpected extra field, helping businesses process direct debit batches more reliably.
Original PR description
### Issue: An unexpected `<SchmeNm><Cd>CUST</Cd></SchmeNm>` node was added inside `<InitgPty><Id><OrgId><Othr>` for all countries Some Italian banks reject SDD files containing this node ### Cause:…
### Issue: An unexpected `<SchmeNm><Cd>CUST</Cd></SchmeNm>` node was added inside `<InitgPty><Id><OrgId><Othr>` for all countries Some Italian banks reject SDD files containing this node ### Cause: https://github.com/odoo/enterprise/commit/3c3c64b511d07fc1ba33c30363972f5b0f7283d6 added `<SchmeNm><Cd>CUST</Cd></SchmeNm>` unconditionally for all countries The original fix was intended for Nordea (Sweden) only, which requires this node explicitly The assumption that other countries would accept it was incorrect ### Steps to reproduce: - Install `account_sepa_direct_debit` and `l10n_it` - Switch to the IT company - In Settings, set SEPA Direct Debit Creditor Identifier to `BE30ZZZ300D000000042` - Create and confirm a Payment (Method: SEPA Direct Debit, any customer and amount) - Create and validate a Batch Payment with that payment - Open the generated PAIN008 XML Before the fix, `<SchmeNm><Cd>CUST</Cd></SchmeNm>` is present opw-6530996 Forward-Port-Of: odoo/enterprise#130304
The Indian GST reporting token refresh now correctly extends the existing token's validity without replacing the saved token with an unrelated response value. This prevents incorrect token data from being stored and helps keep GST reporting authentication stable.
Original PR description
Previously, `_cron_refresh_gst_token` updated the value of `l10n_in_gstr_gst_token` when refreshing the GST token using `response.get('txn')`.
However, the response received during a token refresh is: `{'status_cd': '1', 'status_desc': 'If previous Auth Token is found'}`
The GST token itself remains unchanged during a refresh; only its validity is extended. Therefore, writing `l10n_in_gstr_gst_token` with `response.get('txn')` is unnecessary and incorrect.
This commit removes that write operation.
Forward-Port-Of: odoo/enterprise#130726
Forward-Port-Of: odoo/enterprise#130313Fixed a display issue in field service quotations where enabling the optional Related Task column could move or cut off section amount totals. This keeps quotation lines easier to read and helps users verify section totals accurately.
Original PR description
Steps to reproduce: --- - Install `industry_fsm_sale` module. - Create a quotation. - Add a section line, then a product line below it. - Enable the optional `Related Task` column from the column…
Steps to reproduce: --- - Install `industry_fsm_sale` module. - Create a quotation. - Add a section line, then a product line below it. - Enable the optional `Related Task` column from the column selector. Issue: --- - When the Related Task optional column is enabled, the section line's aggregated Amount value appears in the wrong column or is clipped. Root cause: --- - `getSectionColumns()` computes the section title's colspan as `columns.length - sectionCols.length + 1` [1]. This formula assumes all non-section columns sit in the middle of the list, with the aggregated amount column (`price_subtotal`) anchored at the right end. - The `task_id` [2] field was added via `position="inside"`, which appends it at the end of `<list>` after `price_subtotal` — breaking that assumption by placing a non-section column after the aggregated amount column. - This makes the section title colspan one unit too wide when `task_id` is enabled, shifting the section's aggregated Amount cell past the `price_subtotal` header column. Fix: --- - Changed the xpath to insert `task_id` after the `discount` field, placing it in the middle of the column list where the colspan formula correctly absorbs it into the title span and keeps the amount column aligned. [1]: https://github.com/odoo/odoo/blob/ed22e3c299d6606f8014e2ffdd4a30f5c7be83ec/addons/account/static/src/components/section_and_note_fields_backend/section_and_note_fields_backend.js#L449 [2]https://github.com/odoo/enterprise/blob/2de1512bce6e2bef16ebd45629cbaf0839bebcbf/industry_fsm_sale/views/sale_order_views.xml#L9-L11 Before: <img width="1254" height="262" alt="image" src="https://github.com/user-attachments/assets/7a62c22c-b002-49d9-a75c-f569987f565e" /> After: <img width="1230" height="337" alt="image" src="https://github.com/user-attachments/assets/951f213a-09af-4b07-be30-d69dae2cc51e" /> opw-6472638 --- Forward-Port-Of: odoo/enterprise#129125