[MOV] sale_{project,timesheet}: move allow_billable field
This commit move allow_billable field of task to sale_project from sale_timesheet module. task-3018123 closes odoo/odoo#106961 Related: odoo/upgrade#4093 Signed-off-by: Laurent Stukkens (ltu) <ltu@odoo.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -74,9 +74,10 @@
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='partner_phone']" position="after">
|
||||
<field name="sale_order_id" attrs="{'invisible': True}" groups="sales_team.group_sale_salesman"/>
|
||||
<field name="sale_line_id" groups="!sales_team.group_sale_salesman" string="Sales Order Item" options='{"no_open": True}' readonly="1" context="{'create': False, 'edit': False, 'delete': False}"/>
|
||||
<field name="sale_line_id" groups="sales_team.group_sale_salesman" string="Sales Order Item" options='{"no_create": True}' readonly="0" context="{'create': False, 'edit': False, 'delete': False, 'with_price_unit': True}" placeholder="Non-billable"/>
|
||||
<field name="sale_line_id" groups="!sales_team.group_sale_salesman" string="Sales Order Item" options='{"no_open": True}' readonly="1" context="{'create': False, 'edit': False, 'delete': False}" attrs="{'invisible': [('allow_billable', '=', False)]}"/>
|
||||
<field name="sale_line_id" groups="sales_team.group_sale_salesman" string="Sales Order Item" options='{"no_create": True}' readonly="0" context="{'create': False, 'edit': False, 'delete': False, 'with_price_unit': True}" placeholder="Non-billable" attrs="{'invisible': [('allow_billable', '=', False)]}"/>
|
||||
<field name="commercial_partner_id" invisible="1" />
|
||||
<field name="allow_billable" invisible="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -101,9 +101,6 @@
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.view_task_form2_inherited"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<field name="allow_billable" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='child_ids']/tree//field[@name='remaining_hours']" position="after">
|
||||
<field name="remaining_hours_so" widget="timesheet_uom" optional="hide" groups="base.group_user"/>
|
||||
</xpath>
|
||||
@@ -190,10 +187,6 @@
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='sale_line_id'][2]" position="attributes">
|
||||
<attribute name="context">{'create': False, 'edit': False, 'delete': False, 'with_price_unit': True, 'with_remaining_hours': True}</attribute>
|
||||
<!-- To do: move allow_billable field in sale_project and add attrs directly on field in master -->
|
||||
<attribute name="attrs">
|
||||
{'invisible': [('allow_billable', '=', False)]}
|
||||
</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user