diff --git a/addons/sale_project/models/project.py b/addons/sale_project/models/project.py index ed976170b71..bbe5a7349a5 100755 --- a/addons/sale_project/models/project.py +++ b/addons/sale_project/models/project.py @@ -483,17 +483,21 @@ class ProjectTask(models.Model): "Remove the sales order item in order to make this task non billable. You can also change or remove the sales order item of each timesheet entry individually.") project_sale_order_id = fields.Many2one('sale.order', string="Project's sale order", related='project_id.sale_order_id') task_to_invoice = fields.Boolean("To invoice", compute='_compute_task_to_invoice', search='_search_task_to_invoice', groups='sales_team.group_sale_salesman_all_leads') + allow_billable = fields.Boolean(related="project_id.allow_billable") # Project sharing fields display_sale_order_button = fields.Boolean(string='Display Sales Order', compute='_compute_display_sale_order_button') @property def SELF_READABLE_FIELDS(self): - return super().SELF_READABLE_FIELDS | {'sale_order_id', 'sale_line_id', 'display_sale_order_button'} + return super().SELF_READABLE_FIELDS | {'allow_billable', 'sale_order_id', 'sale_line_id', 'display_sale_order_button'} - @api.depends('sale_line_id', 'project_id', 'commercial_partner_id') + @api.depends('sale_line_id', 'project_id', 'commercial_partner_id', 'allow_billable') def _compute_sale_order_id(self): for task in self: + if not task.allow_billable: + task.sale_order_id = False + continue sale_order_id = task.sale_order_id or self.env["sale.order"] if task.sale_line_id: sale_order_id = task.sale_line_id.sudo().order_id @@ -505,9 +509,12 @@ class ProjectTask(models.Model): task.partner_id = sale_order_id.partner_id task.sale_order_id = sale_order_id - @api.depends('commercial_partner_id', 'sale_line_id.order_partner_id', 'parent_id.sale_line_id', 'project_id.sale_line_id', 'milestone_id.sale_line_id') + @api.depends('commercial_partner_id', 'sale_line_id.order_partner_id', 'parent_id.sale_line_id', 'project_id.sale_line_id', 'milestone_id.sale_line_id', 'allow_billable') def _compute_sale_line(self): for task in self: + if not task.allow_billable: + task.sale_line_id = False + continue if not task.sale_line_id: # if the display_project_id is set then it means the task is classic task or a subtask with another project than its parent. task.sale_line_id = task.display_project_id.sale_line_id or task.parent_id.sale_line_id or task.project_id.sale_line_id or task.milestone_id.sale_line_id diff --git a/addons/sale_project/tests/test_child_tasks.py b/addons/sale_project/tests/test_child_tasks.py index 73a91a47be2..4f93b6c0069 100644 --- a/addons/sale_project/tests/test_child_tasks.py +++ b/addons/sale_project/tests/test_child_tasks.py @@ -19,12 +19,17 @@ class TestNestedTaskUpdate(TransactionCase): product = cls.env['product.product'].create({ 'name': "Prepaid Consulting", 'type': 'service', + 'service_tracking': 'project_only', }) cls.order_line = cls.env['sale.order.line'].create({ 'name': "Order line", 'product_id': product.id, 'order_id': sale_order.id, }) + sale_order.action_confirm() + + cls.project = cls.order_line.project_id + cls.project.sale_line_id = False cls.user = new_test_user(cls.env, login='mla') #---------------------------------- @@ -54,20 +59,20 @@ class TestNestedTaskUpdate(TransactionCase): self.assertEqual(child.email_from, 'a@c.be') def test_creating_subtask_sale_line_id_on_parent_goes_on_child_if_same_partner_in_values(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'partner_id': self.partner.id, 'parent_id': parent.id}) self.assertEqual(child.sale_line_id, parent.sale_line_id) parent.write({'sale_line_id': False}) self.assertEqual(child.sale_line_id, self.order_line) def test_creating_subtask_sale_line_id_on_parent_goes_on_child_with_partner_if_not_in_values(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'parent_id': parent.id}) self.assertEqual(child.partner_id, parent.partner_id) self.assertEqual(child.sale_line_id, parent.sale_line_id) def test_creating_subtask_sale_line_id_on_parent_dont_go_on_child_if_other_partner(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'partner_id': self.user.partner_id.id, 'parent_id': parent.id}) self.assertFalse(child.sale_line_id) self.assertNotEqual(child.partner_id, parent.partner_id) @@ -76,7 +81,7 @@ class TestNestedTaskUpdate(TransactionCase): commercial_partner = self.env['res.partner'].create({'name': "Jémémy"}) self.partner.parent_id = commercial_partner self.user.partner_id.parent_id = commercial_partner - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'partner_id': self.user.partner_id.id, 'parent_id': parent.id}) self.assertEqual(child.sale_line_id, self.order_line, "Sale order line on parent should be transfered to child") self.assertNotEqual(child.partner_id, parent.partner_id) @@ -115,7 +120,7 @@ class TestNestedTaskUpdate(TransactionCase): self.assertEqual(child.email_from, 'a@c.be') def test_write_sale_line_id_on_parent_write_on_child_if_same_partner(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'parent_id': parent.id, 'partner_id': self.partner.id}) self.assertFalse(child.sale_line_id) parent.write({'sale_line_id': self.order_line.id}) @@ -124,7 +129,7 @@ class TestNestedTaskUpdate(TransactionCase): self.assertEqual(child.sale_line_id, self.order_line) def test_write_sale_line_id_on_parent_write_on_child_with_partner_if_not_set(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'parent_id': parent.id}) child._compute_partner_id() self.assertFalse(child.sale_line_id) @@ -135,7 +140,7 @@ class TestNestedTaskUpdate(TransactionCase): self.assertEqual(child.sale_line_id, self.order_line) def test_write_sale_line_id_on_parent_dont_write_on_child_if_other_partner(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'parent_id': parent.id, 'partner_id': self.user.partner_id.id}) self.assertFalse(child.sale_line_id) parent.write({'sale_line_id': self.order_line.id}) @@ -169,7 +174,7 @@ class TestNestedTaskUpdate(TransactionCase): self.assertEqual(child.email_from, 'a@c.be') def test_linking_sale_line_id_on_parent_write_on_child_if_same_partner(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'partner_id': self.partner.id}) self.assertFalse(child.sale_line_id) child.write({'parent_id': parent.id}) @@ -178,7 +183,7 @@ class TestNestedTaskUpdate(TransactionCase): self.assertEqual(child.sale_line_id, self.order_line) def test_linking_sale_line_id_on_parent_write_on_child_with_partner_if_not_set(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'partner_id': False}) self.assertFalse(child.sale_line_id) self.assertFalse(child.partner_id) @@ -187,7 +192,7 @@ class TestNestedTaskUpdate(TransactionCase): self.assertEqual(child.sale_line_id, parent.sale_line_id) def test_linking_sale_line_id_on_parent_write_dont_child_if_other_partner(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'project_id': self.project.id}) child = self.env['project.task'].create({'name': 'child', 'partner_id': self.user.partner_id.id}) self.assertFalse(child.sale_line_id) self.assertNotEqual(child.partner_id, parent.partner_id) @@ -195,7 +200,7 @@ class TestNestedTaskUpdate(TransactionCase): self.assertFalse(child.sale_line_id) def test_writing_on_parent_with_multiple_tasks(self): - parent = self.env['project.task'].create({'name': 'parent', 'user_ids': False, 'partner_id': self.partner.id}) + parent = self.env['project.task'].create({'name': 'parent', 'user_ids': False, 'partner_id': self.partner.id, 'project_id': self.project.id}) children_values = [{'name': 'child%s' % i, 'user_ids': False, 'parent_id': parent.id} for i in range(5)] children = self.env['project.task'].create(children_values) children._compute_partner_id() @@ -207,7 +212,7 @@ class TestNestedTaskUpdate(TransactionCase): self.assertEqual(child.sale_line_id, self.order_line) def test_linking_on_parent_with_multiple_tasks(self): - parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'user_ids': [(4, self.user.id)]}) + parent = self.env['project.task'].create({'name': 'parent', 'partner_id': self.partner.id, 'sale_line_id': self.order_line.id, 'user_ids': [(4, self.user.id)], 'project_id': self.project.id}) children_values = [{'name': 'child%s' % i, 'user_ids': False} for i in range(5)] children = self.env['project.task'].create(children_values) # test writing user_ids and sale_line_id diff --git a/addons/sale_project/views/project_task_views.xml b/addons/sale_project/views/project_task_views.xml index 6e1c42db30e..377707c22cd 100644 --- a/addons/sale_project/views/project_task_views.xml +++ b/addons/sale_project/views/project_task_views.xml @@ -74,9 +74,10 @@ - - + + + diff --git a/addons/sale_timesheet/models/project.py b/addons/sale_timesheet/models/project.py index a8d3d14b3a9..abf127d7dbf 100644 --- a/addons/sale_timesheet/models/project.py +++ b/addons/sale_timesheet/models/project.py @@ -512,7 +512,6 @@ class ProjectTask(models.Model): pricing_type = fields.Selection(related="project_id.pricing_type") is_project_map_empty = fields.Boolean("Is Project map empty", compute='_compute_is_project_map_empty') has_multi_sol = fields.Boolean(compute='_compute_has_multi_sol', compute_sudo=True) - allow_billable = fields.Boolean(related="project_id.allow_billable") timesheet_product_id = fields.Many2one(related="project_id.timesheet_product_id") remaining_hours_so = fields.Float('Remaining Hours on SO', compute='_compute_remaining_hours_so', search='_search_remaining_hours_so', compute_sudo=True) remaining_hours_available = fields.Boolean(related="sale_line_id.remaining_hours_available") @@ -520,7 +519,6 @@ class ProjectTask(models.Model): @property def SELF_READABLE_FIELDS(self): return super().SELF_READABLE_FIELDS | { - 'allow_billable', 'remaining_hours_available', 'remaining_hours_so', } @@ -555,19 +553,11 @@ class ProjectTask(models.Model): for task in self: task.analytic_account_active = task.analytic_account_active or task.so_analytic_account_id.active - @api.depends('allow_billable') - def _compute_sale_order_id(self): - billable_tasks = self.filtered('allow_billable') - super(ProjectTask, billable_tasks)._compute_sale_order_id() - (self - billable_tasks).sale_order_id = False - @api.depends('commercial_partner_id', 'sale_line_id.order_partner_id', 'parent_id.sale_line_id', 'project_id.sale_line_id', 'allow_billable') def _compute_sale_line(self): - billable_tasks = self.filtered('allow_billable') - (self - billable_tasks).update({'sale_line_id': False}) - super(ProjectTask, billable_tasks)._compute_sale_line() - for task in billable_tasks: - if not task.sale_line_id: + super()._compute_sale_line() + for task in self: + if task.allow_billable and not task.sale_line_id: task.sale_line_id = task._get_last_sol_of_customer() @api.depends('project_id.sale_line_employee_ids') diff --git a/addons/sale_timesheet/views/project_task_views.xml b/addons/sale_timesheet/views/project_task_views.xml index 483606e6b4e..a519b1058be 100644 --- a/addons/sale_timesheet/views/project_task_views.xml +++ b/addons/sale_timesheet/views/project_task_views.xml @@ -101,9 +101,6 @@ project.task - - - @@ -190,10 +187,6 @@ {'create': False, 'edit': False, 'delete': False, 'with_price_unit': True, 'with_remaining_hours': True} - - - {'invisible': [('allow_billable', '=', False)]} -