Skip to content

[16.0][FIX] project_hr: Slowdown when entering the task tree view#1655

Open
iaranburu wants to merge 1 commit intoOCA:16.0from
binovo:feature-16.0-20235-Slowdown_when_entering_the_task_tree_view
Open

[16.0][FIX] project_hr: Slowdown when entering the task tree view#1655
iaranburu wants to merge 1 commit intoOCA:16.0from
binovo:feature-16.0-20235-Slowdown_when_entering_the_task_tree_view

Conversation

@iaranburu
Copy link
Copy Markdown

Odoo 16

When we have many projects, and each project has many tasks, accessing the task tree view from a project slows down the loading process.

This request corrects the calculation of the allowed_assigned_user_ids field so that it only performs one database access and uses filtering during task iteration.

@OCA-git-bot
Copy link
Copy Markdown
Contributor

Hi @pedrobaeza,
some modules you are maintaining are being modified, check this out!

Copy link
Copy Markdown

@luisDIXMIT luisDIXMIT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-commit is failing, maybe because you didn’t run it previously. Run it locally to fix the formatting and push it again.

Copy link
Copy Markdown
Contributor

@alexey-pelykh alexey-pelykh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good optimization idea — batching the search instead of one per record is the right approach for computed fields.

Pre-commit is currently failing though, so that needs a pass before this can move forward. Also, the early return when all_category_ids is empty sets the field on the full recordset, which is fine, but you might also want to handle the case where a task has hr_category_ids populated but company_id is falsy (edge case).

user_obj = self.env["res.users"]
all_category_ids = self.mapped('hr_category_ids').ids
all_company_ids = self.mapped('company_id').ids
if not all_category_ids:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When all_category_ids is empty, you set self.allowed_assigned_user_ids = False and return early. But you should still iterate the tasks to handle the else branch individually — a task might have no categories but another in the batch might. Actually, looking again, if all_category_ids is empty it means NO task in self has categories, so the early return is correct. Disregard this, the logic is fine.

Copy link
Copy Markdown
Contributor

@alexey-pelykh alexey-pelykh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Performance optimization for _compute_allowed_assigned_user_ids

Good approach -- replacing N individual search() calls with a single batched search + in-memory filtering is the right pattern for Odoo computed fields. The performance improvement should be significant when computing across many tasks.

However, there is a behavioral regression and some issues to address before this can be merged.

Behavioral Regression (blocking)

In the original code, when a task has no hr_category_ids, the domain is [] and user_obj.search([]) returns all users -- meaning allowed_assigned_user_ids is populated with every user. In the new code, the else branch sets task.allowed_assigned_user_ids = False (empty recordset). This changes the behavior: tasks without HR categories would show no allowed users instead of all users, potentially breaking the UI for task assignment.

Please restore the original behavior for the no-categories case:

else:
    task.allowed_assigned_user_ids = self.env["res.users"].search([])

Or, better yet, cache that full user list outside the loop so it is only fetched once.

Pre-commit failure (blocking)

CI shows pre-commit is still failing. Please run pre-commit run --all-files locally and push the fixes.

Minor: string quoting style

The new code uses single quotes ('hr_category_ids', 'company_id') while the rest of the file uses double quotes. OCA convention and the existing code style in this file use double quotes -- please align for consistency.

Suggestion: consider performance of filtered() lambda

The filtered() lambda iterates u.employee_ids.category_ids and u.employee_ids for every user in all_users for every task. If the number of users is large, this could still be slow. Consider building a mapping dict (user -> set of (company_id, category_ids)) before the loop for O(1) lookups per task-user pair.

Overall, the optimization direction is correct. Please fix the behavioral regression and pre-commit issues.

Review posted via CorporateHub OCA review campaign

task.allowed_assigned_user_ids = user_obj.search(domain)
task.allowed_assigned_user_ids = all_users.filtered(
lambda u: any(cat in task.hr_category_ids for cat in u.employee_ids.category_ids)
and any(emp.company_id == task.company_id for emp in u.employee_ids)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Behavioral regression: When task.hr_category_ids is falsy, the original code ran user_obj.search([]) which returns all users. Setting False here changes the behavior -- tasks without HR categories would show no allowed users instead of all users.

Please restore:

else:
    task.allowed_assigned_user_ids = self.env["res.users"].search([])

Or cache the full user list outside the loop to avoid a per-task search.

@api.depends("hr_category_ids", "company_id")
def _compute_allowed_assigned_user_ids(self):
user_obj = self.env["res.users"]
all_category_ids = self.mapped('hr_category_ids').ids
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: single quotes here ('hr_category_ids') while the rest of the file uses double quotes. Please use double quotes for consistency with OCA style conventions.

Suggested change
all_category_ids = self.mapped('hr_category_ids').ids
all_category_ids = self.mapped("hr_category_ids").ids
all_company_ids = self.mapped("company_id").ids

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants