Improvement/flexible task iteration (#507)
* updated to use new spiff branch and fixed broken tests w/ burnettk essweine * updated spiffworkflow with new main build w/ burnettk essweine * initial updates to new spiff branch w/ burnettk essweine * more updates for new spiff w/ burnettk essweine * fixed some linting issues w/ burnettk essweine * fixed some failing tests w/ burnettk * updated spiffworkflow for cancel fix w/ burnettk * Improvement/flexible task iteration 2 (#504) * wip * consistent failure, mostly * removing test code and tests * removing unused test bpmn files * removing unused test bpmn files * minor cleanup of commented code * spaces and unused imports * go back to spiff on main --------- Co-authored-by: burnettk <burnettk@users.noreply.github.com> * lint * updated test to reflect storing predicted tasks w/ burnettk * add some orders so postgres does not do whatever it wants, and clear log * fix lint --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com> Co-authored-by: danfunk <daniel.h.funk@gmail.com> Co-authored-by: burnettk <burnettk@users.noreply.github.com>
This commit is contained in:
parent
c986dbb9e5
commit
1826cc4b6c
|
@ -70,11 +70,19 @@ if [[ "$subcommand" != "pre" ]] || [[ -n "$(git status --porcelain "spiffworkflo
|
|||
run_pre_commmit || run_pre_commmit
|
||||
fi
|
||||
|
||||
function clear_log_file() {
|
||||
unit_testing_log_file="./log/unit_testing.log"
|
||||
if [[ -f "$unit_testing_log_file" ]]; then
|
||||
> "$unit_testing_log_file"
|
||||
fi
|
||||
}
|
||||
|
||||
for python_project in "${python_projects[@]}"; do
|
||||
if [[ "$subcommand" != "pre" ]] || [[ -n "$(git status --porcelain "$python_project")" ]]; then
|
||||
pushd "$python_project"
|
||||
poetry install
|
||||
poetry run mypy $(get_python_dirs)
|
||||
clear_log_file
|
||||
./bin/tests-par
|
||||
popd
|
||||
fi
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "alembic"
|
||||
|
@ -2366,7 +2366,7 @@ lxml = "*"
|
|||
type = "git"
|
||||
url = "https://github.com/sartography/SpiffWorkflow"
|
||||
reference = "main"
|
||||
resolved_reference = "f113aba0f59f18e9dce7263289c441a28a83b4c6"
|
||||
resolved_reference = "90159bd23c3c74fcf480414473e851460a01e92c"
|
||||
|
||||
[[package]]
|
||||
name = "sqlalchemy"
|
||||
|
@ -2419,7 +2419,7 @@ files = [
|
|||
]
|
||||
|
||||
[package.dependencies]
|
||||
greenlet = {version = "!=0.4.17", markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\""}
|
||||
greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""}
|
||||
typing-extensions = ">=4.2.0"
|
||||
|
||||
[package.extras]
|
||||
|
|
|
@ -8,7 +8,7 @@ from typing import Any
|
|||
import marshmallow
|
||||
from marshmallow import Schema
|
||||
from marshmallow_enum import EnumField # type: ignore
|
||||
from SpiffWorkflow.task import TaskStateNames # type: ignore
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
|
@ -232,9 +232,8 @@ class Task:
|
|||
|
||||
@classmethod
|
||||
def task_state_name_to_int(cls, task_state_name: str) -> int:
|
||||
task_state_integers = {v: k for k, v in TaskStateNames.items()}
|
||||
task_state_int: int = task_state_integers[task_state_name]
|
||||
return task_state_int
|
||||
state_value: int = TaskState.get_value(task_state_name)
|
||||
return state_value
|
||||
|
||||
|
||||
class OptionSchema(Schema):
|
||||
|
|
|
@ -18,7 +18,7 @@ from MySQLdb import OperationalError # type: ignore
|
|||
from SpiffWorkflow.bpmn.exceptions import WorkflowTaskException # type: ignore
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import asc
|
||||
from sqlalchemy import desc
|
||||
|
@ -493,7 +493,7 @@ def _interstitial_stream(
|
|||
) -> Generator[str, str | None, None]:
|
||||
def get_reportable_tasks() -> Any:
|
||||
return processor.bpmn_process_instance.get_tasks(
|
||||
TaskState.WAITING | TaskState.STARTED | TaskState.READY | TaskState.ERROR
|
||||
state=TaskState.WAITING | TaskState.STARTED | TaskState.READY | TaskState.ERROR
|
||||
)
|
||||
|
||||
def render_instructions(spiff_task: SpiffTask) -> str:
|
||||
|
@ -607,7 +607,7 @@ def _interstitial_stream(
|
|||
|
||||
|
||||
def _get_ready_engine_step_count(bpmn_process_instance: BpmnWorkflow) -> int:
|
||||
return len([t for t in bpmn_process_instance.get_tasks(TaskState.READY) if not t.task_spec.manual])
|
||||
return len([t for t in bpmn_process_instance.get_tasks(state=TaskState.READY) if not t.task_spec.manual])
|
||||
|
||||
|
||||
def _dequeued_interstitial_stream(
|
||||
|
|
|
@ -41,8 +41,9 @@ from SpiffWorkflow.serializer.exceptions import MissingSpecError # type: ignore
|
|||
from SpiffWorkflow.spiff.parser.process import SpiffBpmnParser # type: ignore
|
||||
from SpiffWorkflow.spiff.serializer.config import SPIFF_SPEC_CONFIG # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore
|
||||
from SpiffWorkflow.util.task import TaskIterator # type: ignore
|
||||
from SpiffWorkflow.util.task import TaskState
|
||||
from spiffworkflow_backend.data_stores.json import JSONDataStore
|
||||
from spiffworkflow_backend.data_stores.json import JSONFileDataStore
|
||||
from spiffworkflow_backend.data_stores.typeahead import TypeaheadDataStore
|
||||
|
@ -790,8 +791,6 @@ class ProcessInstanceProcessor:
|
|||
)
|
||||
bpmn_process_instance.data[ProcessInstanceProcessor.VALIDATION_PROCESS_KEY] = validate_only
|
||||
|
||||
# run _predict to ensure tasks are predicted to add back in LIKELY and MAYBE tasks
|
||||
bpmn_process_instance._predict()
|
||||
return (
|
||||
bpmn_process_instance,
|
||||
full_bpmn_process_dict,
|
||||
|
@ -1044,16 +1043,6 @@ class ProcessInstanceProcessor:
|
|||
|
||||
db.session.add(self.process_instance_model)
|
||||
db.session.commit()
|
||||
|
||||
known_task_ids = [str(t.id) for t in self.bpmn_process_instance.get_tasks()]
|
||||
TaskModel.query.filter(TaskModel.process_instance_id == self.process_instance_model.id).filter(
|
||||
TaskModel.guid.notin_(known_task_ids) # type: ignore
|
||||
).delete()
|
||||
HumanTaskModel.query.filter(HumanTaskModel.process_instance_id == self.process_instance_model.id).filter(
|
||||
HumanTaskModel.task_id.notin_(known_task_ids) # type: ignore
|
||||
).delete()
|
||||
db.session.commit()
|
||||
|
||||
human_tasks = HumanTaskModel.query.filter_by(
|
||||
process_instance_id=self.process_instance_model.id, completed=False
|
||||
).all()
|
||||
|
@ -1111,7 +1100,7 @@ class ProcessInstanceProcessor:
|
|||
task_name=ready_or_waiting_task.task_spec.bpmn_id,
|
||||
task_title=ready_or_waiting_task.task_spec.bpmn_name,
|
||||
task_type=ready_or_waiting_task.task_spec.__class__.__name__,
|
||||
task_status=ready_or_waiting_task.get_state_name(),
|
||||
task_status=TaskState.get_name(ready_or_waiting_task.state),
|
||||
lane_assignment_id=potential_owner_hash["lane_assignment_id"],
|
||||
)
|
||||
db.session.add(human_task)
|
||||
|
@ -1365,14 +1354,14 @@ class ProcessInstanceProcessor:
|
|||
def status_of(bpmn_process_instance: BpmnWorkflow) -> ProcessInstanceStatus:
|
||||
if bpmn_process_instance.is_completed():
|
||||
return ProcessInstanceStatus.complete
|
||||
user_tasks = bpmn_process_instance.get_ready_user_tasks()
|
||||
user_tasks = bpmn_process_instance.get_tasks(state=TaskState.READY, manual=True)
|
||||
|
||||
# workflow.waiting_events (includes timers, and timers have a when firing property)
|
||||
|
||||
# if the process instance has status "waiting" it will get picked up
|
||||
# by background processing. when that happens it can potentially overwrite
|
||||
# human tasks which is bad because we cache them with the previous id's.
|
||||
# waiting_tasks = bpmn_process_instance.get_tasks(TaskState.WAITING)
|
||||
# waiting_tasks = bpmn_process_instance.get_tasks(state=TaskState.WAITING)
|
||||
# waiting_tasks = bpmn_process_instance.get_waiting()
|
||||
# if len(waiting_tasks) > 0:
|
||||
# return ProcessInstanceStatus.waiting
|
||||
|
@ -1409,7 +1398,7 @@ class ProcessInstanceProcessor:
|
|||
return None
|
||||
|
||||
def lazy_load_subprocess_specs(self) -> None:
|
||||
tasks = self.bpmn_process_instance.get_tasks(TaskState.DEFINITE_MASK)
|
||||
tasks = self.bpmn_process_instance.get_tasks(state=TaskState.DEFINITE_MASK)
|
||||
loaded_specs = set(self.bpmn_process_instance.subprocess_specs.keys())
|
||||
for task in tasks:
|
||||
if task.task_spec.description != "Call Activity":
|
||||
|
@ -1489,7 +1478,7 @@ class ProcessInstanceProcessor:
|
|||
|
||||
@classmethod
|
||||
def get_tasks_with_data(cls, bpmn_process_instance: BpmnWorkflow) -> list[SpiffTask]:
|
||||
return [task for task in bpmn_process_instance.get_tasks(TaskState.FINISHED_MASK) if len(task.data) > 0]
|
||||
return [task for task in bpmn_process_instance.get_tasks(state=TaskState.FINISHED_MASK) if len(task.data) > 0]
|
||||
|
||||
@classmethod
|
||||
def get_task_data_size(cls, bpmn_process_instance: BpmnWorkflow) -> int:
|
||||
|
@ -1531,7 +1520,7 @@ class ProcessInstanceProcessor:
|
|||
return self._serializer.workflow_to_dict(self.bpmn_process_instance) # type: ignore
|
||||
|
||||
def next_user_tasks(self) -> list[SpiffTask]:
|
||||
return self.bpmn_process_instance.get_ready_user_tasks() # type: ignore
|
||||
return self.bpmn_process_instance.get_tasks(state=TaskState.READY, manual=True) # type: ignore
|
||||
|
||||
def next_task(self) -> SpiffTask:
|
||||
"""Returns the next task that should be completed even if there are parallel tasks and multiple options are available.
|
||||
|
@ -1545,7 +1534,7 @@ class ProcessInstanceProcessor:
|
|||
|
||||
endtasks = []
|
||||
if self.bpmn_process_instance.is_completed():
|
||||
for spiff_task in SpiffTask.Iterator(self.bpmn_process_instance.task_tree, TaskState.ANY_MASK):
|
||||
for spiff_task in TaskIterator(self.bpmn_process_instance.task_tree, TaskState.ANY_MASK):
|
||||
# Assure that we find the end event for this process_instance, and not for any sub-process_instances.
|
||||
if TaskService.is_main_process_end_event(spiff_task):
|
||||
endtasks.append(spiff_task)
|
||||
|
@ -1557,17 +1546,17 @@ class ProcessInstanceProcessor:
|
|||
# a parallel gateway with multiple tasks, so prefer ones that share a parent.
|
||||
|
||||
# Get a list of all ready tasks
|
||||
ready_tasks = self.bpmn_process_instance.get_tasks(TaskState.READY)
|
||||
ready_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.READY)
|
||||
|
||||
if len(ready_tasks) == 0:
|
||||
# If no ready tasks exist, check for a waiting task.
|
||||
waiting_tasks = self.bpmn_process_instance.get_tasks(TaskState.WAITING)
|
||||
waiting_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.WAITING)
|
||||
if len(waiting_tasks) > 0:
|
||||
return waiting_tasks[0]
|
||||
|
||||
# If there are no ready tasks, and not waiting tasks, return the latest error.
|
||||
error_task = None
|
||||
for task in SpiffTask.Iterator(self.bpmn_process_instance.task_tree, TaskState.ERROR):
|
||||
for task in TaskIterator(self.bpmn_process_instance.task_tree, TaskState.ERROR):
|
||||
error_task = task
|
||||
return error_task
|
||||
|
||||
|
@ -1582,7 +1571,7 @@ class ProcessInstanceProcessor:
|
|||
last_user_task = completed_user_tasks[0]
|
||||
if len(ready_tasks) > 0:
|
||||
for task in ready_tasks:
|
||||
if task._is_descendant_of(last_user_task):
|
||||
if task.is_descendant_of(last_user_task):
|
||||
return task
|
||||
for task in ready_tasks:
|
||||
if self.bpmn_process_instance.last_task and task.parent == last_user_task.parent:
|
||||
|
@ -1593,12 +1582,12 @@ class ProcessInstanceProcessor:
|
|||
# If there are no ready tasks, but the thing isn't complete yet, find the first non-complete task
|
||||
# and return that
|
||||
next_task_to_return = None
|
||||
for task in SpiffTask.Iterator(self.bpmn_process_instance.task_tree, TaskState.NOT_FINISHED_MASK):
|
||||
for task in TaskIterator(self.bpmn_process_instance.task_tree, TaskState.NOT_FINISHED_MASK):
|
||||
next_task_to_return = task
|
||||
return next_task_to_return
|
||||
|
||||
def completed_user_tasks(self) -> list[SpiffTask]:
|
||||
user_tasks = self.bpmn_process_instance.get_tasks(TaskState.COMPLETED)
|
||||
user_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.COMPLETED)
|
||||
user_tasks.reverse()
|
||||
user_tasks = list(
|
||||
filter(
|
||||
|
@ -1638,7 +1627,7 @@ class ProcessInstanceProcessor:
|
|||
|
||||
human_task.completed_by_user_id = user.id
|
||||
human_task.completed = True
|
||||
human_task.task_status = spiff_task.get_state_name()
|
||||
human_task.task_status = TaskState.get_name(spiff_task.state)
|
||||
db.session.add(human_task)
|
||||
|
||||
task_service = TaskService(
|
||||
|
@ -1701,11 +1690,11 @@ class ProcessInstanceProcessor:
|
|||
return self.process_instance_model.id
|
||||
|
||||
def get_ready_user_tasks(self) -> list[SpiffTask]:
|
||||
return self.bpmn_process_instance.get_ready_user_tasks() # type: ignore
|
||||
return self.bpmn_process_instance.get_tasks(state=TaskState.READY, manual=True) # type: ignore
|
||||
|
||||
def get_current_user_tasks(self) -> list[SpiffTask]:
|
||||
"""Return a list of all user tasks that are READY or COMPLETE and are parallel to the READY Task."""
|
||||
ready_tasks = self.bpmn_process_instance.get_ready_user_tasks()
|
||||
ready_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.READY, manual=True)
|
||||
additional_tasks = []
|
||||
if len(ready_tasks) > 0:
|
||||
for child in ready_tasks[0].parent.children:
|
||||
|
@ -1714,19 +1703,19 @@ class ProcessInstanceProcessor:
|
|||
return ready_tasks + additional_tasks # type: ignore
|
||||
|
||||
def get_all_user_tasks(self) -> list[SpiffTask]:
|
||||
all_tasks = self.bpmn_process_instance.get_tasks(TaskState.ANY_MASK)
|
||||
all_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.ANY_MASK)
|
||||
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(TaskState.ANY_MASK)
|
||||
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]]
|
||||
|
||||
def get_all_waiting_tasks(self) -> list[SpiffTask]:
|
||||
all_tasks = self.bpmn_process_instance.get_tasks(TaskState.ANY_MASK)
|
||||
all_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.ANY_MASK)
|
||||
return [t for t in all_tasks if t.state in [TaskState.WAITING]]
|
||||
|
||||
def get_all_ready_or_waiting_tasks(self) -> list[SpiffTask]:
|
||||
all_tasks = self.bpmn_process_instance.get_tasks(TaskState.ANY_MASK)
|
||||
all_tasks = self.bpmn_process_instance.get_tasks(state=TaskState.ANY_MASK)
|
||||
return [t for t in all_tasks if t.state in [TaskState.WAITING, TaskState.READY]]
|
||||
|
||||
def get_task_by_guid(self, task_guid: str) -> SpiffTask | None:
|
||||
|
@ -1736,7 +1725,7 @@ class ProcessInstanceProcessor:
|
|||
def get_task_by_bpmn_identifier(
|
||||
cls, bpmn_task_identifier: str, bpmn_process_instance: BpmnWorkflow
|
||||
) -> SpiffTask | None:
|
||||
all_tasks = bpmn_process_instance.get_tasks(TaskState.ANY_MASK)
|
||||
all_tasks = bpmn_process_instance.get_tasks(state=TaskState.ANY_MASK)
|
||||
for task in all_tasks:
|
||||
if task.task_spec.name == bpmn_task_identifier:
|
||||
return task
|
||||
|
|
|
@ -14,6 +14,7 @@ from SpiffWorkflow.bpmn.event import PendingBpmnEvent # type: ignore
|
|||
from SpiffWorkflow.bpmn.specs.control import BoundaryEventSplit # type: ignore
|
||||
from SpiffWorkflow.bpmn.specs.event_definitions.timer import TimerEventDefinition # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from spiffworkflow_backend import db
|
||||
from spiffworkflow_backend.exceptions.api_error import ApiError
|
||||
from spiffworkflow_backend.models.group import GroupModel
|
||||
|
@ -199,7 +200,7 @@ class ProcessInstanceService:
|
|||
|
||||
@classmethod
|
||||
def ready_user_task_has_associated_timer(cls, processor: ProcessInstanceProcessor) -> bool:
|
||||
for ready_user_task in processor.bpmn_process_instance.get_ready_user_tasks():
|
||||
for ready_user_task in processor.bpmn_process_instance.get_tasks(state=TaskState.READY, manual=True):
|
||||
if isinstance(ready_user_task.parent.task_spec, BoundaryEventSplit):
|
||||
return True
|
||||
return False
|
||||
|
@ -596,7 +597,7 @@ class ProcessInstanceService:
|
|||
spiff_task.task_spec.bpmn_id,
|
||||
spiff_task.task_spec.bpmn_name,
|
||||
task_type,
|
||||
spiff_task.get_state_name(),
|
||||
TaskState.get_name(spiff_task.state),
|
||||
can_complete=can_complete,
|
||||
lane=lane,
|
||||
process_identifier=spiff_task.task_spec._wf_spec.name,
|
||||
|
|
|
@ -10,7 +10,7 @@ from lxml import etree # type: ignore
|
|||
from SpiffWorkflow.bpmn.exceptions import WorkflowTaskException # type: ignore
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from spiffworkflow_backend.services.custom_parser import MyCustomParser
|
||||
|
||||
|
||||
|
@ -126,7 +126,7 @@ class ProcessModelTestRunnerMostlyPureSpiffDelegate(ProcessModelTestRunnerDelega
|
|||
spiff_task.run()
|
||||
|
||||
def get_next_task(self, bpmn_process_instance: BpmnWorkflow) -> SpiffTask | None:
|
||||
ready_tasks = list(bpmn_process_instance.get_tasks(TaskState.READY))
|
||||
ready_tasks = list(bpmn_process_instance.get_tasks(state=TaskState.READY))
|
||||
if len(ready_tasks) > 0:
|
||||
return ready_tasks[0]
|
||||
return None
|
||||
|
|
|
@ -9,7 +9,7 @@ from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflow # type: ignore
|
|||
from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer
|
||||
from SpiffWorkflow.exceptions import WorkflowException # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskStateNames
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
|
||||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessNotFoundError
|
||||
from spiffworkflow_backend.models.bpmn_process_definition import BpmnProcessDefinitionModel
|
||||
|
@ -136,6 +136,9 @@ class TaskService:
|
|||
spiff_task: SpiffTask,
|
||||
) -> None:
|
||||
for child_spiff_task in spiff_task.children:
|
||||
if child_spiff_task.has_state(TaskState.PREDICTED_MASK):
|
||||
self.__class__.remove_spiff_task_from_parent(child_spiff_task, self.task_models)
|
||||
continue
|
||||
self.update_task_model_with_spiff_task(
|
||||
spiff_task=child_spiff_task,
|
||||
)
|
||||
|
@ -265,7 +268,7 @@ class TaskService:
|
|||
spiff_task_data = new_properties_json.pop("data")
|
||||
python_env_data_dict = self.__class__._get_python_env_data_dict_from_spiff_task(spiff_task, self.serializer)
|
||||
task_model.properties_json = new_properties_json
|
||||
task_model.state = TaskStateNames[new_properties_json["state"]]
|
||||
task_model.state = TaskState.get_name(new_properties_json["state"])
|
||||
json_data_dict = self.__class__.update_task_data_on_task_model_and_return_dict_if_updated(
|
||||
task_model, spiff_task_data, "json_data_hash"
|
||||
)
|
||||
|
@ -430,6 +433,9 @@ class TaskService:
|
|||
# we are going to avoid saving likely and maybe tasks to the db.
|
||||
# that means we need to remove them from their parents' lists of children as well.
|
||||
spiff_task = spiff_workflow.get_task_from_id(UUID(task_id))
|
||||
if spiff_task.has_state(TaskState.PREDICTED_MASK):
|
||||
self.__class__.remove_spiff_task_from_parent(spiff_task, self.task_models)
|
||||
continue
|
||||
|
||||
task_model = TaskModel.query.filter_by(guid=task_id).first()
|
||||
if task_model is None:
|
||||
|
|
|
@ -16,7 +16,7 @@ from SpiffWorkflow.bpmn.specs.event_definitions.message import MessageEventDefin
|
|||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
||||
from SpiffWorkflow.exceptions import SpiffWorkflowException # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from spiffworkflow_backend.exceptions.api_error import ApiError
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.message_instance import MessageInstanceModel
|
||||
|
@ -166,7 +166,7 @@ class ExecutionStrategy:
|
|||
self.delegate.save(bpmn_process_instance)
|
||||
|
||||
def get_ready_engine_steps(self, bpmn_process_instance: BpmnWorkflow) -> list[SpiffTask]:
|
||||
tasks = [t for t in bpmn_process_instance.get_tasks(TaskState.READY) if not t.task_spec.manual]
|
||||
tasks = [t for t in bpmn_process_instance.get_tasks(state=TaskState.READY) if not t.task_spec.manual]
|
||||
|
||||
if len(tasks) > 0:
|
||||
self.subprocess_spec_loader()
|
||||
|
@ -249,7 +249,7 @@ class TaskModelSavingDelegate(EngineStepDelegate):
|
|||
# but it didn't quite work in all cases, so we deleted it. you can find it in commit
|
||||
# 1ead87b4b496525df8cc0e27836c3e987d593dc0 if you are curious.
|
||||
for waiting_spiff_task in bpmn_process_instance.get_tasks(
|
||||
TaskState.WAITING
|
||||
state=TaskState.WAITING
|
||||
| TaskState.CANCELLED
|
||||
| TaskState.READY
|
||||
| TaskState.MAYBE
|
||||
|
|
|
@ -2,7 +2,7 @@ from datetime import datetime
|
|||
|
||||
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from spiffworkflow_backend.specs.start_event import StartConfiguration
|
||||
from spiffworkflow_backend.specs.start_event import StartEvent
|
||||
|
||||
|
@ -10,7 +10,7 @@ from spiffworkflow_backend.specs.start_event import StartEvent
|
|||
class WorkflowService:
|
||||
@classmethod
|
||||
def future_start_events(cls, workflow: BpmnWorkflow) -> list[SpiffTask]:
|
||||
return [t for t in workflow.get_tasks(TaskState.FUTURE) if isinstance(t.task_spec, StartEvent)]
|
||||
return [t for t in workflow.get_tasks(state=TaskState.FUTURE) if isinstance(t.task_spec, StartEvent)]
|
||||
|
||||
@classmethod
|
||||
def next_start_event_configuration(cls, workflow: BpmnWorkflow, now_in_utc: datetime) -> StartConfiguration | None:
|
||||
|
|
|
@ -9,7 +9,7 @@ from typing import Any
|
|||
import pytest
|
||||
from flask.app import Flask
|
||||
from flask.testing import FlaskClient
|
||||
from SpiffWorkflow.task import TaskState # type: ignore
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from spiffworkflow_backend.exceptions.process_entity_not_found_error import ProcessEntityNotFoundError
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.process_group import ProcessGroup
|
||||
|
@ -1617,7 +1617,7 @@ class TestProcessApi(BaseTest):
|
|||
assert len(ready_tasks) == 1
|
||||
ready_task = ready_tasks[0]
|
||||
|
||||
# check all_tasks here to ensure we actually deleted items when cancelling the instance
|
||||
# check all_tasks here to ensure we actually deleted item when cancelling the instance
|
||||
all_tasks = TaskModel.query.filter_by(process_instance_id=process_instance_id).all()
|
||||
assert len(all_tasks) == 8
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class TestDotNotation(BaseTest):
|
|||
processor.do_engine_steps(save=True)
|
||||
human_task = process_instance.human_tasks[0]
|
||||
|
||||
user_task = processor.get_ready_user_tasks()[0]
|
||||
user_task = processor.get_all_ready_or_waiting_tasks()[0]
|
||||
form_data = {
|
||||
"invoice.contibutorName": "Elizabeth",
|
||||
"invoice.contributorId": 100,
|
||||
|
|
|
@ -52,7 +52,7 @@ class TestJinjaService(BaseTest):
|
|||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True)
|
||||
|
||||
JinjaService.render_instructions_for_end_user(processor.get_ready_user_tasks()[0])
|
||||
JinjaService.render_instructions_for_end_user(processor.get_all_ready_or_waiting_tasks()[0])
|
||||
"\n".join(
|
||||
[
|
||||
r"* From Filter: Sanitized \| from \| filter",
|
||||
|
|
|
@ -5,7 +5,7 @@ from flask import g
|
|||
from flask.app import Flask
|
||||
from flask.testing import FlaskClient
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from SpiffWorkflow.util.task import TaskState # type: ignore
|
||||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
|
||||
from spiffworkflow_backend.models.db import db
|
||||
from spiffworkflow_backend.models.group import GroupModel
|
||||
|
@ -500,7 +500,7 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
assert gateway_task is not None
|
||||
assert gateway_task.state == TaskState.READY
|
||||
|
||||
gateway_task = processor.bpmn_process_instance.get_tasks(TaskState.READY)[0]
|
||||
gateway_task = processor.bpmn_process_instance.get_tasks(state=TaskState.READY)[0]
|
||||
processor.manual_complete_task(str(gateway_task.id), execute=True, user=process_instance.process_initiator)
|
||||
processor.save()
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
|
@ -659,7 +659,9 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
.filter(TaskDefinitionModel.bpmn_identifier == spiff_task.task_spec.name)
|
||||
.count()
|
||||
)
|
||||
assert task_models_with_bpmn_identifier_count < 3, count_failure_message
|
||||
|
||||
# some tasks will have 2 COMPLETED and 1 LIKELY/MAYBE
|
||||
assert task_models_with_bpmn_identifier_count < 4, count_failure_message
|
||||
task_model = TaskModel.query.filter_by(guid=str(spiff_task.id)).first()
|
||||
|
||||
assert task_model.start_in_seconds is not None
|
||||
|
@ -737,8 +739,7 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
.filter(TaskModel.state.in_(["LIKELY", "MAYBE"])) # type: ignore
|
||||
.count()
|
||||
)
|
||||
assert task_models_that_are_predicted_count == 0
|
||||
|
||||
assert task_models_that_are_predicted_count == 4
|
||||
assert processor_final.get_data() == data_set_7
|
||||
|
||||
def test_does_not_recreate_human_tasks_on_multiple_saves(
|
||||
|
|
|
@ -41,6 +41,7 @@ class TestTaskService(BaseTest):
|
|||
bpmn_process_level_2b = (
|
||||
BpmnProcessModel.query.join(BpmnProcessDefinitionModel)
|
||||
.filter(BpmnProcessDefinitionModel.bpmn_identifier == "Level2b")
|
||||
.order_by(BpmnProcessModel.id)
|
||||
.first()
|
||||
)
|
||||
assert bpmn_process_level_2b is not None
|
||||
|
@ -50,6 +51,7 @@ class TestTaskService(BaseTest):
|
|||
bpmn_process_level_3 = (
|
||||
BpmnProcessModel.query.join(BpmnProcessDefinitionModel)
|
||||
.filter(BpmnProcessDefinitionModel.bpmn_identifier == "Level3")
|
||||
.order_by(BpmnProcessModel.id)
|
||||
.first()
|
||||
)
|
||||
assert bpmn_process_level_3 is not None
|
||||
|
@ -86,6 +88,7 @@ class TestTaskService(BaseTest):
|
|||
task_model_level_2b = (
|
||||
TaskModel.query.join(TaskDefinitionModel)
|
||||
.filter(TaskDefinitionModel.bpmn_identifier == "level_2b_subprocess_script_task")
|
||||
.order_by(TaskModel.id)
|
||||
.first()
|
||||
)
|
||||
assert task_model_level_2b is not None
|
||||
|
@ -100,6 +103,7 @@ class TestTaskService(BaseTest):
|
|||
task_model_level_3 = (
|
||||
TaskModel.query.join(TaskDefinitionModel)
|
||||
.filter(TaskDefinitionModel.bpmn_identifier == "level_3_script_task")
|
||||
.order_by(TaskModel.id)
|
||||
.first()
|
||||
)
|
||||
assert task_model_level_3 is not None
|
||||
|
|
|
@ -16,7 +16,10 @@ test('renders hotCrumbs', () => {
|
|||
render(
|
||||
<BrowserRouter>
|
||||
<ProcessBreadcrumb
|
||||
hotCrumbs={[['Process Groups', '/process-groups'], [`Process Group: hey`]]}
|
||||
hotCrumbs={[
|
||||
['Process Groups', '/process-groups'],
|
||||
[`Process Group: hey`],
|
||||
]}
|
||||
/>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue