[IMP] project: Allow multi levels on sub-tasks

Purpose
=======

Currently, it is only possible to have 1 level of sub-tasks per task.
The user may want several levels of granurality.

Specifications
==============

Allow having multi levels of sub-tasks
- Move the parent_id field out of the debug mode and display it above the
  Deadline field
- Remove the 'parent task' stat button
- Add the parent_id field to the project.task optional list view
- Display the sub-tasks stat button on sub-tasks
- The 'sub-tasks' stat button should only count/display tasks from the
  first level of sub-tasks
- The name of the sub-task should be
  parent task: sub task level 1: sub task level 2: sub task level 3...
- The sub-task should be created in the sub-task project set on the
  parent task's project
- The subtask_planned_hours and the subtask_effective_hours fields should
  take into account the planned hours of all sub-level tasks

TaskID: 2107078
This commit is contained in:
Yannick Tivisse
2019-11-22 09:29:43 +00:00
parent 342ffbc57e
commit f34f6ee3b6
2 changed files with 22 additions and 32 deletions
+9 -17
View File
@@ -588,15 +588,12 @@ class Task(models.Model):
@api.depends('child_ids.planned_hours')
def _compute_subtask_planned_hours(self):
for task in self:
task.subtask_planned_hours = sum(task.child_ids.mapped('planned_hours'))
task.subtask_planned_hours = sum(child_task.planned_hours + child_task.subtask_planned_hours for child_task in task.child_ids)
@api.depends('child_ids')
def _compute_subtask_count(self):
""" Note: since we accept only one level subtask, we can use a read_group here """
task_data = self.env['project.task'].read_group([('parent_id', 'in', self.ids)], ['parent_id'], ['parent_id'])
mapping = dict((data['parent_id'][0], data['parent_id_count']) for data in task_data)
for task in self:
task.subtask_count = mapping.get(task.id, 0)
task.subtask_count = len(self._get_all_subtasks())
@api.onchange('project_id')
def _onchange_project(self):
@@ -882,21 +879,17 @@ class Task(models.Model):
def action_assign_to_me(self):
self.write({'user_id': self.env.user.id})
def action_open_parent_task(self):
return {
'name': _('Parent Task'),
'view_mode': 'form',
'res_model': 'project.task',
'res_id': self.parent_id.id,
'type': 'ir.actions.act_window',
'context': dict(self._context, create=False)
}
def _get_all_subtasks(self):
children = self.mapped('child_ids')
if not children:
return self.env['project.task']
return children + children._get_all_subtasks()
def action_subtask(self):
action = self.env.ref('project.project_task_action_sub_task').read()[0]
# only display subtasks of current task
action['domain'] = [('id', 'child_of', self.id), ('id', '!=', self.id)]
# display all subtasks of current task
action['domain'] = [('id', 'in', self._get_all_subtasks().ids)]
# update context, with all default values as 'quick_create' does not contains all field in its view
if self._context.get('default_project_id'):
@@ -908,7 +901,6 @@ class Task(models.Model):
'default_name': self.env.context.get('name', self.name) + ':',
'default_parent_id': self.id, # will give default subtask field in `default_get`
'default_company_id': default_project.company_id.id if default_project else self.env.company.id,
'search_default_parent_id': self.id,
})
action['context'] = ctx
+13 -15
View File
@@ -76,7 +76,7 @@
<record id="project_task_action_sub_task" model="ir.actions.act_window">
<field name="name">Sub-tasks</field>
<field name="res_model">project.task</field>
<field name="view_mode">kanban,tree,form,calendar,pivot,graph,activity</field>
<field name="view_mode">tree,kanban,form,calendar,pivot,graph,activity</field>
<field name="search_view_id" ref="project.view_task_search_form"/>
</record>
@@ -451,9 +451,8 @@
</header>
<sheet string="Task">
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" icon="fa-tasks" type="object" name="action_open_parent_task" string="Parent Task" attrs="{'invisible' : [('parent_id', '=', False)]}" groups="project.group_subtask_project"/>
<button name="action_subtask" type="object" class="oe_stat_button" icon="fa-tasks"
attrs="{'invisible' : ['|', ('parent_id', '!=', False), ('id', '=', False)]}" context="{'default_user_id': user_id, 'default_parent_id': id, 'default_project_id': subtask_project_id}" groups="project.group_subtask_project">
attrs="{'invisible' : [('id', '=', False)]}" context="{'default_user_id': user_id, 'default_parent_id': id, 'default_project_id': subtask_project_id}" groups="project.group_subtask_project">
<field string="Sub-tasks" name="subtask_count" widget="statinfo"/>
</button>
<button name="%(rating_rating_action_task)d" type="action" attrs="{'invisible': [('rating_count', '=', 0)]}" class="oe_stat_button" icon="fa-smile-o" groups="project.group_project_rating">
@@ -483,14 +482,17 @@
<field name="user_id"
class="o_task_user_field"
options='{"no_open": True}'/>
<field
name="parent_id"
domain="[('parent_id', '=', False)]"
groups="project.group_subtask_project"
/>
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
</group>
<group name="sales_order_group">
</group>
<group>
<group name="dates">
<field name="date_deadline"/>
</group>
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
<group name="dates">
<field name="date_deadline"/>
</group>
</group>
<notebook>
@@ -504,12 +506,6 @@
<field name="sequence" groups="base.group_no_one"/>
<field name="email_from" invisible="1"/>
<field name="email_cc" groups="base.group_no_one"/>
<field
name="parent_id"
domain="[('parent_id', '=', False)]"
attrs="{'invisible' : [('subtask_count', '>', 0)]}"
groups="project.group_subtask_project"
/>
<field name="child_ids" invisible="1" />
<field name="subtask_project_id" invisible="1" />
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
@@ -678,9 +674,11 @@
<tree decoration-bf="message_needaction==True" decoration-danger="date_deadline and (date_deadline&lt;current_date)" string="Tasks">
<field name="message_needaction" invisible="1"/>
<field name="sequence" invisible="not context.get('seq_visible', False)"/>
<field name="name"/>
<field name="name"/>
<!-- YTI TODO user_invisible and seq_visible seem to be useless -->
<field name="project_id" invisible="context.get('user_invisible', False)" optional="show"/>
<field name="partner_id" optional="hide"/>
<field name="parent_id" groups="project.group_subtask_project" optional="show"/>
<field name="user_id" invisible="context.get('user_invisible', False)" optional="show"/>
<field name="date_deadline" optional="hide"/>
<field name="stage_id" invisible="context.get('set_visible',False)" optional="show"/>