_*: hr_timesheet,sale_project,sale_timesheet Generally, you don't want subtasks to be displayed at the same level as their parent tasks. You want to consider the subtasks as part of their parent's project, but don't want to see them directly in this project. Rather, you want them to be accessible only via their parent. (There are exceptions to that and we want to stay flexible.) First solution that comes to mind is to have `project_id` set to False for the latter tasks, but then how to get the value of the fields that are related to the project? So, second solution would be to have a field `project_root_id`, which would be the project of the parent, or the grand-parent, etc. The issue now is that we have to fields "project", and it isn't obvious when to use one or the other. The most simple way to answer this need is to keep one field "project", that will always be set for (non-private) tasks, and create a boolean field : `display_in_project`. But we want it to be technical (no checkbox in the view). So, when the user unsets the project on a subtask, the view will act as if the project was unset, but in the back-end, we'll set `display_in_project` to False and set `project_id` back. The fact that all tasks have a project allows us to know if action x can be perform on this task t, dependind on t.project_id.allow_x. task-3367246 closes odoo/odoo#128281 Related: odoo/enterprise#43996 Related: odoo/upgrade#4930 Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com>
140 lines
6.0 KiB
Python
140 lines
6.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
import logging
|
|
import collections
|
|
|
|
from odoo import models, Command
|
|
from odoo.tools import populate
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
class ProjectStage(models.Model):
|
|
_inherit = "project.task.type"
|
|
_populate_sizes = {"small": 10, "medium": 50, "large": 500}
|
|
|
|
def _populate_factories(self):
|
|
return [
|
|
("name", populate.constant('stage_{counter}')),
|
|
("sequence", populate.randomize([False] + [i for i in range(1, 101)])),
|
|
("description", populate.constant('project_stage_description_{counter}')),
|
|
("active", populate.randomize([True, False], [0.8, 0.2])),
|
|
("fold", populate.randomize([True, False], [0.9, 0.1]))
|
|
]
|
|
|
|
class ProjectProject(models.Model):
|
|
_inherit = "project.project"
|
|
_populate_sizes = {"small": 10, "medium": 50, "large": 1000}
|
|
_populate_dependencies = ["res.company", "project.task.type"]
|
|
|
|
def _populate_factories(self):
|
|
company_ids = self.env.registry.populated_models["res.company"]
|
|
stage_ids = self.env.registry.populated_models["project.task.type"]
|
|
|
|
def get_company_id(random, **kwargs):
|
|
return random.choice(company_ids)
|
|
# user_ids from company.user_ids ?
|
|
# Also add a partner_ids on res_company ?
|
|
|
|
def get_stage_ids(random, **kwargs):
|
|
return [
|
|
(6, 0, [
|
|
random.choice(stage_ids)
|
|
for i in range(random.choice([j for j in range(1, 10)]))
|
|
])
|
|
]
|
|
|
|
return [
|
|
("name", populate.constant('project_{counter}')),
|
|
("sequence", populate.randomize([False] + [i for i in range(1, 101)])),
|
|
("active", populate.randomize([True, False], [0.8, 0.2])),
|
|
("company_id", populate.compute(get_company_id)),
|
|
("type_ids", populate.compute(get_stage_ids)),
|
|
('color', populate.randomize([False] + [i for i in range(1, 7)])),
|
|
# TODO user_id but what about multi-company coherence ??
|
|
]
|
|
|
|
|
|
class ProjectTask(models.Model):
|
|
_inherit = "project.task"
|
|
_populate_sizes = {"small": 500, "medium": 5000, "large": 50000}
|
|
_populate_dependencies = ["project.project", "res.partner", "res.users"]
|
|
|
|
def _populate_factories(self):
|
|
project_ids = self.env.registry.populated_models["project.project"]
|
|
stage_ids = self.env.registry.populated_models["project.task.type"]
|
|
user_ids = self.env.registry.populated_models['res.users']
|
|
partner_ids_per_company_id = {
|
|
company.id: ids
|
|
for company, ids in self.env['res.partner']._read_group(
|
|
[('company_id', '!=', False), ('id', 'in', self.env.registry.populated_models["res.partner"])],
|
|
['company_id'],
|
|
['id:array_agg'],
|
|
)
|
|
}
|
|
company_id_per_project_id = {
|
|
record['id']: record['company_id']
|
|
for record in self.env['project.project'].search_read(
|
|
[('company_id', '!=', False), ('id', 'in', self.env.registry.populated_models["project.project"])],
|
|
['company_id'],
|
|
load=False
|
|
)
|
|
}
|
|
partner_ids_per_project_id = {
|
|
project_id: partner_ids_per_company_id[company_id]
|
|
for project_id, company_id in company_id_per_project_id.items()
|
|
}
|
|
def get_project_id(random, **kwargs):
|
|
return random.choice([False, False, False] + project_ids)
|
|
def get_stage_id(random, **kwargs):
|
|
return random.choice([False, False] + stage_ids)
|
|
def get_partner_id(random, **kwargs):
|
|
project_id = kwargs['values'].get('project_id')
|
|
partner_ids = partner_ids_per_project_id.get(project_id, False)
|
|
return partner_ids and random.choice(partner_ids + [False] * len(partner_ids))
|
|
def get_user_ids(values, counter, random):
|
|
return [Command.set([random.choice(user_ids) for i in range(random.randint(0, 3))])]
|
|
|
|
return [
|
|
("name", populate.constant('project_task_{counter}')),
|
|
("sequence", populate.randomize([False] + [i for i in range(1, 101)])),
|
|
("active", populate.randomize([True, False], [0.8, 0.2])),
|
|
("color", populate.randomize([False] + [i for i in range(1, 7)])),
|
|
("state", populate.randomize(['01_in_progress', '03_approved', '02_changes_requested', '1_done', '1_canceled'])),
|
|
("project_id", populate.compute(get_project_id)),
|
|
("stage_id", populate.compute(get_stage_id)),
|
|
('partner_id', populate.compute(get_partner_id)),
|
|
('user_ids', populate.compute(get_user_ids)),
|
|
]
|
|
|
|
def _populate(self, size):
|
|
records = super()._populate(size)
|
|
# set parent_ids
|
|
self._populate_set_children_tasks(records)
|
|
return records
|
|
|
|
def _populate_set_children_tasks(self, tasks):
|
|
_logger.info('Setting parent tasks')
|
|
rand = populate.Random('project.task+children_generator')
|
|
task_ids_per_company = collections.defaultdict(set)
|
|
for task in tasks:
|
|
if task.project_id:
|
|
task_ids_per_company[task.company_id].add(task.id)
|
|
|
|
for task_ids in task_ids_per_company.values():
|
|
parent_ids = set()
|
|
for task_id in task_ids:
|
|
if not rand.getrandbits(4):
|
|
parent_ids.add(task_id)
|
|
child_ids = task_ids - parent_ids
|
|
parent_ids = list(parent_ids)
|
|
|
|
child_ids_per_parent_id = collections.defaultdict(set)
|
|
for child_id in child_ids:
|
|
if not rand.getrandbits(4):
|
|
child_ids_per_parent_id[rand.choice(parent_ids)].add(child_id)
|
|
|
|
for count, (parent_id, child_ids) in enumerate(child_ids_per_parent_id.items()):
|
|
if (count + 1) % 100 == 0:
|
|
_logger.info('Setting parent: %s/%s', count + 1, len(child_ids_per_parent_id))
|
|
self.browse(child_ids).write({'parent_id': parent_id})
|