diff --git a/bemade_fsm/__manifest__.py b/bemade_fsm/__manifest__.py
index 456a968..02e8490 100644
--- a/bemade_fsm/__manifest__.py
+++ b/bemade_fsm/__manifest__.py
@@ -20,7 +20,7 @@
########################################################################################
{
'name': 'Improved Field Service Management',
- 'version': '17.0.0.1.1',
+ 'version': '17.0.0.2.0',
'summary': 'Adds functionality necessary for managing field service operations at Durpro.',
'description': 'Adds functionality necessary for managing field service operations at Durpro.',
'category': 'Services/Field Service',
diff --git a/bemade_fsm/models/equipment.py b/bemade_fsm/models/equipment.py
index 24587ab..ed15c9a 100644
--- a/bemade_fsm/models/equipment.py
+++ b/bemade_fsm/models/equipment.py
@@ -48,14 +48,14 @@ class Equipment(models.Model):
args = args or []
if name:
equipments = self.search([
- '|', '|', '|',
+ '|', '|',
('pid_tag', operator, name),
('name', operator, name),
('partner_location_id.name', operator, name)],
limit=limit)
else:
equipments = self.search(args, limit=limit)
- return equipments.name_get()
+ return [(equipment.id, equipment.display_name) for equipment in equipments]
def action_view_equipment(self):
return {
diff --git a/bemade_fsm/models/task.py b/bemade_fsm/models/task.py
index e144222..80843b2 100644
--- a/bemade_fsm/models/task.py
+++ b/bemade_fsm/models/task.py
@@ -1,7 +1,4 @@
from odoo import fields, models, api, Command, _
-from odoo.exceptions import ValidationError, UserError
-from odoo.osv import expression
-from collections import defaultdict, namedtuple
from odoo.addons.project.models.project_task import CLOSED_STATES
import re
@@ -23,9 +20,6 @@ class Task(models.Model):
relation="task_work_order_contact_rel",
column1="task_id",
column2="res_partner_id",
- compute="_compute_contacts",
- inverse="_inverse_contacts",
- store=True
)
site_contacts = fields.Many2many(
@@ -33,9 +27,6 @@ class Task(models.Model):
relation="task_site_contact_rel",
column1="task_id",
column2="res_partner_id",
- compute="_compute_contacts",
- inverse="_inverse_contacts",
- store=True
)
# Override related field to make it return false if this is an FSM subtask
@@ -77,6 +68,12 @@ class Task(models.Model):
def create(self, vals):
res = super().create(vals)
for rec in res:
+ if rec.parent_id and rec.is_fsm:
+ rec.partner_id = rec.parent_id.partner_id
+ if not rec.work_order_contacts and rec.parent_id:
+ rec.work_order_contacts = rec.parent_id.work_order_contacts
+ if not rec.site_contacts and rec.parent_id:
+ rec.site_contacts = rec.parent_id.site_contacts
if rec.sale_order_id:
seq = 1
prev_seqs = self.sale_order_id.tasks_ids and \
@@ -87,6 +84,11 @@ class Task(models.Model):
seq += max(map(lambda n: int(n.group(1)) if n else 0, matches))
rec.work_order_number = rec.sale_order_id.name.replace('SO', 'SVR', 1) \
+ f"-{seq}"
+ # If the task is linked to a sales order and has no parent, it should inherit SO work order contacts
+ if not rec.parent_id and not rec.work_order_contacts and rec.sale_order_id.work_order_contacts:
+ rec.work_order_contacts = rec.sale_order_id.work_order_contacts
+ if not rec.parent_id and not rec.site_contacts and rec.sale_order_id.site_contacts:
+ rec.site_contacts = rec.sale_order_id.site_contacts
return res
def write(self, vals):
@@ -101,6 +103,10 @@ class Task(models.Model):
# Here we use child_ids instead of _get_all_subtasks() so as to allow for setting propagate_assignment
# to false on a child task.
to_propagate.child_ids.write({'user_ids': vals['user_ids']})
+ if 'site_contacts' in vals and self.child_ids:
+ self._get_all_subtasks().write({'site_contacts': [Command.set(self.site_contacts.ids)]})
+ if 'work_order_contacts' in vals and self.child_ids:
+ self._get_all_subtasks().write({'work_order_contacts': [Command.set(self.work_order_contacts.ids)]})
return res
@api.depends('sale_order_id')
@@ -123,30 +129,6 @@ class Task(models.Model):
for project in self.project_id
}
- @api.depends('sale_line_id.order_id.site_contacts',
- 'sale_line_id.order_id.work_order_contacts')
- def _compute_contacts(self):
- """ The work order contacts and site contacts for a given task are taken from the sale order if the task
- is related to one, and from the task's customer if there is no sale order related to the task."""
- for rec in self:
- site_contacts = self.sale_line_id and self.sale_line_id.order_id.site_contacts or \
- self.partner_id.site_contacts
- work_order_contacts = self.sale_line_id and self.sale_line_id.order_id.work_order_contacts or \
- self.partner_id.work_order_contacts
- rec.write({
- 'site_contacts': [Command.set(site_contacts.ids)],
- 'work_order_contacts': [Command.set(work_order_contacts.ids)]
- })
-
- def _inverse_contacts(self):
- """ If the task is linked to a sales order, the sales order should have its contacts updated to match."""
- for rec in self:
- if rec.sale_line_id:
- rec.sale_line_id.order_id.write({
- 'work_order_contacts': [Command.set(rec.work_order_contacts.ids)],
- 'site_contacts': [Command.set(rec.site_contacts.ids)],
- })
-
@api.depends('parent_id.visit_id', 'project_id.is_fsm', 'project_id.allow_billable')
def _compute_allow_billable(self):
for rec in self:
diff --git a/bemade_fsm/tests/test_sale_order.py b/bemade_fsm/tests/test_sale_order.py
index 1e0561a..fd5d620 100644
--- a/bemade_fsm/tests/test_sale_order.py
+++ b/bemade_fsm/tests/test_sale_order.py
@@ -211,33 +211,6 @@ class TestSalesOrder(BemadeFSMBaseTest):
self.assertEqual(sol.task_id.work_order_contacts, partner.work_order_contacts)
self.assertEqual(sol.task_id.site_contacts, partner.site_contacts)
- def test_changing_task_contacts_mirrors_with_sale_order(self):
- partner = self._generate_partner()
- contact = self._generate_partner("Contact", "person", partner)
- so = self._generate_sale_order(partner)
- product = self._generate_product()
- sol = self._generate_sale_order_line(so, product)
- so.action_confirm()
- task = sol.task_id
- task_form = Form(task)
-
- # Now change the site/work order contact on the task and make sure it feeds back to the sales order
- task_form.site_contacts.add(contact)
- task_form.work_order_contacts.add(contact)
- task_form.save()
-
- self.assertEqual(task.site_contacts, so.site_contacts)
- self.assertEqual(task.work_order_contacts, so.work_order_contacts)
-
- # Test changing it on the SO feeds back to the task as well
- f = Form(so)
- f.work_order_contacts.remove(contact.id)
- f.site_contacts.remove(contact.id)
- f.save()
-
- self.assertEqual(task.site_contacts, so.site_contacts)
- self.assertEqual(task.work_order_contacts, so.work_order_contacts)
-
def test_tasks_created_at_order_confirmation_have_no_assignees(self):
so, visit, sol1, sol2 = self._generate_so_with_one_visit_two_lines()
user = self._generate_project_user(name="User", login='login')
diff --git a/bemade_fsm/tests/test_task.py b/bemade_fsm/tests/test_task.py
index 14b838a..8d5a3ef 100644
--- a/bemade_fsm/tests/test_task.py
+++ b/bemade_fsm/tests/test_task.py
@@ -1,5 +1,5 @@
from .test_bemade_fsm_common import BemadeFSMBaseTest
-from odoo.tests.common import tagged
+from odoo.tests.common import tagged, Form
from odoo import Command
@@ -10,18 +10,21 @@ class TaskTest(BemadeFSMBaseTest):
def setUpClass(cls):
# Chose to set up all tests the same way since this code was becoming very redundant
super().setUpClass()
- cls.so = cls._generate_sale_order()
- cls.template = cls._generate_task_template(names=['Parent', 'Child', 'Grandchild'], structure=[2, 1])
- cls.product = cls._generate_product(task_template=cls.template)
- cls.sol = cls._generate_sale_order_line(sale_order=cls.so, product=cls.product)
cls.user = cls._generate_project_manager_user('Bob', 'Bob')
- cls.so.action_confirm()
- cls.task = cls.sol.task_id
+
+ def _generate_so_with_multilevel_task_template(self):
+ so = self._generate_sale_order()
+ template = self._generate_task_template(names=['Parent', 'Child', 'Grandchild'], structure=[2, 1])
+ product = self._generate_product(task_template=template)
+ sol = self._generate_sale_order_line(sale_order=so, product=product)
+ return so, sol
def test_reassigning_assignment_propagating_task_changes_subtasks(self):
- task = self.task
- task.propagate_assignment = True
+ so, sol = self._generate_so_with_multilevel_task_template()
+ so.action_confirm()
+ task = sol.task_id
+ task.propagate_assignment = True
task.write({
'user_ids': [Command.set([self.user.id])],
'propagate_assignment': True,
@@ -30,7 +33,10 @@ class TaskTest(BemadeFSMBaseTest):
self.assertTrue(all([t.user_ids == self.user for t in task | task._get_all_subtasks()]))
def test_reassigning_task_doesnt_propagate_by_default(self):
- task = self.task
+ so, sol = self._generate_so_with_multilevel_task_template()
+ so.action_confirm()
+ task = sol.task_id
+
task.write({
'user_ids': [Command.set([self.user.id])],
})
@@ -38,7 +44,9 @@ class TaskTest(BemadeFSMBaseTest):
self.assertFalse(any([t.user_ids for t in task.child_ids.child_ids]))
def test_unset_propagate_assignment_unsets_for_all_children(self):
- task = self.task
+ so, sol = self._generate_so_with_multilevel_task_template()
+ so.action_confirm()
+ task = sol.task_id
# First, set propagation and assign
task.propagate_assignment = True
task.write({
@@ -53,3 +61,66 @@ class TaskTest(BemadeFSMBaseTest):
})
self.assertTrue(all([not t.user_ids for t in task | task.child_ids]))
self.assertTrue(all([t.user_ids == self.user for t in task.child_ids.child_ids]))
+
+ def test_task_gets_work_order_contacts_from_sale_order(self):
+ so, sol = self._generate_so_with_multilevel_task_template()
+ work_order_contacts = self._generate_partner(parent=so.partner_id) | self._generate_partner(
+ parent=so.partner_id)
+ so.write({'work_order_contacts': [(6, 0, work_order_contacts.ids)]})
+
+ so.action_confirm()
+ task = sol.task_id
+
+ self.assertEqual(task.work_order_contacts, so.work_order_contacts)
+ # Just a safeguard to make sure we set it properly on the SO
+ self.assertEqual(len(task.work_order_contacts), 2)
+ # Make sure all subtasks got the same
+ for subtask in task._get_all_subtasks():
+ self.assertEqual(subtask.work_order_contacts, so.work_order_contacts)
+
+ def test_task_gets_site_contacts_from_sale_order(self):
+ so, sol = self._generate_so_with_multilevel_task_template()
+ site_contacts = self._generate_partner(parent=so.partner_id) | self._generate_partner(parent=so.partner_id)
+ so.write({'site_contacts': [(6, 0, site_contacts.ids)]})
+
+ so.action_confirm()
+ task = sol.task_id
+
+ self.assertEqual(task.site_contacts, so.site_contacts)
+ # Just a safeguard to make sure we set it properly on the SO
+ self.assertEqual(len(task.site_contacts), 2)
+ # Make sure all subtasks got the same
+ for subtask in task._get_all_subtasks():
+ self.assertEqual(subtask.site_contacts, so.site_contacts)
+
+ def test_task_gets_work_order_contacts_from_parent(self):
+ so, sol = self._generate_so_with_multilevel_task_template()
+ work_order_contacts = self._generate_partner(parent=so.partner_id) | self._generate_partner(parent=so.partner_id)
+ so.write({'work_order_contacts': [(6, 0, work_order_contacts.ids)]})
+
+ so.action_confirm()
+ task = sol.task_id
+ task.write({'work_order_contacts': [Command.link(self._generate_partner(parent=so.partner_id).id)]})
+ for subtask in task._get_all_subtasks():
+ self.assertEqual(subtask.work_order_contacts, task.work_order_contacts)
+ with Form(task) as task_form:
+ with task_form.child_ids.new() as subtask:
+ subtask.name = "Subtask 1"
+ subtask = task.child_ids[-1]
+ self.assertEqual(subtask.work_order_contacts, task.work_order_contacts)
+
+ def test_task_gets_site_contacts_from_parent(self):
+ so, sol = self._generate_so_with_multilevel_task_template()
+ site_contacts = self._generate_partner(parent=so.partner_id) | self._generate_partner(parent=so.partner_id)
+ so.write({'site_contacts': [(6, 0, site_contacts.ids)]})
+
+ so.action_confirm()
+ task = sol.task_id
+ task.write({'site_contacts': [Command.link(self._generate_partner(parent=so.partner_id).id)]})
+ for subtask in task._get_all_subtasks():
+ self.assertEqual(subtask.site_contacts, task.site_contacts)
+ with Form(task) as task_form:
+ with task_form.child_ids.new() as subtask:
+ subtask.name = "Subtask 1"
+ subtask = task.child_ids[-1]
+ self.assertEqual(subtask.site_contacts, task.site_contacts)
diff --git a/bemade_fsm/views/res_partner.xml b/bemade_fsm/views/res_partner.xml
index 3061fb2..68d7efb 100644
--- a/bemade_fsm/views/res_partner.xml
+++ b/bemade_fsm/views/res_partner.xml
@@ -4,8 +4,8 @@
Equipments
bemade_fsm.equipment
tree,form
- {'default_partner_id': active_id}
- [("partner_id", "=", active_id)]
+ {'default_partner_location_id': active_id}
+ [("partner_location_id", "=", active_id)]