Daily updates from Odoo
Friday, October 31, 2025
30 changes
2 changes
Enhancements to existing features
VoIP sessions now try to sign out automatically when a browser tab is closed and expire sooner if that does not happen. This helps prevent users from hitting provider limits caused by multiple open or recently closed Odoo tabs.
Original PR description
Some providers like OnSIP allow for a limited number of registrations per user. This is a problem in Odoo because each tab opened creates a new registration for one hour. This commit mitigates the problems in two ways: - Sends an "unregister" request onbeforeunload to try to invalidate the registration upon closing the tab. - Reduces the TTL of registrations so that they get invalidated quicker in case the unregistration failed. Forward-Port-Of: odoo/enterprise#98413 Forward-Port-Of: odoo/enterprise#97963
Recruitment screens now load much faster by simplifying how eligible users are determined for job records. This reduces page processing time and response size, making the Recruitment app feel more responsive, especially for companies with many users.
Original PR description
Description ----------- The commit odoo/odoo@0f981b14ea22cc154bcd93f53dc19f46c37ecb13 tried to fix an issue where, if the `company_id` was not set in the Form view, no `user_id` would match if they…
Description
-----------
The commit odoo/odoo@0f981b14ea22cc154bcd93f53dc19f46c37ecb13 tried to fix an issue where, if the `company_id` was not set in the Form view, no `user_id` would match if they had a `company_id` set, while the wanted behavior was the inverse, all internal users should match regardless of companies.
This was fixed by introducing a computed field `allowed_user_ids` which was doing the company computation manually and replaced the `company_ids` domain leaf on the field.
Sadly, this approach introduces a performance regression on the front-end side, as the webclient creates internal data structures *per* individual result of the RHS in the domain. So if `allowed_user_ids` returns a lot of matching `ids`, it becomes a significant overhead.
Following the refactoring of `domains.py`, a slight semantic change happened and the initial issue of the bugfix can be resolved by just changing the domain operator to `'=?'` instead. When `company_id=False`, the domain leaf `('company_ids, '=?', False)` is optimized out by `_operator_equal_if_value` as `_TRUE_DOMAIN` (aka `(1, '=', 1)`). This is as expected behavior post-bugfix. This was not the case before the refactoring.
This allows us to completely deprecate the usage of the field `allowed_user_ids` and the front-end has no significant post-processing to do.
⚠️ This commits deprecates `hr.job.allowed_user_ids`, but doesn't remove it yet, as it might be referenced by views or custom JS.
Benchmark
---------
On a 19.0 database where `allowed_user_ids` returns 1.4k ids, opening the default kanban view of the Recruitment app took:
| | Before | After | Improvement |
|-----------------------|---------|--------|-------------|
| Backend process time | 400ms | 160ms | 2.5x |
| Frontend process time | 3.3s | 220ms | **15x** |
| Total (LCP) time | 3.7s | 380ms | 9.7x |
| Response Payload size | ~800KiB | ~33KiB | **24x** |
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#2323542 changes
Enhancements to existing features
Recruitment pages now avoid loading large hidden user lists, making key views open much faster. This improves responsiveness for recruiters, especially in databases with many users, while keeping the same company-based user selection behavior.
Original PR description
Description ----------- The commit odoo/odoo@0f981b14ea22cc154bcd93f53dc19f46c37ecb13 tried to fix an issue where, if the `company_id` was not set in the Form view, no `user_id` would match if they…
Description
-----------
The commit odoo/odoo@0f981b14ea22cc154bcd93f53dc19f46c37ecb13 tried to fix an issue where, if the `company_id` was not set in the Form view, no `user_id` would match if they had a `company_id` set, while the wanted behavior was the inverse, all internal users should match regardless of companies.
This was fixed by introducing a computed field `allowed_user_ids` which was doing the company computation manually and replaced the `company_ids` domain leaf on the field.
Sadly, this approach introduces a performance regression on the front-end side, as the webclient creates internal data structures *per* individual result of the RHS in the domain. So if `allowed_user_ids` returns a lot of matching `ids`, it becomes a significant overhead.
Following the refactoring of `domains.py`, a slight semantic change happened and the initial issue of the bugfix can be resolved by just changing the domain operator to `'=?'` instead. When `company_id=False`, the domain leaf `('company_ids, '=?', False)` is optimized out by `_operator_equal_if_value` as `_TRUE_DOMAIN` (aka `(1, '=', 1)`). This is as expected behavior post-bugfix. This was not the case before the refactoring.
This allows us to completely deprecate the usage of the field `allowed_user_ids` and the front-end has no significant post-processing to do.
⚠️ This commits deprecates `hr.job.allowed_user_ids`, but doesn't remove it yet, as it might be referenced by views or custom JS.
Benchmark
---------
On a 19.0 database where `allowed_user_ids` returns 1.4k ids, opening the default kanban view of the Recruitment app took:
| | Before | After | Improvement |
|-----------------------|---------|--------|-------------|
| Backend process time | 400ms | 160ms | 2.5x |
| Frontend process time | 3.3s | 220ms | **15x** |
| Total (LCP) time | 3.7s | 380ms | 9.7x |
| Response Payload size | ~800KiB | ~33KiB | **24x** |
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#232354Portal comments that include a rating are now treated as meaningful even when no written text is added. This helps customer reviews, course feedback, and rated chatter entries remain visible and editable instead of being ignored as empty messages.
Original PR description
*: portal, portal_rating, rating, website_slides task-5016995 Forward-Port-Of: odoo/odoo#230426 Forward-Port-Of: odoo/odoo#223515
16 changes
Enhancements to existing features
The asset list view has been adjusted to show additional useful information while keeping some fields hidden by default. This gives users more flexibility to see relevant asset details without cluttering the standard view.
Original PR description
This PR adds some new fields to the assets list view and makes some fields `optional='hide'`. Task [link](https://www.odoo.com/odoo/project.task/5163529) task-5163529
VoIP users can now close error screens when the issue does not block their work. This makes it clearer that minor errors can be dismissed and helps reduce confusion during calls or softphone use.
Original PR description
When the error is non-blocking, a close button is now added to the error screen in order to indicate that the error can be removed. Task ID: [4891947](https://www.odoo.com/odoo/project/5778/tasks/4891947)
Users can now upload files or attach documents directly in conversations with AI agents, so the agent can use that content when answering. This makes AI chats more useful for document-based questions and keeps each file linked to the correct message in the conversation history.
Original PR description
Purpose: -------- When chatting with an agent one can now upload files (or attach documents if documents is installed) that will be processed by the LLM to generate the answers Technical Changes:…
Purpose:
--------
When chatting with an agent one can now upload files (or attach documents
if documents is installed) that will be processed by the LLM to generate
the answers
Technical Changes:
------------------
To support this feature, files needs to be inside their related messages.
Previously they were simply appended to the list of inputs that were sent
to the LLMs, but that does not work inside a chatter because one sends the
history of messages. So if a user uploads a file in its first message, then
another one in the second message, one can't append them both to the list
of inputs otherwise the LLM would consider the first one as a new upload,
instead of an attachment from the previous message.
The `request_llm` method of the llm api service has been refactored to be
able to achieve this, and simplify the addition of attachment in any
message.
Instead of having 3 parameters "user_prompts", "inputs" and "files", there
is now only one parameter "messages".
Messages should always be either a string (considered as user prompt),
either a dict containing the role and the message parts:
```py
{'role': 'user', 'parts': [
{'type': 'text', 'content': 'hello'},,
{'type': 'image/png', 'content': 'aW1hZ2UgY29udGVudA=='},
{'type': 'application/pdf', 'content': 'cGRmIGNvbnRlbnQ='},
]}
```
These messages will be converted to the format expected by the different
providers before the loop calling the llm so that the llm answers can be
appended to this message list.
The tools are now also converted before the loop (there is no real need
to convert them in every loop iteration.
Task-5031785The Shop Floor registration flow no longer changes production quantity, component reservations, or manufacturing order status just because a lot or serial number is generated. This helps prevent unintended manufacturing order updates and gives users clearer control when registering production, especially for serial-numbered items.
Original PR description
In the Shop Floor app, opening the 'Register Production' step no longer pre-fills the 'Quantity Producing' field, and the field is now editable for serial numbers. Additionally, generating a lot or serial number for a manufacturing order no longer updates the 'Quantity Producing' field. Component reservations and the MO status also remain unchanged when a lot or serial number is generated. These changes ensure that generating lot or serial numbers does not introduce unintended side effects in the manufacturing order flow. Task ID: [4688059](https://www.odoo.com/odoo/project/966/tasks/4688059)
Malta reporting now includes return deadlines and guided submission wizards for EC Sales List, tax returns, and Intrastat goods reports. This helps businesses track compliance timing and prepare required submissions more consistently within Odoo.
Original PR description
- add ec_sales_list return deadline and wizard - add tax_return wizard - add intrastat return deadline and wizard task - 4781287
Payroll salary rules can now specify whether they appear on payslips always, never, or only when the result is not zero. This improves payslip clarity across multiple country payroll localizations and ensures items like Australia's Medicare Adjustment appear only when relevant.
Original PR description
- Modify the 'Appear on Payslip' field from a boolean to a selection field with the following options:
- Always
- Never
- If result is not zero
- update the data for 'appear on payslip' field in several localization.
- In the Australia localization, update the 'Medicare Adjustment' appear_on_payslip field to "If Result is Not Zero". This adjustment is necessary since the payslip template utilizes this configuration.
task-4979423This update removes outdated invisible fields from several Odoo views across website, accounting, helpdesk, WhatsApp, and related modules. The change simplifies internal screen definitions and reduces maintenance overhead without changing day-to-day functionality for users.
Original PR description
Invisible field from views are useless since: see: https://github.com/odoo/odoo/commit/5639ed865c5a3b82bab25b0ecac28c68c02e93065639ed8 see: https://github.com/odoo/odoo/pull/137031
Mexican payroll payslips now show clear issues when required information is missing for CFDI generation. This helps payroll teams identify and correct missing data earlier, reducing failed electronic payslip processing.
Original PR description
We now have a "issues" system on the payslips. Let's use it to signal what is missing for the correct generation of the CFDI. Task: 5068311 Forward-Port-Of: odoo/enterprise#94748
This update improves the bank reconciliation widget with more consistent styling and clearer transaction details. It also prevents users from choosing certain bank-related accounts that would create ineffective reconciliation rules, and keeps payable and receivable actions more consistently available.
Original PR description
[IMP] account_accountant: css backport To have a consistent css across all version of the new bank rec widget, we decided to backport few changes. backport of:…
[IMP] account_accountant: css backport To have a consistent css across all version of the new bank rec widget, we decided to backport few changes. backport of: https://github.com/odoo/enterprise/commit/524a7a46a0c2888b591de7ad1a0a6d744e345f5a https://github.com/odoo/enterprise/commit/2a83c85cb2c9a7a5da3d4a8483120eeda6b2e6cb https://github.com/odoo/enterprise/commit/e3cb3ab3ec8c64297d8e97d941e0d2eea3e64667 https://github.com/odoo/enterprise/commit/fdbb93abbf831cfa2fdc75e79aa76c094d6e522a https://github.com/odoo/enterprise/commit/f9725d7b01cbd1235f022821a6861adb2955e49e [FIX] account_accountant: restrict some account in the set_account Before this commit, we could select the liquidity account or bank suspense account which could create a reco model for it that would do nothing. [FIX] account_accountant: partner_name Before this commit, when a transaction had no partner_name and some lines with the same partner. When unfolded, we had the info of the partner on the statement line and on the line itself which was a duplicate of information. This commit will change when the line is unfolded so that the partner is visible on the statement line only when there is a partner_name [FIX] account_accountant: payable and receivable button Before this commit, the payable and receivable buttons where on the top line only when the reconcile button was not there anymore. Now We decided to always have them present in secondary next to the reconcile button. no task-id Forward-Port-Of: odoo/enterprise#98458 Forward-Port-Of: odoo/enterprise#96852
This update simplifies how website builder options are defined and shared across related builder components. It helps developers maintain website editing features more consistently, reducing future maintenance effort without changing the business-facing behavior.
Original PR description
The commit: 1. use static property to configure a builder option 2. introduce the concept of dependencies to access the plugin's shared in builder option 3. make a plugin context the same for Plugin,…
The commit:
1. use static property to configure a builder option
2. introduce the concept of dependencies to access the plugin's shared
in builder option
3. make a plugin context the same for Plugin, BuilderOption and
BuilderAction to have the same API in each class.
Before this commit, to define an option, we had to define a javascript
object that would contain the information of the option within the
`builder_options` resource.
```js
class MyPlugin extends Plugin {
resources: {
builder_options: [
{
selector: "div.selector",
template: "my.owlTemplate",
cleanForSave() {}
// ... other option props
}
]
}
}
// For a custom component
class MyPlugin extends Plugin {
resources: {
builder_options: [
{
selector: "div.selector",
template: MyCustomComponent,
cleanForSave() {}
// ... other option props
}
]
}
}
class MyCustomComponent extends BaseOptionComponent {
// ...
}
```
When building anything for the builder, there is 3 classes that are
important: `Plugin`, `BaseOptionComponent`, `BuilderAction`.
In practice, the option object defined in builder_options feels
strange. On the other hand, making the configuration of the option as
a static property of the component somehow feels simpler as everything
related to that option is defined in the same class.
```js
class MyPlugin extends Plugin {
resources: {
builder_options: [MyCustomComponent]
}
}
class MyCustomComponent extends BaseOptionComponent {
static template = "my.owlTemplate";
static selector = "div.selector";
static cleanForSave(context) {}
// ...
}
```
To have the same mental context in the 3 important class, they all
share the same API (`dependencies`, `dispatchTo`, `getResource`, ...)
(see `Editor.getPluginContext`)
To access a plugin shared method, it's now the same for `Plugin`,
`BuliderAction` and `BaseOptionComponent`:
```js
class MyCustomComponent extends BaseOptionComponent {
static selector = "mySelector";
static dependency = "myPlugin";
myMethod() {
this.dependencies.myPlugin.pluginMethod();
}
}
```
To access a resource, dispatch, ...:
```js
class MyCustomComponent extends BaseOptionComponent {
static selector = "mySelector";
myMethod() {
const resource = this.getResource('myResource');
}
}
```
Forward-Port-Of: odoo/enterprise#96515
Forward-Port-Of: odoo/enterprise#94102The IoT restart button now uses the shared IoT communication service to restart IoT Boxes remotely. This makes remote restart handling more consistent and easier to maintain, with minimal visible change for users.
Original PR description
In order to simplify restarting IoT Boxes remotely, we adapted the restart button to use the `iot_http` service. odoo/odoo#232133 Task: 5169648 Forward-Port-Of: odoo/enterprise#97525
VoIP browser tabs now try to close their phone service registration when the tab is closed, and unused registrations expire sooner if that cleanup fails. This helps businesses avoid hitting provider limits that can prevent users from making or receiving calls.
Original PR description
Some providers like OnSIP allow for a limited number of registrations per user. This is a problem in Odoo because each tab opened creates a new registration for one hour. This commit mitigates the problems in two ways: - Sends an "unregister" request onbeforeunload to try to invalidate the registration upon closing the tab. - Reduces the TTL of registrations so that they get invalidated quicker in case the unregistration failed. Forward-Port-Of: odoo/enterprise#98413 Forward-Port-Of: odoo/enterprise#97963
Companies can now choose how negative amounts appear in financial reports, either with a minus sign or in parentheses. US companies will use the parentheses format by default, matching common local accounting practice, while other companies can set their preferred format in settings.
Original PR description
This PR allows the user to choose how to display the negative amounts in the reports, either " (negative_amount) " - common US formatting - or " - negative_amount ". If the country is US the (negative_amount) format will be selected by default. The choice is available in the settings and is company specific. task-5118741
Payroll rule parameters now keep a visible history when key values or their start dates change. This helps payroll teams audit configuration changes more easily from the rule parameter record itself.
Original PR description
This commit adds native-style tracking for the fields `date_from` and `parameter_value` of the model `hr.rule.parameter.value` inside its parent model `hr.rule.parameter` that nests parameter value lines in its form view. For this purpose, a chatter was thus added to `hr.rule.parameter` form view. TaskID: 5176977
Opening the Phone app call list is now much faster for HR officers on large databases. The access rule was adjusted to avoid slow database filtering, reducing load times from seconds to milliseconds in the benchmark.
Original PR description
Description ----------- The rule `voip_call_hr_access_rule` is added with an `OR` to `voip_call_rule_user`, but with the presence of the `One2many` `employee_ids` in the domain, the final query leads…
Description ----------- The rule `voip_call_hr_access_rule` is added with an `OR` to `voip_call_rule_user`, but with the presence of the `One2many` `employee_ids` in the domain, the final query leads to a bad plan where Postgres does a full Seq.Scan on `voip_call` to then post-filter based on `user_id`. To simplify the final query, we inline the ids that are being resolved from searching on `res.users.employee_id` (which is just a proxy for `res.users.employee_ids`). We also re-write the `ir.rule` to use this new inlining via `employee_id` and avoid using `employee_ids` which is resolved as a generic One2many from the ORM. This leads to a few more queries, but each is fast and trivial to process. Benchmark --------- On a database with over 10M `voip.call` and `res.users`, for a Hr Officer, to open the Phone's app default list view with no default filter (the default setup), took: | Before | After | Speed-up | |--------|-------|----------| | 13.3s | 80ms | 162x | Forward-Port-Of: odoo/enterprise#98098
WhatsApp users can now mark channels as favorites, making key conversations easier to find in the Discuss sidebar. This improves day-to-day navigation for teams that rely on WhatsApp channels to manage customer or operational conversations.
Original PR description
Enterprise counter-part. task-4113458 https://github.com/odoo/odoo/pull/232398
8 changes
Enhancements to existing features
The Phone app now opens much faster for HR officers by improving how access checks are handled behind the scenes. This reduces waiting time dramatically on large databases while keeping the same access behavior for users.
Original PR description
Description ----------- The rule `voip_call_hr_access_rule` is added with an `OR` to `voip_call_rule_user`, but with the presence of the `One2many` `employee_ids` in the domain, the final query leads to a bad plan where Postgres does a full Seq.Scan on `voip_call` to then post-filter based on `user_id`. To simplify the final query, we inline the ids that are being resolved from searching on `res.users.employee_id` (which is just a proxy for `res.users.employee_ids`). We also re-write the `ir.rule` to use this new inlining via `employee_id` and avoid using `employee_ids` which is resolved as a generic One2many from the ORM. This leads to a few more queries, but each is fast and trivial to process. Benchmark --------- On a database with over 10M `voip.call` and `res.users`, for a Hr Officer, to open the Phone's app default list view with no default filter (the default setup), took: | Before | After | Speed-up | |--------|-------|----------| | 13.3s | 80ms | 162x |
HR users can open the Phone app much faster on large databases. The access check was optimized to avoid slow database scanning, reducing load times from seconds to milliseconds in the benchmark.
Original PR description
Description ----------- The rule `voip_call_hr_access_rule` is added with an `OR` to `voip_call_rule_user`, but with the presence of the `One2many` `employee_ids` in the domain, the final query leads…
Description ----------- The rule `voip_call_hr_access_rule` is added with an `OR` to `voip_call_rule_user`, but with the presence of the `One2many` `employee_ids` in the domain, the final query leads to a bad plan where Postgres does a full Seq.Scan on `voip_call` to then post-filter based on `user_id`. To simplify the final query, we inline the ids that are being resolved from searching on `res.users.employee_id` (which is just a proxy for `res.users.employee_ids`). We also re-write the `ir.rule` to use this new inlining via `employee_id` and avoid using `employee_ids` which is resolved as a generic One2many from the ORM. This leads to a few more queries, but each is fast and trivial to process. Benchmark --------- On a database with over 10M `voip.call` and `res.users`, for a Hr Officer, to open the Phone's app default list view with no default filter (the default setup), took: | Before | After | Speed-up | |--------|-------|----------| | 13.3s | 80ms | 162x | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
VoIP browser tabs now try to unregister when closed and registrations expire sooner if cleanup does not happen. This helps customers avoid hitting provider limits on active phone registrations, especially when users open multiple Odoo tabs.
Original PR description
Some providers like OnSIP allow for a limited number of registrations per user. This is a problem in Odoo because each tab opened creates a new registration for one hour. This commit mitigates the problems in two ways: - Sends an "unregister" request onbeforeunload to try to invalidate the registration upon closing the tab. - Reduces the TTL of registrations so that they get invalidated quicker in case the unregistration failed. Forward-Port-Of: odoo/enterprise#98413 Forward-Port-Of: odoo/enterprise#97963
The mail call permission dialog has been resized to remove unnecessary empty space. This creates a cleaner, more focused experience when users are asked to grant call permissions.
Original PR description
**Purpose of this PR:** Reduce the size of the call permission dialog to eliminate extra empty space on the right side. **Before** <img width="1355" height="643" alt="image" src="https://github.com/user-attachments/assets/e8366841-d07e-4c05-8f88-8710631bfd57" /> **After** <img width="1901" height="932" alt="image" src="https://github.com/user-attachments/assets/9e13f665-8028-4c61-9170-9eaf9d3b00a0" /> task-[5091767](https://www.odoo.com/odoo/project.task/5091767) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Live chat transcripts now add spacing when the speaker changes, making saved conversation histories easier to read. This helps sales or support teams quickly understand the flow and context when reviewing chats in related records such as leads.
Original PR description
When converting a livechat session history into a description (e.g., for leads), messages from different authors were shown consecutively without separation, making it difficult to follow the conversation flow. This PR inserts a line break whenever the message author changes, making the transcript easier to read and providing clearer context shifts. Task-5217172 **Before:** <img width="530" height="463" alt="image" src="https://github.com/user-attachments/assets/29304bc5-d8e4-470a-adc0-bf6d1d963bcf" /> **After:** <img width="491" height="586" alt="image" src="https://github.com/user-attachments/assets/7a019672-84fa-457d-ae2f-48bb4a3506a3" /> --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Purchase catalog suggestions now show all recommended products on the first page when suggestions are enabled, instead of hiding some behind pagination. The change also improves performance and makes bulk adding suggestions respect the selected purchase order section.
Original PR description
Description of the issue/feature this PR addresses: Improves purchase catalog suggestions, adding a filter on products with `suggested_qty > 0` on suggestion toggle. This ensure all suggested products will be shown on the first catalog page Perf improvements on both front end (reducing number of RPCs) and backend (filtering domain as much as possible on search method). Current behavior before PR: Before, if there were more products than the paging limit, not all suggested product would be pulled to the front (couldn't order a view by a computed field.) Desired behavior after PR is merged: All suggested products are shown on first page. task#5114649 previous PR: odoo/odoo#218343 And separated all the refacto on a beanch on master: https://github.com/odoo/odoo/pull/232456 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The depreciation schedule report now defaults to the previous financial year instead of the previous month. This better matches how businesses typically use the report for year-end filings such as tax returns and BNB attachments.
Original PR description
The depreciation schedule report is usually is consulted to be attached to the BNB and/or tax return of a completed financial year. For an ongoing financial year, it has very little value. Therefore default opening of the depreciation schedule report is changed from previous month(default value) to previous year. task-5167082
Mass mailing now better supports older email templates during the move to Odoo 19. Users can still view legacy email content, receive clearer warnings when parts are outdated, and avoid several editing crashes.
Original PR description
This work's purpose is to prepare `mass_mailing` for the upcoming migration to Odoo 19.0. Existing mail content produced with the old editor is not upgraded, and users who end up editing such content must be informed if a snippet is not up to date. contents: - ensure that existing mail content with an obsolete mail HTML structure is properly displayed, even if the editor will not work at all, instead of showing the Theme Selector if no authorized theme is detected. - ensure that a user editing an obsolete snippet is informed and can change it to the new version - various crash fixes See commits messages for further detail. task-5134263
1 change
Enhancements to existing features
The Pakistan payroll localization has been updated with the latest 2026 income tax bracket values. This helps businesses calculate employee payroll taxes in line with the new requirements.
Original PR description
Tax brackets for pakistan localization has been updated to include the new values for 2026.
1 change
Enhancements to existing features
Stock availability calculations now avoid unnecessary repeated checks when many incoming and outgoing stock moves are linked. This can make large picking reports much faster, reducing wait times for users reviewing product availability.
Original PR description
Before this commit, computing `product_availability` and `product_availability_state` required calling the `get_report_lines` method from the `stock.forecasted_product_product` model. In pickings…
Before this commit, computing `product_availability` and `product_availability_state` required calling the `get_report_lines` method from the `stock.forecasted_product_product` model. In pickings containing moves linked to many incoming and outgoing moves, the `reconcile_out_with_ins` function caused performance issues. The reconciliation logic worked as follows: 1. For each `out_move`, attempt to match it with an `in_move` if the `in_move` references the `out_move` in its `move_dests`. 2. If the demand of the `out_move` is not fully satisfied, add it to `unreconciled_outs`. 3. Loop over `unreconciled_outs` (after attempting to reconcile them using the initial prodcedure) to reconcile against the remaining `in_moves`. The performance bottleneck was that even when an `in_move` directly referenced an `out_move`, the code would unnecessarily loop over **all** `in_moves` to filter out the `in_moves` that has the `out_move` in its `move_dest`. --- To improve performance, an **inverse mapping** from `out_move` IDs to their corresponding `in_moves` is introduced. - Reconciliation now starts by iterating only over the relevant `in_moves`. - If the demand is still unmet, the algorithm attempts reconciliation against the remaining `in_moves`. - This reduces the time complexity to **O(N + M)**, since `in_moves` with zero quantities are removed and never revisited. **Implementation details:** - An `OrderedSet` is used for the inverse mapping to preserve the original query order. - Benefits of `OrderedSet`: - **O(1)** removal (assuming no collisions) - Maintains insertion order, ensuring the same order as the query result. --- | Metric | Before PR | After PR | |---------------|-----------|----------| | Execution Time| ~90 sec | ~10 sec | The benchmark above is done on a `stock.picking` record that queried in the `_get_report_lines` method **5331** `out_moves` and **8922** `in_moves`. opw-4951469