Daily updates from Odoo
Friday, April 17, 2026
22 changes · saas-18.3
Enhancements to existing features
This update replaces the unreliable VIES check with a more robust system using the IAP server. This improves the accuracy of EU VAT ID validation, particularly for French partners, and reduces potential errors during Tax ID changes.
Original PR description
Currently, when changing the Tax ID of a partner that is another EU country, we perform a VIES check to know whether it is valid (i.e. can do intra-com). However, it is often the case that the VIES check fails because of an internal error on their side (timeout, max concurrent update, ...), especially for France. Instead, we will now use the IAP server which stores the validity of a Tax ID for some time. If the IAP server does not have the info (because VIES is down), we will not actively wait. Instead, IAP will perform a push to a webhook on the client database once it has the information. For security purposes, an HMAC is generated and sent to IAP so that only IAP can contact the db with the up-to-date info, and not anyone on the internet that calls this new webhook. There is also a cron for polling for OnPrem instances that cannot be contacted via the webhook. task-5977584 Forward-Port-Of: odoo/odoo#259565 Forward-Port-Of: odoo/odoo#258155
Resolved issues and error corrections
This update fixes an issue where numbers in the domain selector and expression editor were not displayed correctly based on the user's locale settings. Now, numbers are formatted according to the user's local preferences, ensuring a consistent and accurate experience across different regions. This improves usability and data clarity.
Original PR description
Before this commit, the domain selector (and expression editor) did not format numbers according to the localization parameters (decimal and thousands separators), while the parsing step did. After this commit, the value is displayed in the correct format to the user, while the expression remains unchanged. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#258287
This update fixes an issue where Mercado Pago webhooks with invoice references containing slashes (like INV/2026/00001) were not being correctly processed, resulting in a 404 error. The change allows the webhook to handle these references, ensuring accurate processing of Mercado Pago payments. This improves the reliability of payment processing.
Original PR description
Currently, the mercado_pago_webhook http route only takes into consideration 1 url segment. This means that invoices with references like INV/2026/00001 don't match any defined route and the server returns a 404. /payment/mercado_pago/webhook/S00001 => OK /payment/mercado_pago/webhook/INV/2026/00001 => KO This commit allows references with slashes to be matched by the route by capturing the entire remaining url path including the slashes. /payment/mercado_pago/webhook/S00001 => OK /payment/mercado_pago/webhook/INV/2026/00001 => OK opw-6035161 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#259378
This update resolves an issue where the Point of Sale app on iOS/Safari would unexpectedly crash due to a lost connection to its local database. The fix prevents crashes when the app goes to the background or when the operating system temporarily closes the database connection. This ensures a more reliable and stable Point of Sale experience for our iOS users.
Original PR description
On iOS/Safari, the WebKit IDB server process can be killed by the OS (e.g. due to memory pressure when the app is backgrounded), resulting in an UnknownError: "Connection to Indexed Database server lost". Additionally, returning from background can leave the connection in an InvalidStateError "closing" state while this.db remains non-null. opw-5121896 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#256401 Forward-Port-Of: odoo/odoo#253943
This update fixes an issue with invoice rounding related to down payments. The system now correctly uses specific currency fields to ensure the total invoice amount, including taxes, matches the expected value. This improves accuracy when processing invoices with down payments, preventing potential discrepancies.
Original PR description
'total_excluded_currency' is for the base amount. 'base_amount_currency' should be used only when getting the base per tax. When dealing with a down payment, a distortion in the taxes amounts might be introduced to ensure the total of the invoice is exactly the expected one. opw-6060486 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
A recent issue prevented activity states from being consistently shared across different tabs within Odoo. This PR corrects a technical typo that was causing this problem, ensuring that activity updates are now properly synchronized across all tabs. This improves the user experience by guaranteeing consistent visibility of activity updates.
Original PR description
Since [1], the activity state, which is supposed to be shared accross tab through a broadcast channel, isn't anymore. This PR fixes the responsible typo. [1]: #161286 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#258644 Forward-Port-Of: odoo/odoo#255785
This update fixes a test failure in the HTML Editor module caused by relying on a fixed animation frame wait. The change now monitors elapsed time, making the test more reliable across different system speeds. This ensures consistent test results and reduces the risk of false failures.
Original PR description
Waiting for a full animation frame is too dangerous. In the general case, an animation frame happens every 16ms, in which case the power buttons haven't been updated yet since they have a debouncing timeout of 30ms. However, when the runbot is slow, more than 30ms may very well have elapsed between two animation frames. When that is the case, the power buttons are displayed and the test fails. This commit changes the forced awaiting of an animation frame to a waiting pased on the time passed. In the general case, an animation frame will have happened in 20ms, so the test will still catch a regression. When the runbot is slow however, more time might have passed, but not necessarily an animation frame, so the power buttons should still be invisible, making this test more reliable. runbot-242466
This update corrects a rounding issue in the Peppol invoice XML generation, preventing validation errors related to line amount calculations. The fix ensures accurate invoice formatting for Peppol compliance, avoiding potential delays in electronic invoice processing. This improves the reliability of our Peppol integration.
Original PR description
**PROBLEM** Previously, we rounded the unit price up to 6 digits in the generated xml for peppol. However, odoo compute the lineExtensionAmount with the raw unit price. The generated xml is invalid because `priceAmount*InvoicedQuantity != LineExtensionAmount`. **STEP TO REPRODUCE** 1. Create an invoice with unit price of 0.01110515964, and quantity of 278362.5. 2. Generate an XML with peppol, and try validating the invoice. You should have the following error: `[PEPPOL-EN16931-R120]-Invoice line net amount MUST equal (Invoiced quantity * (Item net price/item price base quantity) + Sum of invoice line charge amount - sum of invoice line allowance amount` opw-6009771 Forward-Port-Of: odoo/odoo#255358
This update ensures that dynamic reports attached to invoices in email templates use the correctly configured 'Printed Report Name' instead of a default naming pattern. Previously, invoices used a different email flow that didn't properly apply these names. This fix guarantees consistent and accurate report filenames in email attachments.
Original PR description
When sending an invoice by email template, dynamic report attachments do not use their configured Printed Report Name. Instead, they fall back to a default naming pattern (e.g. report name + invoice…
When sending an invoice by email template, dynamic report attachments do not use their configured Printed Report Name. Instead, they fall back to a default naming pattern (e.g. report name + invoice number). This is due to a difference in flow: sales use the standard mail.compose.message wizard, which correctly applies each report’s print_report_name, while invoices use the dedicated account.move.send flow. In this flow, dynamic report filenames are not computed from the report itself. To fix this, the send flow is updated so _get_placeholder_mail_template_dynamic_attachments_data computes the filename from each dynamic report. When a print_report_name is defined, it is used. Otherwise, the previous fallback behavior is preserved. The fix will ensure extra dynamic reports follow their configured printed name. Steps to reproduce: 1. Go to Settings > Technical > Reporting > Reports and duplicate the standard Invoice report. 2. In the duplicated report, set a custom value in Printed Report Name (e.g. 'CUSTOM_NAME_TEST'). 3. Go to Settings > Technical > Email > Templates and open “Invoice: Sending”. 4. Add the duplicated report under Dynamic Reports. 5. Create a customer invoice and confirm it. 3. Click Send (or Send & Print) to open the email preview. Related Ticket: opw-6058716 Forward-Port-Of: odoo/odoo#259597 Forward-Port-Of: odoo/odoo#259267
This update resolves an issue where invoices weren't automatically marked as paid when using a specific payment setup (default bank account as outstanding account). This prevented invoices from correctly reflecting completed subscription payments. The fix ensures invoices are properly reconciled, streamlining the billing process.
Original PR description
Currently, when a subscription payment is processed through a provider configured to use as outstanding account the bank default account, the resulting invoice may remain in an 'open' state even…
Currently, when a subscription payment is processed through a provider configured to use as outstanding account the bank default account, the resulting invoice may remain in an 'open' state even though the payment transaction is 'done'. This type of configuration is usually done when users want to skip the bank reconciliation process, and just create payments without the need to reconcile the payments with transactions. Steps to reproduce: - In Settings, under Sales > Invoicing, disable Automatic Invoice - Activate demo payment method - In the main Bank account add the default account as outstanding account for demo payment method. - Create a sales order with a subscription product - Open Preview - Pay - Go back to the sales order and open the created invoice Issue: The invoice is created and the payment is registered, but the invoice remains 'Not Paid'. Analysis: The invoice and the payment move lines are not automatically reconciled during the post-processing of the transaction, leaving the invoice unbalanced. opw-5869303
This update resolves an access error that prevented users in branch companies from correctly calculating TDS entries on vendor bills. The fix ensures the system uses the correct company ID for currency calculations, addressing a discrepancy between branch and parent company access rights.
Original PR description
**Steps to reproduce:** * Install the **l10n_in** module. * Create a **branch company** under an Indian company. * Switch to the branch company only. * Create a user with **Accounting Administrator**…
**Steps to reproduce:** * Install the **l10n_in** module. * Create a **branch company** under an Indian company. * Switch to the branch company only. * Create a user with **Accounting Administrator** access (and bank validation rights) and also give permission of this branch company. * Login from this user . * Create and confirm a vendor bill in the branch company. * Click **TDS Entry** and select any TDS section. **Observed behavior:** * An **AccessError** is raised when selecting the TDS section. **Cause:** * In `_compute_amount` (wizard), currency is taken from `tax_id.company_id`. * For branch setups, taxes (and related accounts) belong to the **parent company**, so `tax_id.company_id` points to the parent. * The user operating in the branch company does not have access to the parent company, triggering an access error. **Fix:** * Use the wizard’s `company_id` instead of `tax_id.company_id` when determining currency. * The wizard `company_id` is correctly computed based on the active company, ensuring proper access rights. **Note:** * Regression test is not feasible due to ORM cache behavior: * In tests, `mock` environments share a transaction-level cache. * `compute_sudo=True` fields populate cache with superuser access. * By the time `_compute_amount` runs, values are already cached. * No database fetch occurs, so record rules are not evaluated and the AccessError cannot be reproduced. opw-6095312 Forward-Port-Of: odoo/odoo#259091
This update resolves an error that prevented users from saving appointments when removing the organizer (user) and setting a Google Meet link. The fix prevents a 'singleton' error that occurred when a method expected a single user record, now it gracefully handles appointments without a designated organizer.
Original PR description
Currently an error is generated when the user tries to save an appointment as follows: - Install the appointment_google_calendar module without demo data - Create a new appointment as below: - Remove…
Currently an error is generated when the user tries to save an
appointment as follows:
- Install the appointment_google_calendar module without demo data
- Create a new appointment as below:
- Remove Organizer (user_id)
- Set the Google Meet link inside VideocallURL, e.g., https://meet.google.com/aaa-aaa-aaa
- An error occurs in the log and a message is shown to the user when save the record
- Also, an error occurs when trying to preview `Appointment: Attendee Invitation`
after creating appointment as follows:
- Set the Google Meet link inside Videocall URL > save
- Remove Organizer (user_id)
Error:
```
test odoo.addons.mail.models.mail_render_mixin: Failed to render QWeb template for Mail Template: 'Appointment: Appointment Booked' (ID: 12) - Context language:en_US
Target Model: calendar.event
Error: Error while render the template
ValueError: Expected singleton: res.users()
```
This is because the method `is_google_calendar_synced` expected a single
record, but since we removed `user_id` from the event (appointment),
it will generate a singleton error.
This commit will fix the above issue by not calling `is_google_calendar_synced`
when the event does not have `user_id`.
sentry-7393595716
Forward-Port-Of: odoo/enterprise#113966This update corrects a technical error in the Danish accounting module (l10n_dk) that prevented accounts without a standard code from being correctly processed. The fix ensures all accounts, regardless of their code, are now handled accurately within the system. This improves data accuracy and functionality for Danish businesses using Odoo.
Original PR description
From https://github.com/odoo/odoo/pull/256541.
```yml
File "/home/.../odoo/addons/l10n_dk/migrations/1.4/end-migrate.py", line 102, in migrate
if len(account.code) < 6:
TypeError: object of type 'bool' has no len()
```
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#258399
Forward-Port-Of: odoo/odoo#258299This update fixes a limitation in Odoo Studio where activity filters (past, today, future) weren't consistently working when the 'use_mail' Chatter feature was enabled. The team added necessary filters to the search view, ensuring users can effectively filter activities based on their timeliness within Studio. This enhances Studio's usability for managing and tracking activities related to records.
Original PR description
Steps to reproduce
==================
- Install studio
- Create a new app
- Create a new model
- Keep the Chatter toggled (use_mail)
- Exit studio
- Create three records, one with an activity in the past, one today and one in the future
- Click on the clock status icon in the top right
- There should be a section with the new model
- Click on 1 Late => every records is displayed
- Same for Today and Future
Cause of the issue
==================
https://github.com/odoo/odoo/blob/b6434b91a7f94075e1372ec827787504ef7aa4f0/addons/mail/static/src/core/web/activity_menu.js#L39-L77
For this feature to work, the activities_{overdue,today,upcoming_all} filter should be present
Solution
========
We add them to the search view. They are all pretty much implemented the same way in every model.
opw-6069150
Forward-Port-Of: odoo/enterprise#113011This update corrects a discrepancy in how purchase order move lines handle sub-location destinations. Previously, even with a sub-location configured, move lines defaulted to the main warehouse, preventing accurate forecasted quantity updates. This change prioritizes the sub-location, ensuring that quantities are correctly tracked for specific receiving areas.
Original PR description
### **Description of the issue/feature this PR addresses:** **Issue:** In Odoo 18/19, purchase move lines default to the WH's main stock location (`lot_stock_id`) as the `location_final_id`. However,…
### **Description of the issue/feature this PR addresses:** **Issue:** In Odoo 18/19, purchase move lines default to the WH's main stock location (`lot_stock_id`) as the `location_final_id`. However, when a user configures a sub-location on the Receipt Operation Type, the picking destination is correct, but the move lines are defaulted to the main warehouse. This mismatch causes the Forecasted Quantity to not increment for the intended sub-location **Solution:** Prioritize the `default_location_dest_id` before falling back to the default stock location opw-6032018 ### **Current behavior before PR:** When confirming a PO, the `location_final_id` on stock moves defaults to the `lot_stock_id`, regardless of the specific destination set on the Operation Type. This causes a mismatch in 1-step receiving flows where a sub-location (e.g., WH/Stock/Test) is intended, since the move lines revert to the root warehouse location (WH/Stock). Thus, the forecasted quantity for the specific sub-location doesn't increment as expected. ### **Desired behavior after PR is merged:** The `_get_final_location_record` method will now evaluate if the Operation Type's `default_location_dest_id` is a child of the warehouse's main stock. If it is, the sub-location is used as the `location_final_id` for the moves and move lines. This ensures that the forecasted quantity reflects the intended destination upon PO confirmation while still maintaining the fallback to the warehouse root for standard multi-step routes. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#256725 Forward-Port-Of: odoo/odoo#254527
This update fixes an issue where the Italian tax module was incorrectly removing parts of VAT numbers when generating invoices for Spain. The fix ensures that VAT numbers, like A95758389, are accurately exported to the tax agency's XML files, preventing data discrepancies. This ensures compliance with Italian tax regulations.
Original PR description
**Steps to reproduce:** * Install `l10n_it_edi` module. * Create a partner with country **Spain** and VAT `A95758389`. * Create an invoice and send it to the Tax Agency, and download XML. **Observed behavior:** * The exported XML contains `5758389` in <IdCodice> instead of `A95758389` — the first two characters of the VAT are silently dropped. **Cause:** * In `_l10n_it_edi_get_values`, the EU branch that strips the country-code prefix used a bare `else` after the `isdecimal()` check, unconditionally removing the first two characters of any VAT that does not start with two digits. Spanish NIFs like `A95758389` start with `A9` (letter + digit), which is not a country-code prefix but was treated as one, corrupting the value. **Fix:** * Remove country prefix from normalized VAT by `removeprefix(normalized_country)` Instead of removing the first two characters. It will ensure that only the country prefix will be removed. opw-6089198 Forward-Port-Of: odoo/odoo#258626
This update resolves issues causing crashes when deleting sign templates and breaks in the tracking of document signatures. The fix ensures documents remain stable during template creation and deletion, and accurately maintains the link between signature requests and their original documents, regardless of the number of templates created.
Original PR description
Steps to reproduce: Bug 1 (The Crash): 1. Open Documents app, select a PDF, and click Action > Sign. 2. In the Sign app, delete the newly created Sign Template. 3. Return to the Documents app. 4. A…
Steps to reproduce:
Bug 1 (The Crash):
1. Open Documents app, select a PDF, and click Action > Sign.
2. In the Sign app, delete the newly created Sign Template.
3. Return to the Documents app.
4. A traceback occurs (`KeyError: <document_id>`) in `web_read`.
Bug 2 (The Broken Lineage):
1. Create two separate Sign Templates from the exact same Document.
2. Send a signature request from the second template.
3. The `reference_doc` on the signature request fails to link back to the original Document.
Current behavior:
When creating a sign template from a document, `documents_sign` intentionally unlinks the original `ir.attachment` (`res_model = False`) to pass custody to `sign.document`. If the template is deleted, the attachment is orphaned, permanently corrupting the original `documents.document` and crashing the UI.
Furthermore, the lineage tracking (`reference_doc`) relies strictly on a 1:1 shared `attachment_id`. If a user creates multiple templates from one document, the system is forced to make a copy for the second template, natively breaking the lineage tracking because the IDs no longer match.
Expected behavior:
Documents should not be corrupted when generating or deleting sign templates. Furthermore, lineage tracking (`reference_doc`) should successfully link back to the original document regardless of how many templates have been generated from it.
Fix:
1. Replaced the `res_model = False` custody-handoff hack in `documents_sign` with a safe `.copy({'original_id': attachment.id})`. This sandboxes the Sign app's files, completely preventing the deletion crash and the multi-template conflicts.
2. Updated the `reference_doc` computation in `sign.request` to dynamically search for both the current `attachment_id` AND its `original_id` (utilizing a minimal-diff recordset union `|`). This perfectly preserves the lineage tracking for all templates without requiring database schema changes.
Task: 5432116This update fixes an error in the manufacturing report that incorrectly converted quantities between different units of measure (e.g., Kg and Ton). The fix ensures accurate calculations for produced quantities and average unit costs, resolving discrepancies in reporting. This improves the reliability of production cost analysis.
Original PR description
Steps to reproduce:
- Create a product W1 with UoM = Kg with the following BoM:
- Component C1: 1 unit, cost = $1
- Create and confirm MO1:
- Produce 1 Kg of W1 → total cost = $1
- Create and confirm MO2:
- Produce 1 Ton of W1 → total cost = $1000
- Open the Manufacturing Report and group results
Problem:
- qty_produced ≈ 1.001 instead of 1001
- unit_cost average ≈ 1000 instead of 1
Expected behavior:
- qty_produced = 1001
- unit_cost average = 1 (consistent across MOs)
The manufacturing report (`mrp.report`) incorrectly converts quantities from move UoM to product UoM, leading to wrong `qty_produced` and `qty_demanded` values when different units of measure are used
The current implementation uses:
sm.quantity / uom.factor * uom_prod.factor
This inverts the conversion ratio. As a result:
- 1 Ton is converted to 0.001 Kg instead of 1000 Kg
opw-6097098This update ensures that survey invitations are sent in the recipient's preferred language, regardless of whether they speak multiple languages. Previously, invitations were consistently sent in English, even for recipients who preferred other languages. This change improves the user experience and avoids confusion.
Original PR description
When sending survey invitations to a group of recipients with different language preferences, some recipients would receive the invitation in the incorrect language. ### Steps to reproduce 1. Install…
When sending survey invitations to a group of recipients with different language preferences, some recipients would receive the invitation in the incorrect language. ### Steps to reproduce 1. Install the "Surveys" module and activate a second language (e.g., Dutch). 2. Create a survey and ensure its invitation template has translations for both languages. 3. Create two contacts: one with English as their language and another with Dutch. 4. On the survey, click "Share" and add both contacts as recipients. 5. Send the invitations. 6. The contact with Dutch preferred language receives the email in English. ### Cause By default, the wizard uses a single language for every email in a batch. While it can switch this language if everyone in the group speaks the same tongue, it fails to do so for mixed-language groups. Adding compute_lang=True fixes this by telling the system to look up and use the correct language for each recipient one by one. opw-5868581 Forward-Port-Of: odoo/odoo#246778
This update addresses a persistent issue with a test related to the HTML editor's icon functionality. The developer implemented a change to the test code, specifically using `setContent` to set the selection, in an attempt to resolve the problem. This ensures the icon tests are now consistently reliable.
Original PR description
My last desperate fix attempt did not fix the issue so here is yet another desperate fix attempt. I have seen issues related to the use of `setContent` just to set the selection in the past so I hope it might be that. It's the only noticeable change between this test and the others, be it icon tests or color selector ones. runbot-242333 Forward-Port-Of: odoo/odoo#259544
This update resolves an issue where negative numbers in accounting reports (like customer statements) were incorrectly formatted, splitting the minus sign and amount across lines. This ensures consistent and accurate display of financial data when printing reports, improving clarity for users.
Original PR description
When printing accounting reports such as customer statements, a negative number may be split across two lines, leaving the minus sign on the first line and the amount on the second. Steps to reproduce: - Make an invoice for [Partner] with a total of 10.0 - Make another invoice for [Partner] with a total of 100.0 - Create a credit note for this last invoice - Open the customer statement report for [Partner] - Print PDF Issue: The first line of the partner section has fewer digits than the amounts of the subsequent journal items. On pdf, the column width is based on the smaller line, causing the longer negative strings to wrap and separate the minus sign from the amount. opw-5951300 Forward-Port-Of: odoo/enterprise#113727
This update resolves an issue where ISO20022 payments using JPY were failing due to a hardcoded decimal format in the generated XML files. The fix dynamically adjusts the decimal places based on the currency, ensuring compatibility with banks that don't use decimal values for JPY.
Original PR description
Steps to reproduce: ------------------- 1. Activate JPY and create a JPY bank journal with ISO20022 as an outgoing payment method 2. Create a vendor (with a country) and add a trusted bank account 3.…
Steps to reproduce: ------------------- 1. Activate JPY and create a JPY bank journal with ISO20022 as an outgoing payment method 2. Create a vendor (with a country) and add a trusted bank account 3. Create and confirm a vendor bill in JPY (e.g. ¥1000), and pay it using the ISO20022 method on the JPY journal 4. Create a batch payment containing that payment, with Batch Type Outbound, on the JPY journal, with ISO20022 as payment method 5. Validate the batch — the XML file is generated and attached 6. Download it -> The `<InstdAmt Ccy="JPY">` node outputs `1000.00`, while JPY has no decimals. The file is rejected by banks. The fix: -------- Backport of 8da91d94ed1e8fad0e827f96172e3785e9f0e28d: > Generating the xml file for iso20022 always generates the amount with two decimals which is hard coded and can cause error for currencies without decimals for example JPY. > The fix is to have the currency decimal number dynamically set through the currency decimal places field. opw-6103849 Forward-Port-Of: odoo/enterprise#113296