From 9f72b02c4193b2d6409d37bd2c695cb465cd753f Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 3 Apr 2023 11:40:26 -0400 Subject: [PATCH] some cleanup and added back in option to get most recent tasks only --- .../routes/process_instances_controller.py | 7 +++ .../services/process_instance_processor.py | 7 ++- .../services/task_service.py | 10 +--- .../unit/test_process_instance_processor.py | 53 +++++++++---------- .../src/routes/ProcessInstanceShow.tsx | 5 +- 5 files changed, 37 insertions(+), 45 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py index dd0ad1958..a7dda2104 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py @@ -669,6 +669,13 @@ def process_instance_task_list( task_model_query = task_model_query.filter(bpmn_process_alias.id.in_(bpmn_process_ids)) task_models = task_model_query.all() + task_model_list = {} + if most_recent_tasks_only: + for task_model in task_models: + if task_model.bpmn_identifier not in task_model_list: + task_model_list[task_model.bpmn_identifier] = task_model + + task_models = list(task_model_list.values()) if to_task_model is not None: task_models_dict = json.loads(current_app.json.dumps(task_models)) for task_model in task_models_dict: 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 93f3a811a..864ab2d1f 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1336,13 +1336,10 @@ class ProcessInstanceProcessor: # ensure the correct order for foreign keys for human_task_to_delete in human_tasks_to_delete: db.session.delete(human_task_to_delete) - db.session.commit() for task_to_delete in tasks_to_delete: db.session.delete(task_to_delete) - db.session.commit() for bpmn_process_to_delete in bpmn_processes_to_delete: db.session.delete(bpmn_process_to_delete) - db.session.commit() related_human_task = HumanTaskModel.query.filter_by(task_model_id=to_task_model.id).first() if related_human_task is not None: @@ -1354,10 +1351,10 @@ class ProcessInstanceProcessor: ).all() for human_task_to_delete in human_tasks_to_delete: db.session.delete(human_task_to_delete) - db.session.commit() for task_to_update in tasks_to_update: TaskService.reset_task_model(task_to_update, state="FUTURE") + db.session.bulk_save_objects(tasks_to_update) parent_task_model = TaskModel.query.filter_by(guid=to_task_model.properties_json["parent"]).first() if parent_task_model is None: @@ -1371,8 +1368,10 @@ class ProcessInstanceProcessor: json_data_hash=parent_task_model.json_data_hash, python_env_data_hash=parent_task_model.python_env_data_hash, ) + db.session.add(to_task_model) for task_model in task_models_of_parent_bpmn_processes: TaskService.reset_task_model(task_model, state="WAITING") + db.session.bulk_save_objects(task_models_of_parent_bpmn_processes) bpmn_process = to_task_model.bpmn_process properties_json = copy.copy(bpmn_process.properties_json) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/task_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/task_service.py index 2b4807012..8223f5be6 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/task_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/task_service.py @@ -516,22 +516,14 @@ class TaskService: else: task_model.python_env_data_hash = python_env_data_hash - new_properties_json = copy.copy(task_model.properties_json) task_model.state = state task_model.start_in_seconds = None task_model.end_in_seconds = None - db.session.add(task_model) - db.session.commit() - + new_properties_json = copy.copy(task_model.properties_json) new_properties_json["state"] = getattr(TaskState, state) task_model.properties_json = new_properties_json - # if we commit the properties json at the same time as the other items - # the json gets reset for some reason. - db.session.add(task_model) - db.session.commit() - @classmethod def _create_task( cls, 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 15ec170bd..ac5d39989 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 @@ -1,5 +1,6 @@ """Test_process_instance_processor.""" from uuid import UUID +from spiffworkflow_backend.models.db import db import pytest from flask import g @@ -335,7 +336,6 @@ class TestProcessInstanceProcessor(BaseTest): ) processor = ProcessInstanceProcessor(process_instance) processor.do_engine_steps(save=True) - # with open("before_reset.json", 'w') as f: f.write(json.dumps(processor.serialize(), indent=2)) assert len(process_instance.active_human_tasks) == 1 initial_human_task_id = process_instance.active_human_tasks[0].id assert len(process_instance.active_human_tasks) == 1 @@ -348,14 +348,6 @@ class TestProcessInstanceProcessor(BaseTest): spiff_manual_task = processor.bpmn_process_instance.get_task_from_id(UUID(human_task_one.task_id)) ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one) - # NOTES: - # somehow we are hosing the task state so that when completing tasks of a subprocess, the task AFTER the subprocess task - # is not marked READY but instead stays as FUTURE. Running things like: - # self.last_completed_spiff_task.task_spec._update(self.last_completed_spiff_task) - # and - # self.last_completed_spiff_task.task_spec._predict(self.last_completed_spiff_task, mask=TaskState.NOT_FINISHED_MASK) - # did not help. - processor.suspend() task_model_to_reset_to = ( TaskModel.query.join(TaskDefinitionModel) @@ -366,8 +358,15 @@ class TestProcessInstanceProcessor(BaseTest): assert task_model_to_reset_to is not None ProcessInstanceProcessor.reset_process(process_instance, task_model_to_reset_to.guid) + # make sure sqlalchemy session matches current db state + db.session.expire_all() process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first() processor = ProcessInstanceProcessor(process_instance) + + # make sure we reset to the task we expected + ready_or_waiting_tasks = processor.get_all_ready_or_waiting_tasks() + top_level_subprocess_script_spiff_task = next(task for task in ready_or_waiting_tasks if task.task_spec.name == "top_level_subprocess_script") + assert top_level_subprocess_script_spiff_task is not None processor.resume() processor.do_engine_steps(save=True) @@ -511,18 +510,17 @@ class TestProcessInstanceProcessor(BaseTest): f" {expected_task_data_key}." ) - # TODO: add back in when removing MAYBE and LIKELY tasks - # count_failure_message = ( - # f"{base_failure_message} There are more than 2 entries of this task in the db." - # " There should only ever be max 2." - # ) - # task_models_with_bpmn_identifier_count = ( - # TaskModel.query.join(TaskDefinitionModel) - # .filter(TaskModel.process_instance_id == process_instance_relookup.id) - # .filter(TaskDefinitionModel.bpmn_identifier == spiff_task.task_spec.name) - # .count() - # ) - # assert task_models_with_bpmn_identifier_count < 3, count_failure_message + count_failure_message = ( + f"{base_failure_message} There are more than 2 entries of this task in the db." + " There should only ever be max 2." + ) + task_models_with_bpmn_identifier_count = ( + TaskModel.query.join(TaskDefinitionModel) + .filter(TaskModel.process_instance_id == process_instance_relookup.id) + .filter(TaskDefinitionModel.bpmn_identifier == spiff_task.task_spec.name) + .count() + ) + assert task_models_with_bpmn_identifier_count < 3, count_failure_message task_model = TaskModel.query.filter_by(guid=str(spiff_task.id)).first() assert task_model.start_in_seconds is not None @@ -583,13 +581,12 @@ class TestProcessInstanceProcessor(BaseTest): ) assert task_bpmn_identifier in spiff_tasks_checked, message - # TODO: add back in when removing MAYBE and LIKELY tasks - # task_models_that_are_predicted_count = ( - # TaskModel.query.filter(TaskModel.process_instance_id == process_instance_relookup.id) - # .filter(TaskModel.state.in_(["LIKELY", "MAYBE"])) # type: ignore - # .count() - # ) - # assert task_models_that_are_predicted_count == 0 + task_models_that_are_predicted_count = ( + TaskModel.query.filter(TaskModel.process_instance_id == process_instance_relookup.id) + .filter(TaskModel.state.in_(["LIKELY", "MAYBE"])) # type: ignore + .count() + ) + assert task_models_that_are_predicted_count == 0 assert processor.get_data() == data_set_7 diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index ed773ef05..7ae4d4ce2 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -236,8 +236,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { tasks.forEach(function getUserTasksElement(task: Task) { if (task.state === 'COMPLETED') { taskIds.completed.push(task); - } - if (task.state === 'READY' || task.state === 'WAITING') { + } else if (task.state === 'READY' || task.state === 'WAITING') { taskIds.readyOrWaiting.push(task); } return null; @@ -675,8 +674,6 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { }; const canResetProcess = (task: Task) => { - // disabling this feature for now - // return false; return ( ability.can('POST', targetUris.processInstanceResetPath) && processInstance &&