Daily updates from Odoo
Thursday, August 6, 2026
16 changes · master
Enhancements to existing features
GSTR-1 export generation for Indian GST reporting has been optimized to handle large datasets with much lower memory use and faster processing. This helps businesses complete large tax report exports more reliably without hitting time or memory limits.
Original PR description
Current Implementation: ======================= The current implementation of _get_l10n_in_gstr1_json relies on multiple iterations over ORM recordsets. Since the ORM loads multiple fields rather…
Current Implementation: ======================= The current implementation of _get_l10n_in_gstr1_json relies on multiple iterations over ORM recordsets. Since the ORM loads multiple fields rather than only the required fields, memory consumption grows significantly for large datasets (around 700 MB for 150K account move lines). Additionally, the method builds a single large dictionary from _get_tax_details that is tailored for the Indian GST reporting logic. Constructing and holding this intermediate data structure further increases memory usage. The combination of repeated Python loops, ORM overhead, and the large intermediate dictionary results in high execution time and memory consumption, causing the process to exceed the available time and memory limits for large exports. Solution: ========= Instead of processing tax details through the ORM, create a temporary table containing the GST tax details and query this subset directly for each GSTR-1 subsection. This approach bypasses the ORM, fetching only the required columns instead of entire records. Eliminates the need to build the large _get_tax_details dictionary. Reduces the number of Python-side iterations and intermediate data structures. Pushes the data aggregation and filtering to SQL, where it is more efficient. Restricts Python's responsibility to formatting the final JSON output. This significantly reduces memory usage, improves execution speed, and makes the implementation simpler and easier to maintain. task-3941950
Customer portal counters are now calculated with only the level of detail each portal item needs. Alerts still show exact counts, while other portal entries use a faster existence check to improve performance without changing what users see.
Original PR description
Make sure the search_count performed on the portal entries to get the customer portal counters are using the correct limit depending on what is actually needed. Portal entries of type "alert" need the accurate count to be displayed on the alert, no limit should be used. Other portal entries only need to know whether there is at least one matching record in order to display the entry or not, limiting the search_count to 1 to gain some performance. Task-5387495
This update adds more automated checks around marketing automation participant synchronization, especially when scheduled processing fails. The goal is to catch regressions earlier and improve confidence in future performance and reliability work for large databases.
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Add new tests for synchronization cron behavior, notably in case of failure. Forward-Port-Of: odoo/enterprise#126810 Forward-Port-Of: odoo/enterprise#126334
The AI-powered website sales module was updated to stay compatible with recent changes in the main Odoo platform. This helps keep the online sales experience reliable and ready for continued improvements.
Original PR description
Community PR: - https://github.com/odoo/odoo/pull/242995 task-5405584
Test helpers now freeze all Odoo time sources consistently, so automated tests no longer compare a frozen application time with a live database timestamp. This reduces flaky test results across affected apps without changing production behavior.
Original PR description
*= marketing_automations, whatsapp_events
**Odoo has two clocks**
When you write a test and “freeze time,” you usually mean everything should behave as if it’s that moment. In Odoo, that’s not one clock it’s two:
| Source | What it drives |
|:------------|-------------:|
| datetime.now() / fields.Datetime.now() | Domains, defaults, Python logic, “is this overdue?” checks |
| env.cr.now() / cursor.now() | ORM create_date, write_date, and other DB-timestamp fields |
Freezegun only freezes the first one.
So a test can end up in this broken state:
```py
with freeze_time("2024-01-01"):
record = self.env['res.partner'].create({'name': 'Test'})
# Datetime.now() says: 2024-01-01
# record.create_date says: 2025-06-05 (real DB time)
```
The test thinks it’s January 1st, but the record was stamped with today. Any logic comparing “now” vs create_date will be wrong or flaky.
com: https://github.com/odoo/odoo/pull/268541
task-6124007Spreadsheet backend URLs now include the document access token, so copied links work outside the current user session. This makes spreadsheet sharing consistent with regular Documents and avoids needing to open the sharing dialog just to get a usable link.
Original PR description
Regular documents can be shared by copying the URL from the backend. This was not true for spreadsheets: the backend URL only contained the spreadsheet id, so opening it outside the current user session did not carry the document access token. Users had to open the sharing dialog and copy the dedicated link instead. Use the document access token in backend spreadsheet URLs, as `/odoo/.../spreadsheet/<access_token>`, following the same format as other Documents share URLs. The token already embeds the document id, so the id does not need to appear in the path anymore. Spreadsheet actions can be reached from different apps, not only Documents (for example inserted lists/pivots or survey results), so the existing action path is preserved and only the spreadsheet segment is rewritten. Task: [6123064](https://www.odoo.com/odoo/project/2328/tasks/6123064)
Bank synchronization now recognizes a new type of temporary, non-blocking error from Odoofin. This helps avoid marking a bank connection as failed when the issue does not require stopping the synchronization flow.
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
In the payroll run wizard, clicking an employee row now opens that employee's record instead of changing the selection. This makes it faster and clearer for payroll users to review employee details during pay run preparation.
Original PR description
Currently, clicking a row on the first screen of the payrun wizard toggles the employee selection instead of opening the employee record. This change ensures that clicking a row directly opens the employee record. task-6372551
Resolved issues and error corrections
The Barcode app now correctly shows the instruction to scan a package when package handling is enabled. This helps warehouse users find transfers from package barcodes directly from the welcome screen and avoids confusion during scanning workflows.
Original PR description
When packages are enabled, the barcode scanner welcome screen does not display the instructions for scanning a package. ## Steps to reproduce - Enable `Packages` in Inventory settings. - Open the Barcode application. - Observe the instructions listed on the welcome/landing page. - Notice that the instruction `Scan a package to find a transfer` is missing, even though packages are enabled. ## Issue The MainMenu component has a getter barcodeHomeHelper that checks this.packageEnabled to construct the barcode scanner helper bullet points. However, during setup, the configuration value was incorrectly assigned to this.packagesEnabled. ## Fix Correct the variable name typo in the main menu setup so that the package related instructions are correctly displayed when packaging is enabled. [^1] [^1]:  Forward-Port-Of: odoo/enterprise#124658
AI chat now works more reliably when users move into areas such as Shopfloor where view options may not be available. The change prevents an error that could stop users from sending AI chat messages in those contexts.
Original PR description
### Issue When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.…
### Issue
When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.
### Steps to Reproduce
[Video](https://drive.google.com/file/d/1i7kWDnmv4mebGtf1to12BNHCG5omBTXl/view?usp=sharing)
1. Click the **Ask AI** button.
2. Open the AI chat.
3. Keep it open and navigate to the **Shopfloor** app.
4. Send a message in the AI chat.
### Error
```text
TypeError: Cannot read properties of undefined (reading 'map')
at WithSearch.getCurrentViewInfo
```
### Fix
Safely handle cases where `config.viewSwitcherEntries` is undefined by using optional chaining and falling back to an empty array.
**Before**
```js
result.available_view_types = config.viewSwitcherEntries.map((v) => v.type);
```
**After**
```js
result.available_view_types =
config.viewSwitcherEntries?.map((v) => v.type) || [];
```
opw-6414684
Forward-Port-Of: odoo/enterprise#126738
Forward-Port-Of: odoo/enterprise#125821This fixes payroll behavior so refund payslips are not recalculated when a user clicks Compute. This helps preserve the intended refund amounts while still allowing users to clear lines with Reset when needed.
Original PR description
When a payslip is a refund payslip, we don't want to compute it if we click on "compute". The lines can still be reset when clicking on "reset" Forward-Port-Of: odoo/enterprise#126845
Peruvian electronic invoices now calculate down payment amounts consistently when withholding tax is involved. This prevents XML total mismatches that could cause validation or reporting issues, and avoids referencing cancelled down payment 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
Australian payroll data updates now include salary rule category information. This prevents scheduled payroll updates from failing when new categories are added, helping payroll maintenance run more reliably.
Original PR description
ir_cron_update_payroll_data updates the payroll data including rules but fails if a new rule category is introduced. This commit adds the hr_salary_rule_category_data file to the list of data files to update. task-6351929 Forward-Port-Of: odoo/enterprise#122392
Appointment cancellation emails are now sent in the language of the customer who booked the appointment, matching the behavior of confirmation emails. This prevents customers from receiving cancellation notices in the organizer's language and improves communication clarity.
Original PR description
**Problem:** When an appointment is cancelled, the cancellation email is always sent in the organizer's (staff member's) language, ignoring the booking customer's language. The booking confirmation,…
**Problem:**
When an appointment is cancelled, the cancellation email is always sent in the organizer's (staff member's) language, ignoring the booking customer's language. The booking confirmation, by contrast, is correctly localized.
**Steps to reproduce:**
1. Set a contact's language to a non-default one (e.g. Romanian).
2. Book an appointment for that contact (they are the booker/attendee).
3. Cancel the appointment.
4. The customer received the confirmation in Romanian but the cancellation email arrives in English.
**Current behavior:**
The cancellation email is rendered in the organizer's language.
**Expected behavior:**
The cancellation email is rendered in the booking customer's language, like the confirmation/invitation email.
**Cause of the issue:**
The cancellation uses `appointment_canceled_mail_template`, whose `lang` is `{{ object.partner_id.lang }}`. On `calendar.event`, `partner_id` is `related='user_id.partner_id'`, i.e. the organizer, not the customer. The template is posted once per event (via `_track_template`), so its single rendering language applies to every recipient, including attendees whose own language differs. The confirmation email is unaffected because it is the per-attendee `attendee_invitation_mail_template` (model `calendar.attendee`), rendered once per attendee in that attendee's language.
**Fix:**
Deriving the language from `appointment_booker_id` makes the cancellation consistent with the other appointment mails, which are meant for the person who booked the meeting. It falls back to `partner_id` when there is no booker (e.g. an event not created through the appointment flow), preserving the previous behavior in that case.
opw-6323179
Forward-Port-Of: odoo/enterprise#125927
Forward-Port-Of: odoo/enterprise#124116Code cleanup and technical improvements
The IoT connection layer was updated to use Odoo’s newer plugin approach, making the underlying code more flexible and easier to maintain. This should not change day-to-day workflows, but it helps improve reliability and future development for IoT, Point of Sale IoT, and self-ordering IoT features.
Original PR description
OWL3 introduced the concept of Plugins, which can be used similarly to services but are more flexible and have stronger typing. This commit does the following: - Converts the longpolling and websocket services to plugins. - Converts the IoT HTTP service to a plugin, but retains a service wrapper as it is still used in many places. - Use the plugin instead of the service for ORM and notification in all IoT code.
This update keeps German POS certification and Mexican POS e-invoicing modules aligned with a recent loyalty system refactor. It renames an internal coupon reference to a card reference, reducing inconsistency and helping prevent future maintenance issues without changing business workflows.
Original PR description
As part of the pos_loyalty refactor, the pos_orderline.coupon_id field was renamed to pos_orderline.card_id. This PR renames wherever the field is used to keep everything consistent Community PR-[#274951](https://github.com/odoo/odoo/pull/274951) Upgrade PR-[#10948](https://github.com/odoo/upgrade/pull/10948)