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)]}
-