Daily updates from Odoo
Tuesday, August 4, 2026
49 changes
8 changes
Enhancements to existing features
The recurring donation product now has a placeholder image, making it appear more polished and recognizable in the online store. This improves the presentation of donation options for website visitors without changing how donations work.
Original PR description
Added placeholder image for the recurring donation product. task-6361612
The Timesheet Timeline view now shows assistant suggestions in true chronological order instead of sorting them by title. It also displays each suggestion's start time, making it easier for users to review and enter timesheets accurately.
Original PR description
Forward-Port-Of: odoo/enterprise#125574 Forward-Port-Of: odoo/enterprise#122862
Payroll batch processing has been optimized by removing unnecessary work entry generation and reducing repeated processing during payslip calculations. This should make large payroll runs noticeably faster, especially when computing many payslips at once.
Original PR description
Backport of https://github.com/odoo/enterprise/pull/124776 without the populate blueprint. Forward-Port-Of: odoo/enterprise#126561 Forward-Port-Of: odoo/enterprise#125288
Added placeholder image for the donation product. Task-6361612 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Added placeholder image for the donation product. Task-6361612 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
We update the IoT Box version, so that it follow the new saas version (19.4). Forward-Port-Of: odoo/odoo#278588
Original PR description
We update the IoT Box version, so that it follow the new saas version (19.4). Forward-Port-Of: odoo/odoo#278588
Pycups has an issue where it can raise an error (1280) meanwhile the status is a success. We don't want to see a traceback in such case, so we skip logging in this case.
Original PR description
Pycups has an issue where it can raise an error (1280) meanwhile the status is a success. We don't want to see a traceback in such case, so we skip logging in this case.
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
6 changes
Enhancements to existing features
Payroll batch processing has been optimized by avoiding repeated and unnecessary work entry calculations. This should make payroll runs and payslip recomputation noticeably faster, especially for companies processing large employee batches.
Original PR description
Backport of https://github.com/odoo/enterprise/pull/124776 without the populate blueprint. Forward-Port-Of: odoo/enterprise#125288
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification
Original PR description
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification ) task-6171251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262801
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
We update the IoT Box version, so that it follow the new saas version (19.4). Forward-Port-Of: odoo/odoo#278588
Original PR description
We update the IoT Box version, so that it follow the new saas version (19.4). Forward-Port-Of: odoo/odoo#278588
this commit move the save order button next to the action button. task-id: 6275576 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
this commit move the save order button next to the action button. task-id: 6275576 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
5 changes
Enhancements to existing features
Payment export files now include building number details in structured addresses where required by upcoming ISO 20022 rules. This helps businesses stay compliant ahead of the November 2026 mandate and reduces the risk of rejected bank payment files.
Original PR description
This commit adds the <BldgNb> node in the iso20022 XML files, as it will be mandatory starting November 2026. Linked: https://github.com/odoo/odoo/pull/271855 task-6317758 Forward-Port-Of: odoo/enterprise#126444 Forward-Port-Of: odoo/enterprise#121674
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification
Original PR description
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification ) task-6171251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262801
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HT
Original PR description
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries…
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HTTP workers were being recycled under normal load. Tracking usage -------------- Every request for a registry goes through the single lookup in the registry constructor, which stamps it with a monotonic timestamp; the stamp is also set when a registry is first built. Collecting idle registries -------------------------- A collection pass drops every registry whose last use is older than the configured idle timeout. It runs at the end of registry loading, so it fires periodically as databases come and go. Registries that are still loading are skipped, so a concurrent build is never collected. Dropping a registry only detaches it from the LRU: a request still holding a reference keeps working, and the next lookup rebuilds it. The timeout is read from ODOO_REGISTRY_MAX_IDLE_TIMEOUT, in seconds; a value of zero, the default, disables the mechanism so behaviour is unchanged unless it is opted into. Results ------- With a five-minute timeout on the same ~2500-database server, the HTTP workers settle at around 40 resident registries instead of saturating memory on the long run. The gevent worker, which sees every web client reconnect at startup and briefly fills the LRU with ~150 databases, releases most of them on the first pass, reclaiming the memory. On a real-life SaaS server with 64GB of RAM, that frees up to ~10GB which were previously taken by unused registries in the LRU. It comes at the expense of extra registry recomputes, but on the other hand workers do not reach their virtual memory limit anymore. closes odoo/odoo#276581 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#278236
4 changes
Enhancements to existing features
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification
Original PR description
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification ) task-6171251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262801
Currently all of our iot boxes are updated on mondays. This PR adds the dynamic selection of the update day of the week based on the rpi serial number. This allows our iot boxes not to be updated all at the same time, reducing the risk of introducing bugs for our clients all at the same time. Related: https://github.com/odoo/odoo/pull/278914
Original PR description
Currently all of our iot boxes are updated on mondays. This PR adds the dynamic selection of the update day of the week based on the rpi serial number. This allows our iot boxes not to be updated all at the same time, reducing the risk of introducing bugs for our clients all at the same time. Related: https://github.com/odoo/odoo/pull/278914
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HT
Original PR description
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries…
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HTTP workers were being recycled under normal load. Tracking usage -------------- Every request for a registry goes through the single lookup in the registry constructor, which stamps it with a monotonic timestamp; the stamp is also set when a registry is first built. Collecting idle registries -------------------------- A collection pass drops every registry whose last use is older than the configured idle timeout. It runs at the end of registry loading, so it fires periodically as databases come and go. Registries that are still loading are skipped, so a concurrent build is never collected. Dropping a registry only detaches it from the LRU: a request still holding a reference keeps working, and the next lookup rebuilds it. The timeout is read from ODOO_REGISTRY_MAX_IDLE_TIMEOUT, in seconds; a value of zero, the default, disables the mechanism so behaviour is unchanged unless it is opted into. Results ------- With a five-minute timeout on the same ~2500-database server, the HTTP workers settle at around 40 resident registries instead of saturating memory on the long run. The gevent worker, which sees every web client reconnect at startup and briefly fills the LRU with ~150 databases, releases most of them on the first pass, reclaiming the memory. On a real-life SaaS server with 64GB of RAM, that frees up to ~10GB which were previously taken by unused registries in the LRU. It comes at the expense of extra registry recomputes, but on the other hand workers do not reach their virtual memory limit anymore. closes odoo/odoo#276581 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#278236
1 change
Enhancements to existing features
Large SEPA direct debit payment batches now validate and send pre-notification emails more efficiently. This reduces waiting time for accounting teams processing hundreds or thousands of payments, helping avoid slowdowns and timeouts.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
4 changes
Enhancements to existing features
### [FIX] website: fix GMaps deprecation console warning for s_google_map Google deprecated the synchronous script loader for initializing the Maps JS API. This caused browser console warnings. The fix adopts Google's official `importLibrary()` bootstrap pattern, which loads map libraries (places, maps, marker) lazily on demand rather than all at once.The version is updated to `v=weekly`, which Google recommends as it receives updates weekly versus quarterly for version numbers(`v=num
Original PR description
### [FIX] website: fix GMaps deprecation console warning for s_google_map Google deprecated the synchronous script loader for initializing the Maps JS API. This caused browser console warnings. The…
### [FIX] website: fix GMaps deprecation console warning for s_google_map Google deprecated the synchronous script loader for initializing the Maps JS API. This caused browser console warnings. The fix adopts Google's official `importLibrary()` bootstrap pattern, which loads map libraries (places, maps, marker) lazily on demand rather than all at once.The version is updated to `v=weekly`, which Google recommends as it receives updates weekly versus quarterly for version numbers(`v=number`). Steps to reproduce: 1. Add the `s_google_map` snippet(not the`s_map`, enable debug mode) 2. Open the browser console and observe the deprecation warning ### [IMP] website: warn user to reload after GMaps config changes Switching from the legacy Google Maps APIs to the new APIs requires enabling additional services in Google Cloud. Existing maps using the legacy API continue to work, but when an admin edits a map without a proper configuration, the `GoogleMapAPIKeyDialog` dialog opens. Google Maps configuration changes (API key update or enabling services) do not take effect during the current editor session because the Maps JavaScript API is loaded at page initialization. Before this commit, such misconfigurations (disabled services or invalid API keys) only triggered a dialog showing a generic Google Maps error. After this commit, a notification informs the user that the page must be reloaded for configuration changes to take effect. The setup instructions are also updated to reference the "Places API (NEW)" service. ### [IMP] website: replace deprecated Places API calls in GPS picker The GPS picker relied on `PlacesService.nearbySearch` and `getDetails`, which are part of the deprecated Places API. The new places API replaces these with `Place.searchNearby` and `fetchFields`. Error handling is consolidated into a single try/catch since the new Places API throws on failure rather than returning a status code, removing the need for `PlacesServiceStatus` checks. ### [IMP] website, *: replace deprecated Google Autocomplete *: website_form_project google.maps.places.Autocomplete is deprecated in the new Places API. The replacement (`AutocompleteSuggestion.fetchAutocompleteSuggestions`) does not fire DOM events, making it incompatible with the old event-listener pattern used in GPSPicker. A new Owl component (`PlacesAutoComplete`) is introduced to wrap the new API, built on top of the existing `AutoCompleteWithPages`. References: https://developers.google.com/maps/documentation/javascript/load-maps-js-api https://developers.google.com/maps/documentation/javascript/advanced-markers/migration https://developers.google.com/maps/documentation/javascript/legacy/places-migration-overview task-[4441041](https://www.odoo.com/odoo/project/974/tasks/4441041) Forward-Port-Of: odoo/odoo#278344 Forward-Port-Of: odoo/odoo#242765
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and /discuss/channel/messages. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttl
Original PR description
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and…
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and /discuss/channel/messages. Measured from openDiscuss resolving to the message being in the DOM:
- 250 to 460ms on an idle machine;
- 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a
busy runbot looks like, 3 of the 10 over 2 seconds;
- 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds.
"Reactions are ordered by id" fails 1 run in 60 at 4x for that reason.
Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the element is there, so it only delays the report of a test that was going to fail anyway.
This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test.
This should also close most of the open runbot errors shaped like:
Failed to find x of "..." (Timeout of 3 seconds). Found 0 instead.
The element does show up in those, just after the wait gave up.
https://runbot.odoo.com/odoo/error/944188
web companion https://github.com/odoo/odoo/pull/279984
Forward-Port-Of: odoo/odoo#279983This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-
Original PR description
This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-billing sequence pattern, leading to traceability issues. This PR allows the creation of self-billing sales journals to prevent this issue. task-6103142 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276028 Forward-Port-Of: odoo/odoo#259935
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
11 changes
Enhancements to existing features
This update makes Odoo's AI assistant more flexible by standardizing how browser-side actions are handled and how results are returned to the AI. It also improves user experience by updating AI thinking messages more dynamically, preserving normal view filters when opening records, and preventing new messages while the assistant is still responding.
Original PR description
Purpose: -------- Instead of handling each AI client tool as a special case when posting a message in the thread, a dedicated registry (ai.client_tools) has been added to make it easy to declare and…
Purpose:
--------
Instead of handling each AI client tool as a special case when posting a message in the thread, a dedicated registry (ai.client_tools) has been added to make it easy to declare and extend client-side tool handlers: `registry.category("ai.client_tools").add(name, (thread, params) => cb);`
On the Python side, AI tools can now trigger client-side behavior by returning a "client_tool" entry with a name and params, keeping the server interface minimal and consistent.
Updating the thinking text is now done using one of this tool, allowing to update the thinking text more dynamically. For example, the thought will now be updated when the web search tool has been executed.
Also, with this commit, the action domains are not overridden anymore: before, if you asked to open your crm pipeline, it would open it without the default hidden domain (type = 'opportunity'). Now, this domain will be applied, so that the view opened is the same as if the user opened it manually.
#### Async JS tools
Client tools can now pause the agent loop, return a result from the
browser and resume the conversation with this result.
By default, client tools wait for a result from the browser. Tools that
do not need to return a result can set `oneway` to true, allowing the
agent loop to continue without creating a pending tool call (for example
to show a notification).
Tool confirmations and client tool results use the same pending tool
response flow. Confirming a tool re-executes it on the Python side,
while returning a client tool result resumes the loop without
re-executing the tool.
To add a tool that allows the agent to get a result from the browser,
one needs to:
- add an AI tool in the backend that returns a dict with a `client_tool`
entry: `'client_tool': {'name': name, 'params': {}}`;
- add an AI tool in the frontend with the same name in the
`ai.client_tools` registry and return the result that needs to be sent
to the LLM.
For a client tool that does not need to return a result, use the `'oneway'`
option on the `client_tool` entry:
`'client_tool': {'name': name, 'params': {}, 'oneway': True}`
To prevent race conditions that could happen when the user sends a new
message while a client tool is being processed, the send button will now
be disabled when the agent is generating a response.
This commit also removes references to `ai_session_identifier` which was
not used anymore.
Task-6352942Improves the process that suggests reconciliation rules when assigning accounts to bank statement lines. The change prevents failures and slowdowns caused by very long payment references, making bank reconciliation setup more reliable for accounting users.
Original PR description
When setting an account to an account.bank.statement there is a step to automatically create a reconciliation rule/model if one does not exist already. To do so, we retrieve 5…
When setting an account to an account.bank.statement there is a step to automatically create a reconciliation rule/model if one does not exist already. To do so, we retrieve 5 account.bank.statement.lines and use them to define the reconciliation model config. A matching is done on the payment_ref of the account.bank.statement.lines by finding the longest common substring in the reference. ### Current Implementation The current algorithm does so by first generating all the possible substrings for all the payment_ref before doing the intersection between these sets and returning the max if `len(substring) >=10`. This is reasonable when the payment_ref follows either a SEPA communication national standard like the Belgian one or the Creditor Reference standard (ISO 11649). For transactions with large, unstructured communication with more than 100 chars, the method `_get_common_substrings` quickly overfill the memory, sometimes raising a MemoryErorr, and takes a significant amount of time. That's because the nested function `_generate_all_substrings` generates n*(n+1)/2 substrings, with n being the lenght of a payment_ref, called `label` in `generate_all_substrings`. ### Proposed Fix This commit introduces another algorithm to find the largest common substring. It starts by taking the two smallest labels to find their substrings intersection. We know that for an arbitrary collection of labels, the intersection of their substrings sets A ∩ B ∩...∩ Z is included in the intersection of any two substrings sets. The underlying assumption of the first step is that for an arbitrary collection of labels the intersection of the substrings sets of the two smallest labels will be the smallest intersection of any given pair of substrings sets. This won't hold true everytime and using a metric such as label similarity instead of shortest string might be better. But on average this should be good enough and it's easier to implement + it removes the need of preprocessing the labels to compute the similarity. The point of the new nested function `common_substrings` is to discard common substrings as we build them. Using the current `generate_all_substsrings` on either the smallest label or both smallest labels would still generate and store a lot of substrings, especially for large labels. By yielding the common substrings as we find them, the memory footprint is vastly reduced. Lastly, the next substring in the common_substrings iterable is only checked against the remaining labels if it's longer than the current match. This speeds up the whole process ### speedup In a customer database with some account.bank.statement.line with payment_ref > 500 chars, setting a specific account (code 4970) on transactions goes from MemoryError to < 1Mb memory consumption. Because of the memory consumption it was not possible to gather timing value on the current version. Testing the new algorithm in a shell and using as labels the 5 longest payment_ref in the customer database (831, 831, 1117, 1178, 1300 chars), averaging to 2000 chars once normalised, the average time to execute `_get_common_substrings` is 900 ms ± 10.3 ms. Forward-Port-Of: odoo/enterprise#121575 Forward-Port-Of: odoo/enterprise#118824
The website builder now shows a proper preview image for the AI live chat snippet, even when live chat is not installed. Users can also preview the fallback contact button on hover, making the editing experience clearer and more consistent.
Original PR description
*:ai_website_livechat Problems: 1) There's no preview of the livechat snippet in the website builder. If ai_website is installed but not livechat, there's no preview image for the snippet resulting in a cluttered and inconsistent UX. 2) There is no preview on hover for the livechat preview button. Unlike other odoo builder options, the user cannot see what the livechat preview button would look like if hovered over. Solutions: 1) An image has been added `ai_livechat.png` which is shown on preview 2) The AI livechat fallback is previewable and defaults to "Contact Us" linking to the /contactus page. Task-5248712
The timesheet ActivityWatch suggestions panel now displays total tracked time by project and an overall total at the bottom. This gives users a clearer view of how much time has been captured before creating or reviewing timesheets.
Original PR description
This commit introduces new time tracking metrics to the ActivityWatch suggestions panel to improve user visibility into their tracked hours. **Enhancements:** - Added the total duration per project in the By Project grouped view. - Added a grand total footer for all suggestions at the bottom of the list. task-6088877 Forward-Port-Of: odoo/enterprise#125515 Forward-Port-Of: odoo/enterprise#114772
This update aligns several country-specific Point of Sale accounting and electronic invoicing flows with recent accounting changes. It helps keep POS receipts, fiscal certification, and tax reporting working correctly across affected localizations after the accounting refactor.
Original PR description
Refector PR: https://github.com/odoo/enterprise/pull/112634
Shop floor users can now manually adjust production time logs when a timer was not started or stopped correctly. This helps keep work order timing accurate by creating or closing time entries based on the corrected time.
Original PR description
The "Update Time Log" dialog inside shopfloor is added to increase the timer's reliability by manually entering the desired time. If someone forgot to start the timer, this option adds a new productivity line ending now. If someone forgot to stop it, this option close the timer and set the end date accordingly. Task-6164336
When an item quantity is set to zero in the certified Point of Sale flow, all removed order lines are now visibly struck through, not just weighted products. This improves receipt and order clarity and prevents newly added items from being incorrectly merged with previously removed lines.
Original PR description
We now strike every orderline instead of only the ones related to weightable products, when quantity is set to 0. We also fix an issue where the PoS kept merging new orderlines with strikedthrough ones. task-6425588
Cashiers can now see each customer's due or deposit amount directly on the mobile customer selection card. This makes it easier to spot outstanding balances or available deposits before choosing a customer, speeding up checkout decisions.
Original PR description
This commit adds the customer's due/deposit amount to the customer card displayed in the mobile customer selection list, allowing cashiers to quickly identify outstanding balances or available deposits when choosing a customer. Task-6329233 Related PR: https://github.com/odoo/odoo/pull/272076 <img width="200" height="431" alt="image" src="https://github.com/user-attachments/assets/d4ad9e0a-34f9-4995-84d3-8c28058cba4f" />
This updates internal tests for the rental website planning feature to match recent Google Analytics 4 tracking behavior. It helps keep automated checks reliable when analytics tracking is enabled, with no expected change for day-to-day users.
Original PR description
`tracking_info` is now only computed when `google_analytics_key` is set, and `item_id` now uses the template id as a string rather than the variant id as an integer. Set the key in `setUpClass` and update assertions accordingly. See : - https://github.com/odoo/odoo/pull/253856
The manufacturing work order display was slightly simplified by moving an internal setting to the main screen component instead of sharing it more broadly. This reduces unnecessary internal complexity without changing how users interact with the feature.
Original PR description
This commit removes localStorageName from env. It was added in the env but never used in child components so it can be set on the root component.
HR users can now complete employee document signature requests themselves when they are the only required signer. This removes the unnecessary step of sending the document to the employee, saving time and simplifying the process.
Original PR description
Before:
- When creating a Signature Request from the employee form:
- If the document had only one signer (HR user), the system still asked to
send it to the employee.
- HR users could not sign the document directly.
After:
- If there is only one signer (the HR user):
- The HR user can now sign the document directly.
- No need to send the document to the employee.
Impact:
- Saves time for HR users.
- Makes the process simpler and faster.
- Reduces unnecessary steps.
Task: 60323642 changes
Enhancements to existing features
Large SEPA direct debit batches now validate faster by reducing repeated data processing and lookups. This helps businesses process hundreds or thousands of payments more reliably, with shorter waiting times and fewer timeout risks.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
This update adds and improves automated checks for marketing automation flows, especially around failed or bounced messages and scheduled synchronization. It helps reduce the risk of regressions in campaign enrollment and message handling, improving confidence that automated campaigns continue to behave correctly.
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.
7 changes
Enhancements to existing features
Odoo now checks whether a single or batch payment exceeds the maximum amount allowed by the connected financial institution before attempting to submit it. This helps avoid failed payment attempts and gives businesses clearer control when banks impose transaction limits.
Original PR description
Before trying to initiate payments through Odoo/Odoofin, we should check that the total amount for the (batch) payment does not exceed the maximum payment amount allowed by the institution (some Powens institutions introduced that limit). task-6310729
Bank synchronization now recognizes a new type of recoverable error from Odoo's financial connection service. This helps avoid marking connections as failed when the issue should not block ongoing use, reducing unnecessary disruption for users.
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
Before this commit, Peppol error messages (e.g. Schematron errors) were logged in the chatter as a single unformatted line and without any humanization. The errors were too technical and the user could not easily know what action to take. This PR splits the raw error payload into individual entries, maps known error codes to human-readable explanations, and renders them as an HTML list in the chatter. task-6144909 --- I confirm I have signed the CLA and read the PR guidelines at www.od
Original PR description
Before this commit, Peppol error messages (e.g. Schematron errors) were logged in the chatter as a single unformatted line and without any humanization. The errors were too technical and the user could not easily know what action to take. This PR splits the raw error payload into individual entries, maps known error codes to human-readable explanations, and renders them as an HTML list in the chatter. task-6144909 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#265253
This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-
Original PR description
This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-billing sequence pattern, leading to traceability issues. This PR allows the creation of self-billing sales journals to prevent this issue. task-6103142 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#259935
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 == 16.799999999999997` instead of 0.0) and `int(value1 / value2)` can truncate the quotient one step too low (e.g. `int(0.3 / 0.1) == 2` instead of 3). `float_div` returns the `(quotient, remainder)` pair free of those errors. The key is to never run a lossy `%` or `//` on the raw floats. Instead both ope
Original PR description
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 ==…
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 == 16.799999999999997` instead of 0.0) and `int(value1 / value2)` can truncate the quotient one step too low (e.g. `int(0.3 / 0.1) == 2` instead of 3). `float_div` returns the `(quotient, remainder)` pair free of those errors. The key is to never run a lossy `%` or `//` on the raw floats. Instead both operands are first snapped onto the precision grid with `float_round` and then scaled to integers: since a grid-snapped value is a multiple of `rounding`, dividing it by `rounding` counts how many grid steps it spans. That division is still noisy (`4.35 / 0.05 == 86.99999999999999`), so the result is passed through `builtins.round` to coerce it to the exact integer step count. The euclidean division itself is then a plain integer `divmod`, which is exact, and the remainder is scaled back to real units. This is why the correction is applied to the inputs and not to the output: rounding the result of a native `%` would only round an already-corrupt value, and would still misreport the quotient in the corner cases the util exists to handle. Dividing by `rounding` is meaningful for any precision, not only powers of ten: the grid step can be `0.05`, `0.25`, `0.5`, `0.03`, ... and `value / step` counts the steps in every case. This mirrors the normalize/denormalize scheme `float_round` already uses internally. The util shares `float_round`'s inherent limitation: the scaled step count must stay representable as an exact `float` integer, so exactness is lost past ~2**53 grid steps (extreme magnitudes at a fine precision). This is the IEEE-754 double-precision ceiling and is well outside any realistic quantity or price range. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues.
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649
Original PR description
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649
1 change
Enhancements to existing features
The Amazon sales integration now uses Amazon's newer Orders API ahead of the old version being retired in 2027. This keeps order syncing reliable and improves performance by retrieving order and item details together instead of through repeated follow-up requests.
Original PR description
Amazon has announced the deprecation of the Orders v0 API, with a removal date of March 27, 2027. In this commit, we migrate to the new v2026-01-01 API. This new version restructures how order data is queried and delivered, shifting from a multi-request architecture to a nested consolidated payload. This optimizes our sync performance by eliminating the N+1 query problem when fetching order items. Key changes: - Operation Consolidation: `getOrders` is replaced by `searchOrders`. Because Amazon now embeds orderItems directly inside each order object natively, we remove our secondary item-fetching loops. - Financial aggregation: Item prices, taxes, shipping, and discounts are no longer flat fields on the item but are centralized into a `proceeds` object. - Replacing of deprecated flags. - Reorganization of order-related fields. task-5972714