From 32141a238efaaa7b63c412a40228b1fa553601d5 Mon Sep 17 00:00:00 2001 From: jasquat <2487833+jasquat@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:11:53 +0000 Subject: [PATCH] Reset task in call activity fix (#1417) * updated import pi test to set task data w/ burnettk * fixed persist test so it loads the processor with data * load data and completed tasks when getting bpmn json for an instance * save start and end times on tasks on import w/ burnettk * verify we are saving start and end times for imported process instances w/ burnettk --------- Co-authored-by: jasquat --- .../bin/get_bpmn_json_for_process_instance.py | 5 ++-- .../services/process_instance_processor.py | 13 ++++++-- .../data/service-task-with-data-obj/main.bpmn | 3 +- .../unit/test_process_instance_processor.py | 30 ++++++++++++++++--- 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/spiffworkflow-backend/bin/get_bpmn_json_for_process_instance.py b/spiffworkflow-backend/bin/get_bpmn_json_for_process_instance.py index fe60de70..40604756 100755 --- a/spiffworkflow-backend/bin/get_bpmn_json_for_process_instance.py +++ b/spiffworkflow-backend/bin/get_bpmn_json_for_process_instance.py @@ -6,7 +6,6 @@ from spiffworkflow_backend.services.process_instance_processor import ProcessIns def main(process_instance_id: str) -> None: - """Main.""" app = create_app() with app.app_context(): process_instance = ProcessInstanceModel.query.filter_by(id=process_instance_id).first() @@ -15,7 +14,9 @@ def main(process_instance_id: str) -> None: if not process_instance: raise Exception(f"Could not find a process instance with id: {process_instance_id}") - processor = ProcessInstanceProcessor(process_instance) + processor = ProcessInstanceProcessor( + process_instance, include_completed_subprocesses=True, include_task_data_for_completed_tasks=True + ) processor.dump_to_disk(file_path) print(f"Saved to {file_path}") diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index ea3f59b0..03fb640f 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -98,6 +98,7 @@ from spiffworkflow_backend.services.process_model_service import ProcessModelSer from spiffworkflow_backend.services.service_task_service import CustomServiceTask from spiffworkflow_backend.services.service_task_service import ServiceTaskDelegate from spiffworkflow_backend.services.spec_file_service import SpecFileService +from spiffworkflow_backend.services.task_service import StartAndEndTimes from spiffworkflow_backend.services.task_service import TaskService from spiffworkflow_backend.services.user_service import UserService from spiffworkflow_backend.services.workflow_execution_service import ExecutionStrategy @@ -521,8 +522,14 @@ class ProcessInstanceProcessor: bpmn_process_instance = cls._serializer.from_dict(process_copy) bpmn_process_instance.script_engine = cls._default_script_engine for spiff_task in bpmn_process_instance.get_tasks(): + start_and_end_times: StartAndEndTimes | None = None + if spiff_task.has_state(TaskState.COMPLETED | TaskState.ERROR): + start_and_end_times = { + "start_in_seconds": spiff_task.last_state_change, + "end_in_seconds": spiff_task.last_state_change, + } task_service.update_task_model_with_spiff_task( - spiff_task, store_process_instance_events=store_process_instance_events + spiff_task, store_process_instance_events=store_process_instance_events, start_and_end_times=start_and_end_times ) task_service.save_objects_to_database() db.session.commit() @@ -1687,8 +1694,8 @@ class ProcessInstanceProcessor: return [t for t in all_tasks if t.task_spec.manual] def get_all_completed_tasks(self) -> list[SpiffTask]: - all_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.ANY_MASK) - return [t for t in all_tasks if t.task_spec.manual and t.state in [TaskState.COMPLETED, TaskState.CANCELLED]] + return_tasks: list[SpiffTask] = self.bpmn_process_instance.get_tasks(state=TaskState.COMPLETED | TaskState.CANCELLED) + return return_tasks def get_all_waiting_tasks(self) -> list[SpiffTask]: all_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.ANY_MASK) diff --git a/spiffworkflow-backend/tests/data/service-task-with-data-obj/main.bpmn b/spiffworkflow-backend/tests/data/service-task-with-data-obj/main.bpmn index c2f1cf62..8cb11f4a 100644 --- a/spiffworkflow-backend/tests/data/service-task-with-data-obj/main.bpmn +++ b/spiffworkflow-backend/tests/data/service-task-with-data-obj/main.bpmn @@ -34,7 +34,8 @@ DataObjectReference_0qfbjfj - top_level_data_object = "a" + top_level_data_object = "a" +top_level_var = "b" diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py index 8eca4c8d..7a7cc765 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py @@ -918,8 +918,14 @@ class TestProcessInstanceProcessor(BaseTest): process_model_source_directory="service-task-with-data-obj", ) process_instance = self.create_process_instance_from_process_model(process_model=process_model) - processor = ProcessInstanceProcessor(process_instance) + processor = ProcessInstanceProcessor( + process_instance, include_completed_subprocesses=True, include_task_data_for_completed_tasks=True + ) processor.do_engine_steps(save=True) + initial_completed_spiff_task = processor.get_all_completed_tasks()[0] + initial_completed_task_model = TaskModel.query.filter_by(guid=str(initial_completed_spiff_task.id)).first() + assert initial_completed_task_model.start_in_seconds is not None + assert initial_completed_task_model.end_in_seconds is not None bpmn_process_dict_initial = processor.serialize() @@ -940,12 +946,17 @@ class TestProcessInstanceProcessor(BaseTest): ProcessInstanceProcessor.persist_bpmn_process_dict( bpmn_process_dict_initial, process_instance_model=process_instance, bpmn_definition_to_task_definitions_mappings={} ) - processor = ProcessInstanceProcessor(process_instance) + processor = ProcessInstanceProcessor( + process_instance, include_completed_subprocesses=True, include_task_data_for_completed_tasks=True + ) bpmn_process_dict_after = processor.serialize() self.round_last_state_change(bpmn_process_dict_after) self.round_last_state_change(bpmn_process_dict_initial) assert bpmn_process_dict_after == bpmn_process_dict_initial + final_completed_task_model = TaskModel.query.filter_by(guid=str(initial_completed_spiff_task.id)).first() + assert final_completed_task_model.start_in_seconds is not None + assert final_completed_task_model.end_in_seconds is not None def test_can_persist_given_bpmn_process_dict_when_loaded_before( self, @@ -958,20 +969,31 @@ class TestProcessInstanceProcessor(BaseTest): process_model_source_directory="service-task-with-data-obj", ) process_instance = self.create_process_instance_from_process_model(process_model=process_model) - processor = ProcessInstanceProcessor(process_instance) + processor = ProcessInstanceProcessor( + process_instance, include_completed_subprocesses=True, include_task_data_for_completed_tasks=True + ) processor.do_engine_steps(save=True) + initial_completed_spiff_task = processor.get_all_completed_tasks()[0] + initial_completed_task_model = TaskModel.query.filter_by(guid=str(initial_completed_spiff_task.id)).first() + assert initial_completed_task_model.start_in_seconds is not None + assert initial_completed_task_model.end_in_seconds is not None bpmn_process_dict_initial = processor.serialize() ProcessInstanceProcessor.persist_bpmn_process_dict( bpmn_process_dict_initial, process_instance_model=process_instance, bpmn_definition_to_task_definitions_mappings={} ) - processor = ProcessInstanceProcessor(process_instance) + processor = ProcessInstanceProcessor( + process_instance, include_completed_subprocesses=True, include_task_data_for_completed_tasks=True + ) bpmn_process_dict_after = processor.serialize() self.round_last_state_change(bpmn_process_dict_after) self.round_last_state_change(bpmn_process_dict_initial) assert bpmn_process_dict_after == bpmn_process_dict_initial + final_completed_task_model = TaskModel.query.filter_by(guid=str(initial_completed_spiff_task.id)).first() + assert final_completed_task_model.start_in_seconds is not None + assert final_completed_task_model.end_in_seconds is not None def test_returns_error_if_spiff_task_and_human_task_are_different( self,