From 332b83ef9eb231d1f7329781685151b08fc11088 Mon Sep 17 00:00:00 2001 From: Hiral Bhavsar Date: Fri, 21 Apr 2017 15:37:27 +0530 Subject: [PATCH] [IMP] project, *_timesheet: move subtasks to project -> Move Subtasks mechanism from hr_timesheet to project. -> Various functional improvements: - Add new 'Sub-tasks' setting and 'Sub-task Project' field based on this setting. - Relabel 'Team Collaboration' section to 'Task Management'. - Remove 'Customer Satisfaction' section and move setting 'Rating on Tasks' into 'Task Management' section. - Add customer name on the project's kanban view. - Set default value of 'Sub-task Project' field is the same project. - Add 'Parent Task' stat button on task form view. - Make 'Sub-Tasks' stat button visible when no parent task --- addons/hr_timesheet/models/project.py | 19 -------- addons/hr_timesheet/views/project_views.xml | 31 ------------ addons/project/models/project.py | 29 ++++++++++++ addons/project/models/res_config.py | 1 + addons/project/security/project_security.xml | 5 ++ addons/project/views/project_views.xml | 31 ++++++++++++ addons/project/views/res_config_views.xml | 50 ++++++++++++-------- addons/sale_timesheet/models/product.py | 2 +- 8 files changed, 96 insertions(+), 72 deletions(-) diff --git a/addons/hr_timesheet/models/project.py b/addons/hr_timesheet/models/project.py index 400d5aedc6f..a2b7a9c25e4 100644 --- a/addons/hr_timesheet/models/project.py +++ b/addons/hr_timesheet/models/project.py @@ -8,19 +8,11 @@ from odoo.exceptions import UserError class Project(models.Model): _inherit = "project.project" - subtask_project_id = fields.Many2one( - 'project.project', string='Sub-task Project', ondelete="restrict", - help="Choosing a sub-tasks project will both enable sub-tasks and set their default project (possibly the project itself)") allow_timesheets = fields.Boolean("Allow timesheets", default=True) class Task(models.Model): _inherit = "project.task" - @api.multi - def _get_subtask_count(self): - for task in self: - task.subtask_count = self.search_count([('id', 'child_of', task.id), ('id', '!=', task.id)]) - @api.depends('stage_id', 'timesheet_ids.unit_amount', 'planned_hours', 'child_ids.stage_id', 'child_ids.planned_hours', 'child_ids.effective_hours', 'child_ids.children_hours', 'child_ids.timesheet_ids.unit_amount') def _hours_get(self): @@ -55,15 +47,4 @@ class Task(models.Model): children_hours = fields.Float(compute='_hours_get', store=True, string='Sub-tasks Hours', help="Sum of the planned hours of all sub-tasks (when a sub-task is closed or its spent hours exceed its planned hours, spent hours are counted instead)") timesheet_ids = fields.One2many('account.analytic.line', 'task_id', 'Timesheets') - parent_id = fields.Many2one('project.task', string='Parent Task') - child_ids = fields.One2many('project.task', 'parent_id', string="Sub-tasks") - subtask_project_id = fields.Many2one('project.project', related="project_id.subtask_project_id", string='Sub-task Project', readonly=True) - subtask_count = fields.Integer(compute='_get_subtask_count', type='integer', string="Sub-task count") - _constraints = [(models.BaseModel._check_recursion, 'Circular references are not permitted between tasks and sub-tasks', ['parent_id'])] - - @api.constrains('parent_id') - def _check_subtask_project(self): - for task in self: - if task.parent_id and task.parent_id.project_id and task.project_id and task.project_id != task.parent_id.project_id.subtask_project_id: - raise UserError(_("You can't define a parent task if its project is not correctly configured. The sub-task's project of the parent task's project should be this task's project")) diff --git a/addons/hr_timesheet/views/project_views.xml b/addons/hr_timesheet/views/project_views.xml index f799cc5b76e..7886e39b870 100644 --- a/addons/hr_timesheet/views/project_views.xml +++ b/addons/hr_timesheet/views/project_views.xml @@ -45,9 +45,6 @@ - - -
@@ -57,46 +54,18 @@ - - Sub-tasks - project.task - kanban,tree,form,calendar,pivot,graph - [('id', 'child_of', active_id), ('id', '!=', active_id)] - - { - 'default_parent_id' : active_id, - 'default_project_id' : project_id, - 'default_name' : name + ':', - 'default_partner_id' : partner_id, - } - - - - project.task.form.inherited project.task - - - - - - - diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 2d243e7de78..c111be7e549 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -219,6 +219,8 @@ class Project(models.Model): doc_count = fields.Integer(compute='_compute_attached_docs_count', string="Number of documents attached") date_start = fields.Date(string='Start Date') date = fields.Date(string='Expiration Date', index=True, track_visibility='onchange') + subtask_project_id = fields.Many2one('project.project', string='Sub-task Project', ondelete="restrict", + help="Choosing a sub-tasks project will both enable sub-tasks and set their default project (possibly the project itself)") _sql_constraints = [ ('project_date_greater', 'check(date >= date_start)', 'Error! project start-date must be lower than project end-date.') @@ -256,6 +258,8 @@ class Project(models.Model): # Prevent double project creation when 'use_tasks' is checked self = self.with_context(project_creation_in_progress=True, mail_create_nosubscribe=True) project = super(Project, self).create(vals) + if not vals.get('subtask_project_id'): + project.subtask_project_id = project.id if project.privacy_visibility == 'portal' and project.partner_id: project.message_subscribe(project.partner_id.ids) return project @@ -411,6 +415,10 @@ class Task(models.Model): legend_blocked = fields.Char(related='stage_id.legend_blocked', string='Kanban Blocked Explanation', readonly=True) legend_done = fields.Char(related='stage_id.legend_done', string='Kanban Valid Explanation', readonly=True) legend_normal = fields.Char(related='stage_id.legend_normal', string='Kanban Ongoing Explanation', readonly=True) + parent_id = fields.Many2one('project.task', string='Parent Task') + child_ids = fields.One2many('project.task', 'parent_id', string="Sub-tasks") + subtask_project_id = fields.Many2one('project.project', related="project_id.subtask_project_id", string='Sub-task Project', readonly=True) + subtask_count = fields.Integer(compute='_compute_subtask_count', type='integer', string="Sub-task count") @api.onchange('project_id') def _onchange_project(self): @@ -438,6 +446,17 @@ class Task(models.Model): default['remaining_hours'] = self.planned_hours return super(Task, self).copy(default) + @api.multi + def _compute_subtask_count(self): + for task in self: + task.subtask_count = self.search_count([('id', 'child_of', task.id), ('id', '!=', task.id)]) + + @api.constrains('parent_id') + def _check_subtask_project(self): + for task in self: + if task.parent_id.project_id and task.project_id != task.parent_id.project_id.subtask_project_id: + raise UserError(_("You can't define a parent task if its project is not correctly configured. The sub-task's project of the parent task's project should be this task's project")) + @api.constrains('date_start', 'date_end') def _check_dates(self): if any(self.filtered(lambda task: task.date_start and task.date_end and task.date_start > task.date_end)): @@ -685,6 +704,16 @@ class Task(models.Model): res['headers'] = repr(headers) return res + def action_open_parent_task(self): + return { + 'name': _('Parent Task'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'project.task', + 'res_id': self.parent_id.id, + 'type': 'ir.actions.act_window' + } + class AccountAnalyticAccount(models.Model): _inherit = 'account.analytic.account' diff --git a/addons/project/models/res_config.py b/addons/project/models/res_config.py index ebae91c8546..a06d3bf2190 100644 --- a/addons/project/models/res_config.py +++ b/addons/project/models/res_config.py @@ -25,6 +25,7 @@ class ProjectConfiguration(models.TransientModel): module_sale_timesheet = fields.Boolean("Time Billing") module_hr_expense = fields.Boolean("Expenses") module_project_issue = fields.Boolean("Issue Tracking") + group_subtask_project = fields.Boolean("Sub-tasks", implied_group="project.group_subtask_project") @api.multi def set_default_generate_project_alias(self): diff --git a/addons/project/security/project_security.xml b/addons/project/security/project_security.xml index eea59a61459..680d459bd82 100644 --- a/addons/project/security/project_security.xml +++ b/addons/project/security/project_security.xml @@ -19,6 +19,11 @@ + + Use Subtask Project + + + diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml index db7c2a38210..3c6d7f73759 100644 --- a/addons/project/views/project_views.xml +++ b/addons/project/views/project_views.xml @@ -80,6 +80,23 @@ + + Sub-tasks + project.task + kanban,tree,form,calendar,pivot,graph + [('id', 'child_of', active_id), ('id', '!=', active_id)] + + { + 'default_parent_id' : active_id, + 'default_project_id' : project_id, + 'default_name' : name + ':', + 'default_partner_id' : partner_id, + 'search_default_project_id': [project_id], + } + + + + project.project.form @@ -121,6 +138,7 @@ + @@ -239,6 +257,7 @@ + @@ -256,6 +275,9 @@
+ + +
@@ -353,6 +375,12 @@ action = model.activate_sample_project()
+
-

Customer Satisfaction

-
-
-
- -
-
-
-
-

Issue Management

diff --git a/addons/sale_timesheet/models/product.py b/addons/sale_timesheet/models/product.py index 3d7b65ab2d5..a863bef3805 100644 --- a/addons/sale_timesheet/models/product.py +++ b/addons/sale_timesheet/models/product.py @@ -8,7 +8,7 @@ class ProductTemplate(models.Model): _inherit = 'product.template' track_service = fields.Selection(selection_add=[ - ('timesheet', 'Timesheets on project'), + ('timesheet', 'Timesheets on project (one fare per SO/Project)'), ('task', 'Create a task per order line to track hours')]) project_id = fields.Many2one( 'project.project', 'Project', company_dependent=True,