Thursday, April 30, 2026
17 changes · saas-19.2
Enhancements to existing features
This update enhances the bank reconciliation process by displaying the analytic distribution of each reconciliation line. This provides users with clearer insights into where funds are being allocated, improving accuracy and reducing potential errors. The changes were adapted from existing bank reconciliation components.
Original PR description
For automated reco models, we didn't take the amount into account. That means that some lines could have a suggestion of reco model that makes no sense. This commit will allow to show the analytic distribution of a line in the line to reconcile so that it's clear for the user. (Most of the code is taken from the analytic distribution widget and adapted) Also make the popover works on hover task-5733382 Forward-Port-Of: odoo/enterprise#106118
This update adjusts Odoo's reporting to align with new Indonesian tax regulations (Act 2025). Previously, reports relied on specific tax sections, but now they utilize report line names and tax tags for accurate calculations. This ensures compliance and accurate reporting of TDS/TCS taxes.
Original PR description
In this commit, the XLSX export and report warning are adapted to support the newly introduced TDS/TCS reports as per Act 2025. Previously, the XLSX reports depended on TDS/TCS sections. However, with Act 2025, certain taxes no longer have associated sections. This dependency has been removed, and report generation now relies on report line names and tax tags instead. task-6124431 Forward-Port-Of: odoo/enterprise#115679 Forward-Port-Of: odoo/enterprise#113916
Resolved issues and error corrections
This update fixes a critical issue where gift cards and e-wallets could be reused after being refunded, leading to potential misuse. It now prevents refunds and ensures order lines are created correctly when products are linked to multiple loyalty programs, improving program accuracy and preventing data inconsistencies.
Original PR description
Previously, it was possible to refund a gift card or e-wallet after creation. However, the associated code remained usable, allowing the gift card or e-wallet to be reused, which is not the expected behavior. To address this, refunds for gift cards and e-wallets are now prevented. Additionally, when a product is part of the trigger products for multiple gift card or e-wallet programs, it was not possible to create separate order lines for the same product with different programs selected. The second line was merged into the first. A condition has been added to prevent merging when different programs are selected. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6052281 Forward-Port-Of: odoo/odoo#261647 Forward-Port-Of: odoo/odoo#256896
This update strengthens the security of Xendit payments by requiring a valid access token linked to the specific transaction. Previously, payments could be processed without this verification, creating a potential risk. Now, payments are restricted to the correct transaction, improving security and preventing unauthorized payments.
Original PR description
**Description of the issue/feature this PR addresses:** The `/payment/xendit/payment` endpoint did not enforce validation of an access token tied to the transaction when processing direct payment requests. **Current behavior before PR:** The endpoint accepted public requests using only the transaction reference, allowing payment execution without verifying that the request was linked to the intended transaction. **Desired behavior after PR is merged:** The endpoint now requires a valid access_token associated with the transaction (reference) before processing. This ensures that payment execution is restricted to the correct transaction. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261912 Forward-Port-Of: odoo/odoo#260258
This update resolves an issue where the 'Remove Format' function would get stuck in an infinite loop when used with icons and background colors in the To-do app. The fix ensures that icons are correctly processed during format removal, preventing the loop and restoring normal functionality.
Original PR description
Steps to reproduce: =================== 1. Open the To-do app and pick any task. 2. In the description add text and an icon with a bg color. `(you can add this: <i class="fa rounded rounded-circle…
Steps to reproduce: =================== 1. Open the To-do app and pick any task. 2. In the description add text and an icon with a bg color. `(you can add this: <i class="fa rounded rounded-circle fa-user bg-o-color-1 fa-4x" contenteditable="false"></i>)` 3. Select all and click "Remove format". Result: -> Traceback due to an infinite loop. Cause: ====== Remove format calls `removeAllColor()`, which loops forever at: https://github.com/odoo/odoo/blob/626bde21a25366d0bb29662bae2057c247a1638e/addons/html_editor/static/src/main/font/color_plugin.js#L194-L194 Why: _applyColor doesn't remove the icon's background class, so hasAnySelectedNodeColor keeps returning true and the removal loop never terminates. This happens because `font` is already the `<i>` element with the `fa` class, using `querySelectorAll` on it won't include the element itself, so the icon is never checked or updated. https://github.com/odoo/odoo/blob/6cdc6f55886ea48e90f9023a6c6142bf072745b9/addons/html_editor/static/src/main/font/color_plugin.js#L290 Solution: ========= Check if the font itself has the fa class before doing the `querySelectorAll`, and include it in the nodes to check for color. Test Impact: ============ Before this fix, a `<span>` containing an icon was wrapped in a `<font>` when applying color, treating the icon as a normal span (without size) instead of applying the color directly. https://github.com/odoo/odoo/blob/8792c2d38eb0aadac8d778d83fd76f270404ecd5/addons/html_editor/static/src/main/font/color_plugin.js#L397 opw-5928627 Forward-Port-Of: odoo/odoo#261405 Forward-Port-Of: odoo/odoo#248449
This update corrects a reporting issue within the GSTR-3B report for Indian companies using the '18% IGST (IMP-Service)' tax. Previously, the report incorrectly excluded bills with this tax. The fix adjusts the tax distribution to ensure accurate reporting of IGST liabilities, resolving a discrepancy in import of services.
Original PR description
**Steps to reproduce:** - Install l10n_in_reports - Switch to an Indian company (e.g. IN Company) - Create a bill with a Service product and "18% IGST (IMP-Service)" tax - Confirm the bill - Go to "Accounting / Reporting / India / GSTR-3B" **Issue:** In "4. (A) (2) Import of services" section of the report, the bill that has been created is not taken into account. **Cause:** The "18% IGST (IMP-Service)" tax has a distribution of: * 100% of the tax in "100570" account with "IGST" tax tag * -100% of the tax in same account with "IGST" tax tag Therefore, both distribution lines with the tax tag cancel themselves. opw-6116356 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#260631
This update resolves an issue where multi-company invoice calculations were failing due to incorrect tax access permissions. The change ensures tax calculations are performed securely, regardless of the company context, preventing errors and improving invoice processing reliability.
Original PR description
Description of the issue this commit addresses: In multi-company setups, invoice line tax recomputation could read product or account taxes in user context and trigger an AccessError on account.tax when products carry taxes from another company. Desired behavior after this commit is merged: This patch hardens account.move.line tax recomputation paths by reading tax M2M values in sudo and returning filtered results in normal env, so compute logic no longer crashes on cross-company tax records. Ticket [link](https://www.odoo.com/odoo/project.task/6036638) opw-6036638 Forward-Port-Of: odoo/odoo#260948
This update fixes an issue where backorders created from returns weren't properly associated with the original return. Previously, the system didn't correctly set a link between the backorder and the return, leading to reporting discrepancies. This change ensures that backorders generated from returns are accurately tracked within the return process.
Original PR description
### Steps to reproduce: - Create, confirm and validate a delivery for 2 units of a product A - Click Return > Return All - Validate the return for 1 unit and backorder #### > The backorder does not belong to the return list of the delivery ### Cause of the issue: Backorder pickings are created by copying the picking to backorder: https://github.com/odoo/odoo/blob/9ad995ff6b59a6a2fdfbbd6cf385fe27568dd3ea/addons/stock/models/stock_picking.py#L1580-L1593 https://github.com/odoo/odoo/blob/9ad995ff6b59a6a2fdfbbd6cf385fe27568dd3ea/addons/stock/models/stock_picking.py#L1571-L1578 However, the `return_id` is a `copy=False` field that is not manully set during this copy process: https://github.com/odoo/odoo/blob/9ad995ff6b59a6a2fdfbbd6cf385fe27568dd3ea/addons/stock/models/stock_picking.py#L558 opw-6111544 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261831 Forward-Port-Of: odoo/odoo#259804
This update resolves an issue preventing the MPESA payment method from correctly processing transactions initiated by Safaricom. It disables CSRF checks on callback endpoints and ensures URLs use HTTPS, addressing a common error related to invalid URLs. Additionally, the code now incorporates a 'till number' for transactions, improving data accuracy.
Original PR description
1. The `MPESA` payment method needs a callback url where it does a `POST` request with the transaction details. Since the call comes from safaricom, CSRF will block those requests. This commit will…
1. The `MPESA` payment method needs a callback url where it does a `POST` request with the transaction details. Since the call comes from safaricom, CSRF will block those requests. This commit will disable CSRF checks on the callback endpoints which are expected to be called from an external service 2. Sometimes the `web.base.url` parameter is automatically set to http. But safaricom expects https for all the urls. So we need to ensure that the urls we send on `lipa_na_mpesa_register_urls` use https, otherwise the registration fails with an `invalid url` error. Additionally, I added the error message in case of error 4. In addition to the business short code we also need a till number for transactions. Since this is stable, I've added the till number as an extension of the business shortcode field and then parse it before usage. On master there is a new PR which will properly separate the fields Task-[6045833](https://www.odoo.com/odoo/project/1737/tasks/6045833) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#254993
This update resolves an issue where unreconciling bank statements with batch payments would unexpectedly revert invoices to draft due to approval checks triggered by third-party modules. The fix allows for the necessary repost to occur even when approvals are pending, preventing users from needing to manually re-enter data. This ensures smoother reconciliation processes.
Original PR description
When unreconciling a batch payment from a bank statement line, delete_reconciled_line() resets the linked invoice to draft to recompute its amount_residual, then re-posts it. If a third-party module…
When unreconciling a batch payment from a bank statement line, delete_reconciled_line() resets the linked invoice to draft to recompute its amount_residual, then re-posts it. If a third-party module (e.g. Studio Approvals) silently rejects action_post for the current user, the invoice stays in draft and the user has to redo the work manually. This internal repost is not a business action, the move was already approved when initially posted, so it can run as sudo to bypass approval checks. Steps to reproduce: 1. Add a Studio Approval rule on account.move.action_post with an approver other than the current user 2. As a user without that approval right, post a vendor bill and register a payment 3. Add the payment to a batch payment 4. Reconcile a bank statement line with the batch payment 5. With the user without approval rights, try to unreconcile the bank statement line (delete_reconciled_line) - Expected: the bill stays Posted. - Actual (before fix): the bill silently rolls back to Draft because action_post is rejected by the approval hook. opw-6121448 Forward-Port-Of: odoo/enterprise#115341 Forward-Port-Of: odoo/enterprise#115241
This update fixes a discrepancy in the sale details report by accurately reflecting cash rounding adjustments. Now, the report displays the total cash rounding applied during a session, aligning the displayed total with actual payment amounts. This ensures greater accuracy and transparency in sales reporting.
Original PR description
The sale details report total_paid was computed from sum(order.amount_total), which does not include the cash rounding adjustment. This caused a discrepancy between the displayed total and the sum of individual payment lines when cash rounding is enabled. Use the sum of actual payment amounts instead, which naturally includes cash rounding since payments are recorded with their rounded values. opw-5253018 Forward-Port-Of: odoo/odoo#261884 Forward-Port-Of: odoo/odoo#254401
This update fixes an issue where the Datev export CSV incorrectly reported tax rates when a vendor bill used multiple tax repartition lines. The fix ensures that all tax amounts are accurately included in the CSV, improving the reliability of financial data exports to Datev.
Original PR description
With l10n_de_reports: - Configure a foreign currency with an exchange rate. - Configure a tax with multiple repartition lines. - Create a vendor bill in this foreign currency with this tax. - In the general ledger export the datev csv. In the datev csv the rate is wrong. In the method _l10n_de_datev_get_csv, we build a tax_amount dict. However when one tax has multiple lines, the amount is replaced and not added. opw-6010097 Forward-Port-Of: odoo/enterprise#115535 Forward-Port-Of: odoo/enterprise#110453
This update resolves an issue preventing users from switching between company localization types (Companies vs. Associations & Foundations) for Belgian businesses. The fix clears references to old accounts within cash rounding settings, allowing the localization switch to complete without errors. This ensures accurate reporting and functionality for Belgian clients.
Original PR description
### Issue before this commit: Switching the fiscal localization of a Belgian company from "Companies" to "Associations and Foundations" caused a traceback during the chart reload process. The…
### Issue before this commit:
Switching the fiscal localization of a Belgian company from "Companies" to "Associations and Foundations" caused a traceback during the chart reload process. The operation failed because some accounts from the previous localization could not be deleted.
### Steps to reproduce the issue:
1. Download Accounting
2. Create a new Belgian company
3. Switch to that company
4. Go into Settings -> Fiscal Localization
5. Switch to Associations and Foundations
6. Traceback: The operation cannot be completed: Another model is using the record you are trying to delete. The troublemaker is: 'Account Cash Rounding' (account.cash.rounding). Thanks to the following constraint: 'Profit Account' (profit_account_id). How about archiving the record instead?
### Cause of the issue:
The Belgian localization creates a default cash rounding method ("Round to 0.05") linked to specific profit and loss accounts. When switching localization, it was tried to delete the old chart of accounts, but these accounts are still referenced by account.cash.rounding through profit_account_id and loss_account_id, which use ondelete='restrict'. This prevents account deletion and blocks the localization change. Commit that caused the issue: https://github.com/odoo/odoo/commit/412fc9bed36645dd950c9a60d9b6ffdd9b4bce67
### Reason to introduce the fix:
Before reloading the Belgian chart template, the fix clears the profit_account_id and loss_account_id on the existing cash rounding records. This removes the blocking references, allows the old accounts to be deleted safely, and lets the fiscal localization switch complete successfully without affecting existing cash rounding configurations.
opw-6050537
Forward-Port-Of: odoo/odoo#260145This update resolves a bug where editing previously edited messages caused unexpected behavior like selecting the "(edited)" label and losing content after saving. The fix removes the "(edited)" span from the editor's content, ensuring correct editing functionality and a smoother user experience.
Original PR description
When editing an already-edited message, the `(edited)` span was included in the editor's editable content because `prepareBodyForEditing` (formerly `getNonEditableMentions`) passed the raw body…
When editing an already-edited message, the `(edited)` span was included in the editor's editable content because `prepareBodyForEditing` (formerly `getNonEditableMentions`) passed the raw body directly to the composer. This caused two issues: - CTRL+A would select the `(edited)` label, allowing it to be styled, repositioned, or accidentally deleted. - CTRL+A + Backspace + retype left the body empty after saving, because the self-closing `<span class="o-mail-Message-edited"/>` in the stored HTML was parsed by browsers as an open tag (spans are not void elements), swallowing subsequent content as its children. Fix: strip `.o-mail-Message-edited` from the body before loading it into the editor. The server always re-appends a fresh `(edited)` span at the end when saving, so removing it from the editor content is safe and correct. Also align the mock server with the real server behavior: - Place the span *inside* the last `div`/`p` element instead of after it. Rename `getNonEditableMentions` → `prepareBodyForEditing` to reflect that the function now covers both making mentions non-editable and stripping the edited label. task-6172161 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes an issue where combo products weren't consistently ordered according to their choices, leading to incorrect item sequences in sales orders. The fix ensures combo items are always displayed in the intended order defined by the combo selection, improving the accuracy and reliability of the point-of-sale system.
Original PR description
When creating a combo product, its items were not ordered according to the combo choice sequence, and extra items were always appended at the end. As a result, combo items could appear in the wrong order. This fix ensures that, when computing combo prices and merging combo items with extra items before creating the order lines, the correct sequence is derived from the parent product. All items are then sorted based on this sequence so that they consistently follow the order defined by the combo choices. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6064642 Forward-Port-Of: odoo/odoo#261633 Forward-Port-Of: odoo/odoo#255596
This update resolves a performance issue where changing a product's lot/serial in a stock picking could trigger slow requests due to Odoo fetching all stock quantities without respecting a defined limit. The fix ensures that the system respects the limit during these onchange calls, resulting in significantly faster response times.
Original PR description
## Problem: During an `onchange` call, if a field is defined in the `fields_spec` with a `limit` attribute, the `fetch` method doesn't respect it, and will fetch all records satisfying the domain. In…
## Problem: During an `onchange` call, if a field is defined in the `fields_spec` with a `limit` attribute, the `fetch` method doesn't respect it, and will fetch all records satisfying the domain. In certain circumstances, this leads to slow requests. ## Solution: Enforce the `limit` when fetching if it is present. ## Steps to reproduce: - Have a product with many quant records 1. Open a picking for this product in Barcode 2. Change the lot/serial The frontend will send an `onchange` request that includes `product_stock_quant_ids` in the `fields_spec` (with default `limit` 40). Odoo will fetch all quants for this product regardless of the limit, and the request will take a while to resolve. ## Benchmark: <table> <thead> <tr> <th># of quants</th> <th>Before</th> <th>After</th> </tr> </thead> <tbody> <tr> <td>17193</td> <td>~9s</td> <td>~400ms</td> </tr> </tbody> </table> opw-6041705 Forward-Port-Of: odoo/odoo#261904 Forward-Port-Of: odoo/odoo#259983
This update resolves an issue where printers connected as IoT devices weren't correctly loaded within the Point of Sale system. Previously, these printers were unusable. This change ensures all printers, regardless of their IoT connection, are properly integrated into the PoS workflow.
Original PR description
preparation printers were not loaded in PoS as IoT devices making them unusable. Forward-Port-Of: odoo/enterprise#115768