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 ec741f32..c97fa733 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1335,7 +1335,7 @@ class ProcessInstanceProcessor: and_( or_( TaskModel.end_in_seconds > to_task_model.end_in_seconds, - TaskModel.end_in_seconds.is_not(None), # type: ignore + TaskModel.end_in_seconds.is_(None), # type: ignore ), TaskModel.process_instance_id == process_instance.id, TaskModel.bpmn_process_id.in_(parent_bpmn_processes_ids), # type: ignore diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/task_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/task_service.py index 918de4d8..f75d955c 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/task_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/task_service.py @@ -342,11 +342,11 @@ class TaskService: python_env_data_hash: Optional[str] = None, ) -> None: if json_data_hash is None: - TaskService.update_task_data_on_task_model(task_model, {}, "json_data_hash") + cls.update_task_data_on_task_model(task_model, {}, "json_data_hash") else: task_model.json_data_hash = json_data_hash if python_env_data_hash is None: - TaskService.update_task_data_on_task_model(task_model, {}, "python_env_data") + cls.update_task_data_on_task_model(task_model, {}, "python_env_data") else: task_model.python_env_data_hash = python_env_data_hash diff --git a/spiffworkflow-backend/tests/data/manual_task_with_subprocesses/manual_task_with_subprocesses.bpmn b/spiffworkflow-backend/tests/data/manual_task_with_subprocesses/manual_task_with_subprocesses.bpmn index 939c8c0b..f49f99cd 100644 --- a/spiffworkflow-backend/tests/data/manual_task_with_subprocesses/manual_task_with_subprocesses.bpmn +++ b/spiffworkflow-backend/tests/data/manual_task_with_subprocesses/manual_task_with_subprocesses.bpmn @@ -22,11 +22,10 @@ set_in_top_level_script = 1 - Flow_09gjylo - Flow_1i7syph + Flow_0yxus36 Flow_00k1tii @@ -48,7 +47,7 @@ except: - Flow_1i7syph + Flow_0yxus36 Flow_187mcqe @@ -67,6 +66,7 @@ except: set_top_level_process_script_after_gate = 1 + @@ -102,10 +102,6 @@ except: - - - - @@ -128,6 +124,10 @@ except: + + + + diff --git a/spiffworkflow-backend/tests/data/manual_task_with_subprocesses/test_process_to_call.bpmn b/spiffworkflow-backend/tests/data/manual_task_with_subprocesses/test_process_to_call.bpmn index afda130a..2bdce678 100644 --- a/spiffworkflow-backend/tests/data/manual_task_with_subprocesses/test_process_to_call.bpmn +++ b/spiffworkflow-backend/tests/data/manual_task_with_subprocesses/test_process_to_call.bpmn @@ -2,70 +2,131 @@ - Flow_095sred + Flow_089aeua Flow_1qsx5et Flow_1qsx5et - Flow_095sred + Flow_0zedtvv - Flow_12zb3j0 + Flow_0bkk554 - Flow_12zb3j0 - Flow_0iu4d71 - set_in_test_process_to_call_script = 1 + Flow_1cnuh2a + Flow_17hgw9g + set_in_test_process_to_call_subprocess_script = 1 - Flow_0iu4d71 + Flow_17hgw9g - - + + + + + Flow_0bkk554 + Flow_1cnuh2a + + Flow_1nri60d + + + + Flow_1bfzrzu + + + + Flow_1nri60d + Flow_1bfzrzu + set_in_test_process_to_call_subprocess_subprocess_script = 1 + + - + + + + Flow_0zedtvv + Flow_089aeua + set_in_test_process_to_call_script = 1 + + + + - - - + + + + - + - + + + + + - - - - - - - - - + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 9ca008ec..d1f5da24 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 @@ -256,6 +256,54 @@ class TestProcessInstanceProcessor(BaseTest): assert spiff_task is not None assert spiff_task.state == TaskState.COMPLETED + def test_properly_resets_process_to_given_task( + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + with_super_admin_user: UserModel, + ) -> None: + self.create_process_group(client, with_super_admin_user, "test_group", "test_group") + initiator_user = self.find_or_create_user("initiator_user") + finance_user_three = self.find_or_create_user("testuser3") + assert initiator_user.principal is not None + assert finance_user_three.principal is not None + AuthorizationService.import_permissions_from_yaml_file() + + finance_group = GroupModel.query.filter_by(identifier="Finance Team").first() + assert finance_group is not None + + process_model = load_test_spec( + process_model_id="test_group/manual_task_with_subprocesses", + process_model_source_directory="manual_task_with_subprocesses", + ) + process_instance = self.create_process_instance_from_process_model( + process_model=process_model, user=initiator_user + ) + processor = ProcessInstanceProcessor(process_instance) + processor.do_engine_steps(save=True) + assert len(process_instance.active_human_tasks) == 1 + initial_human_task_id = process_instance.active_human_tasks[0].id + + # save again to ensure we go attempt to process the human tasks again + processor.save() + + assert len(process_instance.active_human_tasks) == 1 + assert initial_human_task_id == process_instance.active_human_tasks[0].id + + processor = ProcessInstanceProcessor(process_instance) + human_task_one = process_instance.active_human_tasks[0] + spiff_manual_task = processor.__class__.get_task_by_bpmn_identifier( + human_task_one.task_name, processor.bpmn_process_instance + ) + ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one) + + # process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first() + # processor = ProcessInstanceProcessor(process_instance) + # human_task_one = process_instance.active_human_tasks[0] + # spiff_manual_task = processor.bpmn_process_instance.get_task(UUID(human_task_one.task_id)) + # ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one) + def test_properly_saves_tasks_when_running( self, app: Flask, @@ -263,7 +311,6 @@ class TestProcessInstanceProcessor(BaseTest): with_db_and_bpmn_file_cleanup: None, with_super_admin_user: UserModel, ) -> None: - """Test_does_not_recreate_human_tasks_on_multiple_saves.""" self.create_process_group(client, with_super_admin_user, "test_group", "test_group") initiator_user = self.find_or_create_user("initiator_user") finance_user_three = self.find_or_create_user("testuser3") @@ -317,7 +364,7 @@ class TestProcessInstanceProcessor(BaseTest): } third_data_set = { **second_data_set, - **{"set_in_test_process_to_call_script": 1}, + **{"set_in_test_process_to_call_script": 1, "set_in_test_process_to_call_subprocess_subprocess_script": 1, "set_in_test_process_to_call_subprocess_script": 1}, } fourth_data_set = {**third_data_set, **{"a": 1, "we_move_on": True}} fifth_data_set = {**fourth_data_set, **{"validate_only": False, "set_top_level_process_script_after_gate": 1}} @@ -338,10 +385,13 @@ class TestProcessInstanceProcessor(BaseTest): # TODO: also check task data here from the spiff_task directly to ensure we hydrated spiff correctly def assert_spiff_task_is_in_process(spiff_task_identifier: str, bpmn_process_identifier: str) -> None: if spiff_task.task_spec.name == spiff_task_identifier: - base_failure_message = f"Failed on {bpmn_process_identifier} - {spiff_task_identifier}." - expected_python_env_data = expected_task_data[spiff_task.task_spec.name] + expected_task_data_key = spiff_task.task_spec.name if spiff_task.task_spec.name in spiff_tasks_checked_once: - expected_python_env_data = expected_task_data[f"{spiff_task.task_spec.name}_second"] + expected_task_data_key = f"{spiff_task.task_spec.name}_second" + + expected_python_env_data = expected_task_data[expected_task_data_key] + + base_failure_message = f"Failed on {bpmn_process_identifier} - {spiff_task_identifier} - task data key {expected_task_data_key}." task_model = TaskModel.query.filter_by(guid=str(spiff_task.id)).first() assert task_model.start_in_seconds is not None @@ -354,7 +404,7 @@ class TestProcessInstanceProcessor(BaseTest): assert task_definition.bpmn_process_definition.bpmn_identifier == bpmn_process_identifier message = ( - f"{base_failure_message} Expected: {expected_python_env_data}. Received: {task_model.json_data()}" + f"{base_failure_message} Expected: {sorted(expected_python_env_data)}. Received: {sorted(task_model.json_data())}" ) # TODO: if we split out env data again we will need to use it here instead of json_data # assert task_model.python_env_data() == expected_python_env_data, message