Daily updates from Odoo
Wednesday, August 5, 2026
49 changes
6 changes
Enhancements to existing features
SEPA direct debit batch validation has been optimized to handle large payment batches more efficiently. Businesses processing hundreds or thousands of payments should see shorter validation and notification times, reducing delays during payment collection workflows.
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
Improves the process that suggests reconciliation rules when assigning accounts to bank statement lines. This prevents memory errors and speeds up handling of long payment references, making bank reconciliation setup more reliable for users with large or detailed transaction descriptions.
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
Generating the requested business-friendly JSON summary for the pull request.
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#126532 Forward-Port-Of: odoo/enterprise#121674
This update backports additional automated tests and testing tools for marketing automation, including WhatsApp and SMS-related campaign behavior. It helps Odoo detect regressions earlier, especially around failed messages, bounced communications, participant status changes, and synchronization jobs.
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#126769 Forward-Port-Of: odoo/enterprise#126334
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#280568 Forward-Port-Of: odoo/odoo#279677
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#280568 Forward-Port-Of: odoo/odoo#279677
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#280586
Forward-Port-Of: odoo/odoo#2799837 changes
Enhancements to existing features
Payment XML files now include the building number field required by the ISO 20022 standard from November 2026. This helps keep SEPA and related bank payment exports compliant ahead of the deadline, reducing the risk of rejected payments later.
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#126532 Forward-Port-Of: odoo/enterprise#121674
Validating large SEPA direct debit batches is now faster, especially when processing hundreds or thousands of payments. This reduces waiting time and helps prevent timeouts during payment validation and customer pre-notification.
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 backports additional automated checks for Marketing Automation campaigns, including message failure, bounce handling, enrollment, and synchronization jobs. It helps reduce the risk of regressions in campaign processing, especially around scheduled synchronization and WhatsApp or SMS activity behavior.
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#126334
Creating reconciliation rules from bank statement lines is now more reliable when transaction references are very long. The update reduces memory use and processing time, avoiding failures that could block users from assigning accounts to bank statements.
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 signing feature now avoids loading unnecessary role data when opening a template. This reduces background work and can make the signing setup screen respond faster, especially in databases with many signing roles.
Original PR description
This `search_read` is done - without `domain` which means it fetches the entire table - without `fields` which means it fetches all fields And the business code only actually needs the id of the very first record which is returned. See `SignTemplateIframe`'s constuctor: `this.props.signRoles[0].id;` AFAICS, that's the only place where it's used. This will be better refactored in master.
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
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#280586
Forward-Port-Of: odoo/odoo#2799834 changes
Enhancements to existing features
SEPA direct debit batch validation has been optimized to handle large payment batches more efficiently. This reduces processing time for companies validating hundreds or thousands of payments, helping avoid delays and timeouts during payment workflows.
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 backports additional automated tests and test tools for marketing automation flows, including synchronization jobs and message failure or bounce scenarios. It helps reduce the risk of regressions in campaign enrollment, participant state handling, SMS, and WhatsApp-related automation behavior.
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#126334
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
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#278661
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#278661
7 changes
Enhancements to existing features
Large SEPA direct debit batches now validate more quickly by reducing repeated system work during mandate checks and customer pre-notification emails. This improves processing reliability for high-volume payment runs, including cases that previously risked timing out.
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 backports expanded test coverage and supporting tools for Marketing Automation, including checks for message failures, bounces, campaign enrollment, and scheduled synchronization behavior. It helps reduce the risk of regressions in automated campaigns, especially when participant synchronization or message delivery encounters errors.
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#126334
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
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951
Original PR description
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
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#280400
Forward-Port-Of: odoo/odoo#279983Comply with new provincial fiscal transparency regulations (CABA, Entre Ríos, Chubut, and other provinces still not defined) that mandate detailing Perception IIBB taxes on B2C invoices (Factura/Invoice B): - Some jurisdictions mandate a new description for IIBB perception taxes on the invoice, - We need to put the IIBB perception taxes in the special "Fiscal Transparency Regime" table, and exclude them from the standard tax table, task-6367087 Forward-Port-Of: odoo/odoo#278729 Forwar
Original PR description
Comply with new provincial fiscal transparency regulations (CABA, Entre Ríos, Chubut, and other provinces still not defined) that mandate detailing Perception IIBB taxes on B2C invoices (Factura/Invoice B): - Some jurisdictions mandate a new description for IIBB perception taxes on the invoice, - We need to put the IIBB perception taxes in the special "Fiscal Transparency Regime" table, and exclude them from the standard tax table, task-6367087 Forward-Port-Of: odoo/odoo#278729 Forward-Port-Of: odoo/odoo#277673
5 changes
Enhancements to existing features
Odoo now checks a bank institution's maximum allowed payment amount before starting an online or batch payment. This helps businesses avoid failed payment attempts when their bank provider enforces 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 Forward-Port-Of: odoo/enterprise#121513
The Amazon sales integration now uses Amazon's newer Orders API ahead of the old API's planned shutdown. This keeps order imports compatible with Amazon's platform and should improve synchronization efficiency by retrieving order and item details together.
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 Forward-Port-Of: odoo/enterprise#126712 Forward-Port-Of: odoo/enterprise#114591
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#278086
Original PR description
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#278086
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 Forward-Port-Of: odoo/odoo#277160
The checks the Tax Agency performs are always based on the latest version of their XSD (no API versioning), but the XSD URI changes with each new version of the checks. Since it's not functionally used, it's not so important to keep it always updated and yet now: - we now update the export templates to have the latest `schemalocation` URI for once. - we start ignoring namespaces in l10n_it_* XML tests - we start ignoring the root FatturaElettronica tag's namespace attributes so there
Original PR description
The checks the Tax Agency performs are always based on the latest version of their XSD (no API versioning), but the XSD URI changes with each new version of the checks. Since it's not functionally used, it's not so important to keep it always updated and yet now: - we now update the export templates to have the latest `schemalocation` URI for once. - we start ignoring namespaces in l10n_it_* XML tests - we start ignoring the root FatturaElettronica tag's namespace attributes so there won't be a problem in case we change the `schemalocation` again. Forward-Port-Of: odoo/odoo#275345
14 changes
Enhancements to existing features
SEPA direct debit batch validation has been optimized for large payment batches. This reduces processing time and avoids timeouts when validating thousands of payments, improving reliability for finance teams.
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
Employees can now be associated with more than one company car, improving support for benefits and payroll scenarios where multiple vehicles are provided. This helps Belgian payroll and salary contract processes calculate and display company car benefits more accurately.
Original PR description
WIP to allow multiple company cars per employee
Archived tax returns now hide the actions that would validate, submit, or fetch e-invoices for them. This prevents users from accidentally continuing work on returns that have been closed or archived, reducing the risk of incorrect tax processing.
Original PR description
Hide validate and Submit button on tax returns when the return is archived, and hide the 'Fetch E-Invoice' button on the return check in case of GSTR-2B report when the return is archived. Previously, an archived return could still be validated and processed further. Since validation is the entry point for all subsequent actions on a return, blocking it at this stage prevents any further processing of archived returns. Related Pr: PR community - https://github.com/odoo/odoo/pull/270669 task-6303338
The Timesheet Assistant now supports keyboard navigation for reviewing and selecting suggested timesheet entries. This improves accessibility and helps users work faster without relying only on a mouse.
Original PR description
Implement full keyboard controls for managing timesheet suggestions to improve accessibility and user efficiency. This adds support for the following interactions: - ArrowUp / ArrowDown to navigate focus through rows - Space to select/deselect the focused item (and set the selection anchor) - Shift + Arrows to select continuous ranges of suggestions task: 6267620 Forward-Port-Of: odoo/enterprise#126143 Forward-Port-Of: odoo/enterprise#120437
Payroll warning messages now open directly in a detailed view when there is only one warning and no custom action is defined. This reduces extra clicks for users, while still showing a list when multiple warnings need review.
Original PR description
When the warning doesn't have a specific action implementation and it returns a single warning record, we display it in a form view instead of the list view. List view will be displayed only in multiple warning records. task-6425861
Appointment kanban cards now open the calendar view focused on today, making navigation more predictable. The separate upcoming meetings button now correctly opens the next scheduled meeting, while confirmation-related actions only load meetings that need confirmation.
Original PR description
Before, a click on an appointment kanban card lead to the gantt view of calendar.event, using the first next event as the initial_date of the gantt view. It was also the case when using the dedicated 'upcoming meetings' button on the card, which was pretty much a fake button. Now, use today as the default, next upcoming meeting when using 'upcoming meetings', using a new dedicated action, and only request meetings when using 'to confirm', as before. The tour is updated accordingly as well. Task-6344764
This draft improves the reliability of Knowledge article comments by adding tests for creating comments, handling large selections, deleting commented text, undo/redo behavior, keyboard navigation, and invalid comment placement. It helps ensure comment markers behave consistently before the feature is finalized, though the work is still described as needing cleanup.
Original PR description
This commit creates a test environment for article comments; it mounts a limited version of the Knowledge form view and mocks the necessary services and routes to allow for comment creation. It still needs to be heavily cleaned up, as many artifacts of earlier versions still linger, or have yet to be used. Many tests have also yet to be written; and the current version keeps them all in the same file. task-4235306
This update adds richer demo data for Belgian payroll testing, including employees, contracts, work schedules, attendance records, and a vehicle. It helps teams manually test payroll scenarios that better reflect real customer situations, and employee search now also works with external codes.
Original PR description
Add demo data records to match more realistic real world scenarios of employees, contracts, resource calendars and attendances. task-6364398
A new assistant rule was added for Timesheet Grid to help track runbot testing and the related branch. This improves internal testing visibility with minimal direct impact on end users.
Original PR description
Add an assistant rule to track runbot testing and which branch. --- task-6410639
Payroll warnings can now automatically apply only to records for the relevant country when company information is available. This reduces irrelevant warnings across multi-country payroll setups and helps teams focus on the alerts that apply to their local rules.
Original PR description
* = l10n_{be, ch, hk, in, sa}_hr_payroll
With this commit, by default when a warning will be defined on a specific country, if this warning is defined with a warning_domain and if the model linked to this warning have company field a sub domain to restrict this warning to model's record defined in this country will be automatically added.
task-6425987Tax return cards have been redesigned to be narrower and less tall, making long lists easier to review. This helps users scan return statuses and actions more quickly, using a layout aligned with other Odoo card views.
Original PR description
Returns are worked through as a list, but the cards were too wide and tall to scan. Reviewed the design following payroll's narrower kanban cards design. task-6088472
The data cleaning merge details popup has been redesigned to make it easier to understand how duplicate records will be combined. Improved views, field display, hover behavior, and keyboard focus help users review merges more confidently before confirming them.
Original PR description
Before this PR, the merge details popup needed a redesign, now the different views showcase the merge better to the user. | Before | Before | After | |--------|--------|--------| | First section |…
Before this PR, the merge details popup needed a redesign, now the different views showcase the merge better to the user. | Before | Before | After | |--------|--------|--------| | First section | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 10 44" src="https://github.com/user-attachments/assets/81faaad4-f950-4031-bd1c-66b46c1e61c3" /> | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 07 59" src="https://github.com/user-attachments/assets/46895709-3575-4bae-864e-f33a96a7737b" /> | | Second section | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 10 47" src="https://github.com/user-attachments/assets/1fd3381c-d93c-4a2e-892b-134633279677" /> | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 08 05" src="https://github.com/user-attachments/assets/0400e9f4-00ee-4d8b-9d77-a1566b1242f5" /> | | Third section | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 10 52" src="https://github.com/user-attachments/assets/dce3590c-4f16-473a-abd7-611f781f70f3" /> | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 08 13" src="https://github.com/user-attachments/assets/a8315904-0067-4794-b48d-6b357445d1c7" /> | | Record hover | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 11 02" src="https://github.com/user-attachments/assets/1fa8fa2e-e9e0-45a6-a8c0-6dd4a8e6fa9b" /> | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 08 17" src="https://github.com/user-attachments/assets/78434801-f34e-4e8f-87d9-bc9841a1628a" /> | | Field display | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 10 52" src="https://github.com/user-attachments/assets/d410867c-3013-4b90-99a2-b26bbab22e86" /> | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 12 02" src="https://github.com/user-attachments/assets/38b1e359-02b5-4586-990e-f11805390ddd" /> | | Tab focus (accessibility) | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 10 44" src="https://github.com/user-attachments/assets/162b0a57-5138-45f7-b595-76337a5793dc" /> | <img width="1023" height="985" alt="Screenshot 2026-06-26 at 11 09 18" src="https://github.com/user-attachments/assets/3b79e21a-ab1c-47a8-874a-0f9f157938f3" /> | task-6196149
HR users can now confirm, reset, or mark multiple appraisals as done in one action. This reduces repetitive work and helps teams process appraisal workflows faster when managing many records.
Original PR description
Before this: HR users had to perform appraisal actions one by one, such as Confirm, Reset and Mark as Done. This was slow and repetitive when managing many appraisals. After this commit: Added bulk server actions to Confirm, Reset, and Mark as Done for multiple appraisals at once, making the appraisal process faster and easier for HR users. Task-6368348
The Sign app now only retrieves the single role record it needs instead of loading every role and all related details. This reduces unnecessary data fetching and should improve performance when opening sign template actions, especially in databases with many roles.
Original PR description
This `search_read` is done - without `domain` which means it fetches the entire table - without `fields` which means it fetches all fields And the business code only actually needs the id of the very first record which is returned. See `SignTemplateIframe`'s constuctor: `this.props.signRoles[0].id;` AFAICS, that's the only place where it's used. This will be better refactored in master. Forward-Port-Of: odoo/enterprise#126835
6 changes
Enhancements to existing features
Appointment pages now calculate bookable capacities much more efficiently, especially when many linked resources are involved. This makes availability pages load far faster and also corrects capacity values in some resource-selection cases.
Original PR description
Before --- - When opening the appointment page, the possible capacities that a user can book needs to be calculated to show the capacity dropdown. - This is currently done by getting all the possible…
Before
---
- When opening the appointment page, the possible capacities that a user can book needs to be calculated to show the capacity dropdown.
- This is currently done by getting all the possible combinations that could arise from each resource along with its linked resources (Linked resources are resources that are used to combine with the main resource to allow a bigger capacity)
- The complexity of this approach blows up with the increase in linked resources. For each resource we end up with O(2^m) where m is the number of linked resources it has. If they have the same number of linked resources, and n is the number of resources, we end up with O(n*2^m)
Solution:
- Flipping the algorithm, we create a structure for possible capacities and only keep the best combination for a found capacity.
- We first store all available capacity for relevant resources.
Algorithm
---
For a resource:
- We initialize the solution S to {0: []}
- Greedy dynamic programming is then used to get all the possible combinations by building the result dict, adding one resource at a time. We add its capacity to all entries of S -> we use the combination if a new capacity is reached OR update the combination if the number of elements of combination is less than the existing one.
Then, for the global solution:
- We go through S of resources (in the order of self), and add entries to G (the general dict of solutions). Again, on collision, we only keep the lower-cardinal combination.
The complexity of this algorithm is O(n*u) where u is the dynamic programming complexity. u would be quadratic O(m^2) if the sub-sums of capacities overlap heavily, for instance when resources have the same capacity, like tables of a restaurant, but could reach (2^m) in the worst case scenario.
Related changes / side effects
---
1. Fixing an issue
2. Cleaning strange logic
3. Cleaning max capacity computation
Benchmark:
- opw-5177932 goes down from 6 mins to less than 2 seconds using the new algorithm.
Also include
---
Fix the max capacity on resources when skipping resource selection. It computed the max capa based on values that were not yet emptied in the website_appointment controller.
Task-6233563The preparation display now uses the clearer label “Footer Note” instead of “General Note,” alongside an updated icon. This makes the action button easier for staff to understand when managing order notes.
Original PR description
Following this commit : ==== - General Note is renamed to Footer Note. task- 4210929
The Amazon sales integration now uses Amazon's newer Orders API ahead of the 2027 retirement of the old version. This keeps order imports compatible with Amazon's platform and should improve synchronization performance by retrieving order details more efficiently.
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 Forward-Port-Of: odoo/enterprise#114591
The checks the Tax Agency performs are always based on the latest version of their XSD (no API versioning), but the XSD URI changes with each new version of the checks. Since it's not functionally used, it's not so important to keep it always updated and yet now: - we now update the export templates to have the latest `schemalocation` URI for once. - we start ignoring namespaces in l10n_it_* XML tests - we start ignoring the root FatturaElettronica tag's namespace attributes so there
Original PR description
The checks the Tax Agency performs are always based on the latest version of their XSD (no API versioning), but the XSD URI changes with each new version of the checks. Since it's not functionally used, it's not so important to keep it always updated and yet now: - we now update the export templates to have the latest `schemalocation` URI for once. - we start ignoring namespaces in l10n_it_* XML tests - we start ignoring the root FatturaElettronica tag's namespace attributes so there won't be a problem in case we change the `schemalocation` again.
**=pos_restaurant,pos_sale Following this commit : ==== - General Note is renamed to Footer Note and icon is also added. - Quotation/Order is renamed to Quotation. - Edit Order Name is renamed to Name. - Customer Note is renamed to Item Note. - Cancel Order is renamed to Delete Order. task- 4210929
Original PR description
**=pos_restaurant,pos_sale Following this commit : ==== - General Note is renamed to Footer Note and icon is also added. - Quotation/Order is renamed to Quotation. - Edit Order Name is renamed to Name. - Customer Note is renamed to Item Note. - Cancel Order is renamed to Delete Order. task- 4210929
This change cleans up the requested data from `/mail/thread/data` route, ensuring it aligns with what is actually needed depending on the user and thread.
Original PR description
This change cleans up the requested data from `/mail/thread/data` route, ensuring it aligns with what is actually needed depending on the user and thread.