Thursday, August 6, 2026
14 changes · saas-19.4
Enhancements to existing features
Bank connection synchronization now recognizes warnings that should not stop the connection from working. This helps avoid unnecessary error states for users when the issue does not require blocking the online banking link.
Original PR description
Odoofin now sends a 'non_blocking_error' error response to indicate that the state on account.online.link shouldn't be set to error. In this commit, we start using it. Task ID: 6358809 Forward-Port-Of: odoo/enterprise#126737 Forward-Port-Of: odoo/enterprise#123287
Resolved issues and error corrections
Replacing a document in the Sign app now keeps multiple signature fields correctly linked to the same signer. This prevents duplicate signer entries and helps users avoid confusion or incorrect signing assignments after updating a document.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields,…
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields, causing Odoo to erroneously generate separate signers for each individual field. ### Current behavior before PR: When a document with multiple signature fields assigned to the same person is replaced, the _copy_sign_items_to function duplicates the sign.item records. During this duplication process, Odoo duplicates the old responsible_ids, creating copies with new ids. These new copies overwrite the old responsible_ids, ensuring that the newly created sign_items have entirely new responsible_ids. Because a shared responsible_id is the primary key Odoo uses to group multiple signature items under a single signer, this change in ID causes the system to lose the grouping. As a result, Odoo treats each copied field as belonging to a completely new, separate signer. _Note_: Because of the limitation mentioned before, any responsible_id that is passed through the copy function, and thereby the copy_data function, is overwritten with new ids. The only work-around then is to update the responsible_id value attached to the new_sign_item after the copy_data function has completed and the new_sign_item has been created. ### Desired behavior after PR is merged: The original responsible_id is explicitly carried over and assigned to the newly copied sign.item immediately after the copy operation completes. This ensures the copied signature fields retain their original role IDs and grouping, keeping them correctly assigned to the single original signer. opw-6354334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#123628
Peruvian electronic invoices now calculate down payment amounts consistently when withholding taxes are involved. This prevents mismatches in submitted XML totals and avoids referencing cancelled down payment invoices, reducing validation issues for affected invoices.
Original PR description
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with…
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with `LegalMonetaryTotal/PrepaidAmount` which correctly excludes it ### Cause: `PrepaidPayment/PaidAmount` was set directly from `prepayment_move.amount_total`, which includes all taxes `LegalMonetaryTotal/PrepaidAmount` uses `_aggregate_base_line_tax_details` to exclude withholding taxes, but this was not applied to the `PrepaidPayment` node ### Fix: Using `prepayment_move.amount_total` directly includes all taxes and does not match the rounding logic of `LegalMonetaryTotal` Instead, `_aggregate_base_line_tax_details` is used with the same `total_grouping_function` as `LegalMonetaryTotal`, ensuring both nodes use the same rounding logic and exclude withholding taxes Reversed down payment moves are also excluded from `AdditionalDocumentReference` to avoid referencing cancelled invoices ### Steps to reproduce: - Install `l10n_pe_edi` and `sale_management` with demo data - Switch to the PE company - Create and confirm a Sale Order (Customer: PE Company, Product: Any, Unit Price: 200, Taxes: VAT 18% and 3% IGV Withholding) - Create, confirm and pay a Down Payment Invoice (Fixed: 28.92) - Go back to the SO and create the Regular Invoice - Confirm it and click Process Now - Open the EDI Document tab and download the XML Before the fix, the sum of `PrepaidPayment/PaidAmount` did not match `LegalMonetaryTotal/PrepaidAmount` opw-6273903 Forward-Port-Of: odoo/enterprise#126776 Forward-Port-Of: odoo/enterprise#121733
This fix prevents users from accidentally expanding the same financial report line multiple times when clicking quickly or using a slow connection. Reports now fold and unfold reliably, avoiding confusing duplicate entries and improving day-to-day report navigation.
Original PR description
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not…
Steps to reproduce:- - Open any report. - Click on a particular line to unfold more than once very fast(or throttle network to 3G) - Once line is unfolded click again to fold that line. - Line is not folding. Cause:- - When we clicked multiple times to unfold line, duplicate child lines were created(as many times as many times we clicked). - Because when first promise was not resolved so `unfolded = false` and we clicked again so new promise also tries to unfold the same line, resulting in unfolding the same line multiple times. - In version 17.0 these duplicate child lines are created but somehow not visible but it breaks `foldLine`. From version 18.0 onwards these duplicate child lines are visible. Solution: In `unfoldLine` set the flag `unfolding`. So in all clicks other than first, we get `unfolding = true` and don't proceed further, preventing unfolding the same line multiple times. task-6260425 Forward-Port-Of: odoo/enterprise#126765 Forward-Port-Of: odoo/enterprise#120392
The Vietnamese financial reports now classify short-term held-to-maturity loan balances under the correct balance sheet category required by Circular 99/2025. This helps businesses produce compliant balance sheets without manual adjustments.
Original PR description
### Expected behavior: As per circular 99/2025, short-term loan (12831) balance is required to fall under Held to Maturity Investment (Code 123) instead of 112, translated: ``` Short-term held-to-maturity investments (Code 123): includes held-to-maturity investments with a remaining term of 12 months or less from the end of the accounting period, such as term deposits, bonds, commercial paper, loans, and other debt securities. This item does not include held-to-maturity investments that have been presented in the item “Cash equivalents” ``` ### Steps to reproduce: Install `l10n_vn_reports` module ### Fix: PO validated: Update the Balance Sheet code formula for the 12381 account opw-6413120 Forward-Port-Of: odoo/enterprise#126763
Appointment bookings now open correctly when the appointment type name contains non-ASCII characters, such as Arabic text. This prevents customers from getting stuck in repeated redirects and ensures they can complete the booking form.
Original PR description
Clicking a slot on an appointment type with a non-ASCII name (for example an Arabic title) puts the browser in an endless 301 loop, so the info form never opens. ### Steps to reproduce - Create an…
Clicking a slot on an appointment type with a non-ASCII name (for example an Arabic title) puts the browser in an endless 301 loop, so the info form never opens. ### Steps to reproduce - Create an appointment type with an Arabic name, e.g. `عنوان`. - Open its page and pick a time slot. - The browser keeps redirecting on `/appointment/<slug>/info` and fails with "too many redirections". ### Cause The info URL is built from the slug `<name>-<id>`, here `عنوان-1`. We build a `URL` with `encodeURIComponent(slug)`, so `url.href` is already encoded once (`عنوان` becomes `%D8%B9...`). But we then navigate with `encodeURI(url.href)`, and `encodeURI` escapes the `%` signs a second time, so `%D8%B9...` becomes `%25D8%25B9...`. The slug is now encoded twice. To canonicalize the URL, the server decodes the request path and the path it rebuilds from the route, once each, and redirects if they differ. For a normal URL they are equal. For ours they are not, because one side is decoded one step less than the other, so the server keeps answering 301 with the same double-encoded URL. An ASCII slug has no `%` for `encodeURI` to escape, so only non-ASCII names hit this. ### Fix Navigate to `url.href` directly. It is already encoded, so the extra `encodeURI` only broke it. Same fix on the manual resource confirmation path. opw-6409641 Forward-Port-Of: odoo/enterprise#125497
This fix ensures Tyro payment surcharge fees are reliably added to point-of-sale orders before the order is validated. It prevents occasional missing surcharge lines caused by timing issues during payment completion, improving billing accuracy for merchants using Tyro.
Original PR description
Currently when completing a Tyro payment with a surcharge fee in some cases there is a race condition preventing the surcharge line to be added to the pos order before its validation This PR fixes that issue opw-6402191 Forward-Port-Of: odoo/enterprise#126035 Forward-Port-Of: odoo/enterprise#125852
Automatic bank reconciliation rules now use simpler text matching and also consider whether transaction amounts are incoming or outgoing. This helps show and apply the right reconciliation suggestions for each journal, reducing incorrect matches and manual cleanup.
Original PR description
Reconcile models automatically created now use contains instead of match regex and take the amount into consideration when creating the rule as well as checking for existing rules, it's checked whether all of the lines are positive or negative. Added an extra filter on the reconcile models so that it only shows rules that would be applied on the journal, and did some optimizations in the substring matching. task-6140372 Forward-Port-Of: odoo/enterprise#126187 Forward-Port-Of: odoo/enterprise#117256
Fixes an issue where online rental orders using click & collect could incorrectly show no availability because reservations from other warehouses were counted. Availability is now checked only against the selected pickup warehouse, helping customers complete valid rental orders and reducing checkout errors.
Original PR description
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2…
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2 different adresses * Create a product available for renting * Setup the product to use serial numbers * Create 2 serial number, 1 in each warehouse * Activate the click & collect option on the website * Create a first sale order to collect in warehouse 1 * In the backend, confirm the order and pick it up * Go back to the website and make a second order for the second warehouse > Observation: When clicking on the "Add to cart" you get an error saying that there is no quantity available Why the fix: ------------ When computing the `product_rented_quantities` it would look for `sale.order.line` in all the warehouse. So it would find the line from the first order even if it's not linked to the selected warehouse. So we just add a new element to the domain to filter out the incorrect warehouses. opw-6328475 Forward-Port-Of: odoo/enterprise#126817 Forward-Port-Of: odoo/enterprise#124969
User-facing messages and warnings now show translated labels for selection fields instead of untranslated internal values. This improves clarity for users working in different languages across accounting, payroll, recruitment, IoT, localization, appointments, documents, and reporting features.
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Forward-Port-Of: odoo/enterprise#126741 Forward-Port-Of: odoo/enterprise#126538
Shop floor users can now finish the final work order in continuous production after entering a produced quantity. The update also ensures produced quantities display correctly when assigning serial numbers, reducing confusion and blocked manufacturing flows.
Original PR description
Previously there was a limitation for continuous production in shopfloor, that blocked the user from marking a workorder as done after registering a quantity. This commit fixes it by assigning the production's `quantity_producing` to the work order's `qty_produced` if it is the final work order. This unblocks the user and allows them to complete the work order.
Belgian CodaBox users can now revoke their connection using either the fiduciary password or a valid IAP token. This fixes a client-side gap so the existing server-side token option works as intended, making disconnection easier when the password is not used.
Original PR description
The user should be able to revoke the CodaBox connection by either entering the fidu password or by using a valid iap_token. This was implemented in the iap server but not in the client side, after this commit the user should be able to either revoke by using the fidu password or by using the iap_token. task-6348433 Forward-Port-Of: odoo/enterprise#126698
This fix prevents Approval records from trying to send notifications while temporary form data is being recalculated. Users working with Studio-created fields linked to Approval Requests can now update forms without crashes, including when requests are approved or refused.
Original PR description
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given…
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given that we'll be working with a virtual "snapshot" record to recompute potentially changed values for our origin record after a change to one or more values. This issue manifests when using Studio to attach a many2many field to a form view, where the related model is "Approval Request". If an approval request record in either the "Approved" or "Refused" state is attached to our record via this new Studio field, any `onchange` requests will trigger this bug. This is because we can't send messages on a virtual record. **After this change** Prevent the creation and sending of a message if we are computing the request status of a virtual `approval.request()` record. The field `request_status` on this model is computed and stored, but the fact that it is a computed field means that it must be recomputed for a virtual record, even if the origin record already has a stored `request_status`. Thus, we may need to compute a `request_status` value for an ephemeral "snapshot" record. Though the issue only manifests for the "Approved" and "Refused" states, this PR expands on a test that covers every approval request state. opw-6390453 Forward-Port-Of: odoo/enterprise#125374
Customer balances shown in Point of Sale are now calculated consistently when the company and PoS use different currencies. This prevents pay-later orders from being converted twice, so staff see the correct amount owed by the customer.
Original PR description
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any…
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any outstanding balance - open the PoS, create an order of USD 100 and validate it with the Customer Account (Pay Later) payment method - open the Customers screen and look at the Total Due of that customer Issue: The Total Due shows about USD 55.56, i.e. the amount converted once too many, instead of the expected USD 100. Cause: get_total_due() sums two amounts that are not expressed in the same currency before converting them. partner.total_due comes from the accounting entries, it is the sum of account.move.line.amount_residual and is therefore in company currency, while total_settled is the sum of pos.payment.amount of the still open sessions, which is in the currency of the order, so the PoS one. The addition is done first and the result is then converted from the company currency to the PoS one, so the pay later payments end up converted a second time. opw-6403320 Forward-Port-Of: odoo/enterprise#126402 Forward-Port-Of: odoo/enterprise#125798