diff options
| -rw-r--r-- | addons/project/models/project.py | 85 | ||||
| -rw-r--r-- | addons/project/views/project_views.xml | 7 | ||||
| -rw-r--r-- | addons/sale_timesheet/models/project.py | 33 |
3 files changed, 63 insertions, 62 deletions
diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 9629d9c7d5a..53a5befe9f1 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -436,9 +436,13 @@ class Task(models.Model): @api.model def default_get(self, fields_list): result = super(Task, self).default_get(fields_list) - # force some parent values, if needed - if 'parent_id' in result and result['parent_id']: - result.update(self._subtask_values_from_parent(result['parent_id'])) + # find default value from parent for the not given ones + parent_task_id = result.get('parent_id') or self._context.get('default_parent_id') + if parent_task_id: + parent_values = self._subtask_values_from_parent(parent_task_id) + for fname, value in parent_values.items(): + if fname not in result: + result[fname] = value return result @api.model @@ -538,11 +542,6 @@ class Task(models.Model): # customer portal: include comment and incoming emails in communication history website_message_ids = fields.One2many(domain=lambda self: [('model', '=', self._name), ('message_type', 'in', ['email', 'comment'])]) - @api.constrains('parent_id') - def _check_parent_id(self): - if not self._check_recursion(): - raise ValidationError(_('You cannot create recursive tasks.')) - def _compute_attachment_ids(self): for task in self: attachment_ids = self.env['ir.attachment'].search([('res_id', '=', task.id), ('res_model', '=', 'project.task')]).ids @@ -619,14 +618,17 @@ class Task(models.Model): @api.onchange('parent_id') def _onchange_parent_id(self): if self.parent_id: - for field_name in self._subtask_implied_fields(): - self[field_name] = self.parent_id[field_name] + for field_name, value in self._subtask_values_from_parent(self.parent_id.id).items(): + if not self[field_name]: + self[field_name] = value @api.onchange('project_id') def _onchange_project(self): if self.project_id: - if not self.parent_id and self.project_id.partner_id: + # find partner + if self.project_id.partner_id: self.partner_id = self.project_id.partner_id + # find stage if self.project_id not in self.stage_id.project_ids: self.stage_id = self.stage_find(self.project_id.id, [('fold', '=', False)]) # keep multi company consistency @@ -709,10 +711,6 @@ class Task(models.Model): def create(self, vals): # context: no_log, because subtype already handle this context = dict(self.env.context) - # force some parent values, if needed - if 'parent_id' in vals and vals['parent_id']: - vals.update(self._subtask_values_from_parent(vals['parent_id'])) - context.pop('default_parent_id', None) # for default stage if vals.get('project_id') and not context.get('default_project_id'): context['default_project_id'] = vals.get('project_id') @@ -723,14 +721,16 @@ class Task(models.Model): if vals.get('stage_id'): vals.update(self.update_date_end(vals['stage_id'])) vals['date_last_stage_update'] = fields.Datetime.now() + # substask default values + if vals.get('parent_id'): + for fname, value in self._subtask_values_from_parent(vals['parent_id']).items(): + if fname not in vals: + vals[fname] = value task = super(Task, self.with_context(context)).create(vals) return task def write(self, vals): now = fields.Datetime.now() - # subtask: force some parent values, if needed - if 'parent_id' in vals and vals['parent_id']: - vals.update(self._subtask_values_from_parent(vals['parent_id'])) # stage change: update date_last_stage_update if 'stage_id' in vals: vals.update(self.update_date_end(vals['stage_id'])) @@ -746,12 +746,6 @@ class Task(models.Model): # rating on stage if 'stage_id' in vals and vals.get('stage_id'): self.filtered(lambda x: x.project_id.rating_status == 'stage')._send_task_rating_mail(force_send=True) - # subtask: update subtask according to parent values - subtask_values_to_write = self._subtask_write_values(vals) - if subtask_values_to_write: - subtasks = self.filtered(lambda task: not task.parent_id).mapped('child_ids') - if subtasks: - subtasks.write(subtask_values_to_write) return result def update_date_end(self, stage_id): @@ -764,27 +758,18 @@ class Task(models.Model): # Subtasks # --------------------------------------------------- - @api.model - def _subtask_implied_fields(self): - """ Return the list of field name to apply on subtask when changing parent_id or when updating parent task. """ + def _subtask_default_fields(self): + """ Return the list of field name for default value when creating a subtask """ return ['partner_id', 'email_from'] - def _subtask_write_values(self, values): - """ Return the values to write on subtask when `values` is written on parent tasks - :param values: dict of values to write on parent - """ - result = {} - for field_name in self._subtask_implied_fields(): - if field_name in values: - result[field_name] = values[field_name] - return result - def _subtask_values_from_parent(self, parent_id): """ Get values for substask implied field of the given""" result = {} parent_task = self.env['project.task'].browse(parent_id) - for field_name in self._subtask_implied_fields(): + for field_name in self._subtask_default_fields(): result[field_name] = parent_task[field_name] + # special case for the subtask default project + result['project_id'] = parent_task.project_id.subtask_project_id return self._convert_to_write(result) # --------------------------------------------------- @@ -942,16 +927,28 @@ class Task(models.Model): def action_subtask(self): action = self.env.ref('project.project_task_action_sub_task').read()[0] - ctx = self.env.context.copy() + + # only display subtasks of current task + action['domain'] = [('id', 'child_of', self.id), ('id', '!=', self.id)] + + # update context, with all default values as 'quick_create' does not contains all field in its view + if self._context.get('default_project_id'): + default_project = self.env['project.project'].browse(self.env.context['default_project_id']) + else: + default_project = self.project_id.subtask_project_id or self.project_id + ctx = dict(self.env.context) ctx.update({ - 'default_parent_id': self.id, - 'default_project_id': self.env.context.get('project_id', self.project_id.id), 'default_name': self.env.context.get('name', self.name) + ':', - 'default_partner_id': self.env.context.get('partner_id', self.partner_id.id), - 'search_default_project_id': self.env.context.get('project_id', self.project_id.id), + '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, }) + parent_values = self._subtask_values_from_parent(self.id) + for fname, value in parent_values.items(): + if 'default_' + fname not in ctx: + ctx['default_' + fname] = value action['context'] = ctx - action['domain'] = [('id', 'child_of', self.id), ('id', '!=', self.id)] + return action # --------------------------------------------------- diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml index 7940111441a..f8abdfd8e80 100644 --- a/addons/project/views/project_views.xml +++ b/addons/project/views/project_views.xml @@ -22,6 +22,7 @@ <field name="partner_id" operator="child_of"/> <field name="stage_id"/> <field name="project_id"/> + <field name="parent_id" groups="project.group_subtask_project"/> <filter string="My Tasks" name="my_tasks" domain="[('user_id', '=', uid)]"/> <filter string="Followed Tasks" name="my_followed_tasks" domain="[('message_is_follower', '=', True)]" /> <filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/> @@ -449,8 +450,7 @@ <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)]}" - context="{'project_id': subtask_project_id, 'name': name, 'partner_id': partner_id}" groups="project.group_subtask_project"> + 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"> <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"> @@ -490,7 +490,7 @@ <group> <group> <field name="sequence" groups="base.group_no_one"/> - <field name="partner_id" attrs="{'readonly': [('parent_id', '!=', False)]}"/> + <field name="partner_id"/> <field name="email_from" invisible="1"/> <field name="email_cc" groups="base.group_no_one"/> <field name="parent_id" attrs="{'invisible' : [('subtask_count', '>', 0)]}" groups="project.group_subtask_project"/> @@ -542,6 +542,7 @@ <group> <field name="name" string = "Task Title"/> <field name="user_id" options="{'no_open': True,'no_create': True}"/> + <field name="parent_id" invisible="1"/> </group> </form> </field> diff --git a/addons/sale_timesheet/models/project.py b/addons/sale_timesheet/models/project.py index d611d47fbeb..d46303097f7 100644 --- a/addons/sale_timesheet/models/project.py +++ b/addons/sale_timesheet/models/project.py @@ -183,10 +183,15 @@ class ProjectTask(models.Model): @api.onchange('project_id') def _onchange_project(self): result = super(ProjectTask, self)._onchange_project() - if self.project_id.sale_line_id: - self.sale_line_id = self.project_id.sale_line_id - if not self.parent_id and not self.partner_id: - self.partner_id = self.sale_line_id.order_partner_id + if self.project_id: + if self.project_id.billable_type == 'employee_rate': + if not self.partner_id: + self.partner_id = self.project_id.sale_order_id.partner_id + elif self.project_id.billable_type == 'task_rate': + if not self.sale_line_id: + self.sale_line_id = self.project_id.sale_line_id + if not self.partner_id: + self.partner_id = self.sale_line_id.order_partner_id # set domain on SO: on non billable project, all SOL of customer, otherwise the one from the SO result = result or {} domain = [('is_service', '=', True), ('is_expense', '=', False), ('order_partner_id', 'child_of', self.partner_id.commercial_partner_id.id), ('state', 'in', ['sale', 'done'])] @@ -205,6 +210,13 @@ class ProjectTask(models.Model): result.setdefault('domain', {})['sale_line_id'] = [('is_service', '=', True), ('is_expense', '=', False), ('order_partner_id', 'child_of', self.partner_id.commercial_partner_id.id), ('state', 'in', ['sale', 'done'])] return result + @api.onchange('parent_id') + def _onchange_parent_id(self): + super(ProjectTask, self)._onchange_parent_id() + # check sale_line_id and customer are coherent + if self.sale_line_id and self.partner_id != self.sale_line_id.order_partner_id: + self.sale_line_id = False + @api.constrains('sale_line_id') def _check_sale_line_type(self): for task in self.sudo(): @@ -229,19 +241,10 @@ class ProjectTask(models.Model): # --------------------------------------------------- @api.model - def _subtask_implied_fields(self): - result = super(ProjectTask, self)._subtask_implied_fields() + def _subtask_default_fields(self): + result = super(ProjectTask, self)._subtask_default_fields() return result + ['sale_line_id'] - def _subtask_write_values(self, values): - result = super(ProjectTask, self)._subtask_write_values(values) - # changing the partner on a task will reset the sale line of its subtasks - if 'partner_id' in result: - result['sale_line_id'] = False - elif 'sale_line_id' in result: - result.pop('sale_line_id') - return result - # --------------------------------------------------- # Actions # --------------------------------------------------- |
