bemade_fsm: completing an FSM tasks completes all its descendants as well.

This commit is contained in:
Marc Durepos 2023-11-21 10:00:30 -05:00
parent 0ddb7c8160
commit 8b8250ffbb
3 changed files with 30 additions and 12 deletions

View file

@ -184,17 +184,21 @@ class Task(models.Model):
rec.allow_billable = rec.project_id.allow_billable rec.allow_billable = rec.project_id.allow_billable
def action_fsm_validate(self): def action_fsm_validate(self):
visits = self.filtered(lambda t: t.visit_id) # Override to make sure all descendant tasks are validated as well
non_visits = self - visits full_hierarchy = self._get_full_hierarchy()
visits = self.filtered(lambda t: bool(t.visit_id))
non_visits = full_hierarchy - visits
super(Task, non_visits).action_fsm_validate() super(Task, non_visits).action_fsm_validate()
visits._stop_all_timers_and_create_timesheets() visits._stop_all_timers_and_create_timesheets()
closed_stage_by_project = visits._get_closed_stage_by_project() closed_stage_by_project = visits._get_closed_stage_by_project()
super(Task, visits.child_ids).action_fsm_validate()
for visit in visits: for visit in visits:
stage = closed_stage_by_project[visit.project_id] stage = closed_stage_by_project[visit.project_id]
visits.write({'stage_id': stage.id, 'fsm_done': True}) visits.write({'stage_id': stage.id, 'fsm_done': True})
def _get_full_hierarchy(self):
if self.child_ids:
return self | self.child_ids._get_full_hierarchy()
return self
def synchronize_name_fsm(self): def synchronize_name_fsm(self):
""" Applies naming to the entire task tree for tasks that are part of this """ Applies naming to the entire task tree for tasks that are part of this
recordset. Root tasks are named: recordset. Root tasks are named:

View file

@ -192,3 +192,16 @@ class BemadeFSMBaseTest(TransactionCase):
sol1.sequence = 2 sol1.sequence = 2
sol2.sequence = 3 sol2.sequence = 3
return so, visit, sol1, sol2 return so, visit, sol1, sol2
def _generate_so_with_one_visit_two_lines_and_descendants(self):
so = self._generate_sale_order()
visit = self._generate_visit(sale_order=so)
task_template = self._generate_task_template(structure=[2, 2, 2],
names=['Parent', 'Child', 'Grandchild', 'Great-grandchild'])
product = self._generate_product(task_template=task_template)
sol1 = self._generate_sale_order_line(sale_order=so, product=product)
sol2 = self._generate_sale_order_line(sale_order=so, product=product)
visit.so_section_id.sequence = 1
sol1.sequence = 2
sol2.sequence = 3
return so, visit, sol1, sol2

View file

@ -102,18 +102,19 @@ class FSMVisitTest(BemadeFSMBaseTest):
self.assertEqual(len(so.order_line), 3) self.assertEqual(len(so.order_line), 3)
def test_marking_visit_task_done_completes_descendants(self): def test_marking_visit_task_done_completes_descendants(self):
so, visit, sol1, sol2 = self._generate_so_with_one_visit_two_lines() so, visit, sol1, sol2 = self._generate_so_with_one_visit_two_lines_and_descendants()
so.action_confirm() so.action_confirm()
parent, child1, child2 = visit.task_id, sol1.task_id, sol2.task_id parent = visit.task_id
parent.action_fsm_validate() parent.action_fsm_validate()
self.assertTrue(parent.is_closed) self._assert_is_done(parent)
self.assertTrue(child1.is_closed)
self.assertTrue(child2.is_closed) def _assert_is_done(self, task):
self.assertEqual(sol1.qty_to_deliver, 0) """ Recursively assert all tasks in a hierarchy are complete """
self.assertEqual(sol2.qty_to_deliver, 0) self.assertTrue(task.is_closed)
self.assertTrue(visit.is_completed) for child in task.child_ids:
self._assert_is_done(child)
def test_marking_visit_task_done_does_not_create_sale_order_line(self): def test_marking_visit_task_done_does_not_create_sale_order_line(self):
so, visit, sol1, sol2 = self._generate_so_with_one_visit_two_lines() so, visit, sol1, sol2 = self._generate_so_with_one_visit_two_lines()