added test for loopback to subprocess and fixed issue w/ burnettk
This commit is contained in:
parent
ac730e57a9
commit
fefac239e2
|
@ -1897,6 +1897,11 @@ class ProcessInstanceProcessor:
|
||||||
all_tasks = self.bpmn_process_instance.get_tasks(TaskState.ANY_MASK)
|
all_tasks = self.bpmn_process_instance.get_tasks(TaskState.ANY_MASK)
|
||||||
return [t for t in all_tasks if t.state in [TaskState.WAITING, TaskState.READY]]
|
return [t for t in all_tasks if t.state in [TaskState.WAITING, TaskState.READY]]
|
||||||
|
|
||||||
|
def get_task_by_guid(
|
||||||
|
self, task_guid: str
|
||||||
|
) -> Optional[SpiffTask]:
|
||||||
|
return self.bpmn_process_instance.get_task_from_id(UUID(task_guid))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_task_by_bpmn_identifier(
|
def get_task_by_bpmn_identifier(
|
||||||
cls, bpmn_task_identifier: str, bpmn_process_instance: BpmnWorkflow
|
cls, bpmn_task_identifier: str, bpmn_process_instance: BpmnWorkflow
|
||||||
|
|
|
@ -60,7 +60,7 @@ class TaskService:
|
||||||
spiff_task: SpiffTask,
|
spiff_task: SpiffTask,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.process_spiff_task_children(spiff_task)
|
self.process_spiff_task_children(spiff_task)
|
||||||
self.process_spiff_task_parents(spiff_task)
|
self.process_spiff_task_parent_subprocess_tasks(spiff_task)
|
||||||
self.save_objects_to_database()
|
self.save_objects_to_database()
|
||||||
|
|
||||||
def process_spiff_task_children(
|
def process_spiff_task_children(
|
||||||
|
@ -68,9 +68,9 @@ class TaskService:
|
||||||
spiff_task: SpiffTask,
|
spiff_task: SpiffTask,
|
||||||
) -> None:
|
) -> None:
|
||||||
for child_spiff_task in spiff_task.children:
|
for child_spiff_task in spiff_task.children:
|
||||||
if child_spiff_task._has_state(TaskState.PREDICTED_MASK):
|
# if child_spiff_task._has_state(TaskState.PREDICTED_MASK):
|
||||||
self.__class__.remove_spiff_task_from_parent(child_spiff_task, self.task_models)
|
# self.__class__.remove_spiff_task_from_parent(child_spiff_task, self.task_models)
|
||||||
continue
|
# continue
|
||||||
self.update_task_model_with_spiff_task(
|
self.update_task_model_with_spiff_task(
|
||||||
spiff_task=child_spiff_task,
|
spiff_task=child_spiff_task,
|
||||||
)
|
)
|
||||||
|
@ -78,10 +78,15 @@ class TaskService:
|
||||||
spiff_task=child_spiff_task,
|
spiff_task=child_spiff_task,
|
||||||
)
|
)
|
||||||
|
|
||||||
def process_spiff_task_parents(
|
def process_spiff_task_parent_subprocess_tasks(
|
||||||
self,
|
self,
|
||||||
spiff_task: SpiffTask,
|
spiff_task: SpiffTask,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""Find the parent subprocess of a given spiff_task and update its data.
|
||||||
|
|
||||||
|
This will also process that subprocess task's children and will recurse upwards
|
||||||
|
to process its parent subprocesses as well.
|
||||||
|
"""
|
||||||
(parent_subprocess_guid, _parent_subprocess) = self.__class__.task_subprocess(spiff_task)
|
(parent_subprocess_guid, _parent_subprocess) = self.__class__.task_subprocess(spiff_task)
|
||||||
if parent_subprocess_guid is not None:
|
if parent_subprocess_guid is not None:
|
||||||
spiff_task_of_parent_subprocess = spiff_task.workflow._get_outermost_workflow().get_task_from_id(
|
spiff_task_of_parent_subprocess = spiff_task.workflow._get_outermost_workflow().get_task_from_id(
|
||||||
|
@ -92,7 +97,10 @@ class TaskService:
|
||||||
self.update_task_model_with_spiff_task(
|
self.update_task_model_with_spiff_task(
|
||||||
spiff_task=spiff_task_of_parent_subprocess,
|
spiff_task=spiff_task_of_parent_subprocess,
|
||||||
)
|
)
|
||||||
self.process_spiff_task_parents(
|
self.process_spiff_task_children(
|
||||||
|
spiff_task=spiff_task_of_parent_subprocess,
|
||||||
|
)
|
||||||
|
self.process_spiff_task_parent_subprocess_tasks(
|
||||||
spiff_task=spiff_task_of_parent_subprocess,
|
spiff_task=spiff_task_of_parent_subprocess,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -391,9 +399,9 @@ class TaskService:
|
||||||
# we are going to avoid saving likely and maybe tasks to the db.
|
# 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.
|
# 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))
|
spiff_task = spiff_workflow.get_task_from_id(UUID(task_id))
|
||||||
if spiff_task._has_state(TaskState.PREDICTED_MASK):
|
# if spiff_task._has_state(TaskState.PREDICTED_MASK):
|
||||||
cls.remove_spiff_task_from_parent(spiff_task, new_task_models)
|
# cls.remove_spiff_task_from_parent(spiff_task, new_task_models)
|
||||||
continue
|
# continue
|
||||||
|
|
||||||
task_model = TaskModel.query.filter_by(guid=task_id).first()
|
task_model = TaskModel.query.filter_by(guid=task_id).first()
|
||||||
if task_model is None:
|
if task_model is None:
|
||||||
|
|
|
@ -110,8 +110,8 @@ class TaskModelSavingDelegate(EngineStepDelegate):
|
||||||
# ):
|
# ):
|
||||||
# self._update_task_model_with_spiff_task(waiting_spiff_task)
|
# self._update_task_model_with_spiff_task(waiting_spiff_task)
|
||||||
if self.last_completed_spiff_task is not None:
|
if self.last_completed_spiff_task is not None:
|
||||||
import pdb; pdb.set_trace()
|
# import pdb; pdb.set_trace()
|
||||||
self.task_service.process_spiff_task_parents(self.last_completed_spiff_task)
|
self.task_service.process_spiff_task_parent_subprocess_tasks(self.last_completed_spiff_task)
|
||||||
self.task_service.process_spiff_task_children(self.last_completed_spiff_task)
|
self.task_service.process_spiff_task_children(self.last_completed_spiff_task)
|
||||||
|
|
||||||
def _should_update_task_model(self) -> bool:
|
def _should_update_task_model(self) -> bool:
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
|
||||||
|
<bpmn:process id="test_loopback_to_subprocess" isExecutable="true">
|
||||||
|
<bpmn:startEvent id="Event_17ujsfj">
|
||||||
|
<bpmn:outgoing>Flow_1dk6oyl</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:exclusiveGateway id="gateway" name="Gateway" default="Flow_11uu31d">
|
||||||
|
<bpmn:incoming>Flow_0s9lss3</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_02xy1ag</bpmn:outgoing>
|
||||||
|
<bpmn:outgoing>Flow_11uu31d</bpmn:outgoing>
|
||||||
|
</bpmn:exclusiveGateway>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0s9lss3" sourceRef="script_task" targetRef="gateway" />
|
||||||
|
<bpmn:scriptTask id="script_task" name="Script Task">
|
||||||
|
<bpmn:incoming>Flow_0sw85uk</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0s9lss3</bpmn:outgoing>
|
||||||
|
<bpmn:script>x=1</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
<bpmn:endEvent id="Event_0ryttlc">
|
||||||
|
<bpmn:incoming>Flow_02xy1ag</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_02xy1ag" sourceRef="gateway" targetRef="Event_0ryttlc">
|
||||||
|
<bpmn:conditionExpression>x==2</bpmn:conditionExpression>
|
||||||
|
</bpmn:sequenceFlow>
|
||||||
|
<bpmn:sequenceFlow id="Flow_1dk6oyl" sourceRef="Event_17ujsfj" targetRef="subprocess" />
|
||||||
|
<bpmn:sequenceFlow id="Flow_0sw85uk" sourceRef="subprocess" targetRef="script_task" />
|
||||||
|
<bpmn:subProcess id="subprocess" name="Subprocess">
|
||||||
|
<bpmn:incoming>Flow_1dk6oyl</bpmn:incoming>
|
||||||
|
<bpmn:incoming>Flow_11uu31d</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0sw85uk</bpmn:outgoing>
|
||||||
|
<bpmn:startEvent id="Event_17df4es">
|
||||||
|
<bpmn:outgoing>Flow_0ih1i19</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0ih1i19" sourceRef="Event_17df4es" targetRef="subprocess_manual_task" />
|
||||||
|
<bpmn:endEvent id="Event_1ehwj0c">
|
||||||
|
<bpmn:incoming>Flow_0dua5j8</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0dua5j8" sourceRef="subprocess_manual_task" targetRef="Event_1ehwj0c" />
|
||||||
|
<bpmn:manualTask id="subprocess_manual_task" name="Subprocess Manual Task">
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<spiffworkflow:instructionsForEndUser>HEY MANUAL</spiffworkflow:instructionsForEndUser>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>Flow_0ih1i19</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0dua5j8</bpmn:outgoing>
|
||||||
|
</bpmn:manualTask>
|
||||||
|
</bpmn:subProcess>
|
||||||
|
<bpmn:sequenceFlow id="Flow_11uu31d" sourceRef="gateway" targetRef="subprocess" />
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="test_loopback_to_subprocess">
|
||||||
|
<bpmndi:BPMNShape id="Event_17ujsfj_di" bpmnElement="Event_17ujsfj">
|
||||||
|
<dc:Bounds x="122" y="-168" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Gateway_16ouwyf_di" bpmnElement="gateway" isMarkerVisible="true">
|
||||||
|
<dc:Bounds x="565" y="-175" width="50" height="50" />
|
||||||
|
<bpmndi:BPMNLabel>
|
||||||
|
<dc:Bounds x="568" y="-118" width="44" height="14" />
|
||||||
|
</bpmndi:BPMNLabel>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_1tvzm43_di" bpmnElement="script_task">
|
||||||
|
<dc:Bounds x="370" y="-190" width="100" height="80" />
|
||||||
|
<bpmndi:BPMNLabel />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_0ryttlc_di" bpmnElement="Event_0ryttlc">
|
||||||
|
<dc:Bounds x="712" y="-168" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_10og25a_di" bpmnElement="subprocess">
|
||||||
|
<dc:Bounds x="210" y="-190" width="100" height="80" />
|
||||||
|
<bpmndi:BPMNLabel />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0s9lss3_di" bpmnElement="Flow_0s9lss3">
|
||||||
|
<di:waypoint x="470" y="-150" />
|
||||||
|
<di:waypoint x="565" y="-150" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_02xy1ag_di" bpmnElement="Flow_02xy1ag">
|
||||||
|
<di:waypoint x="615" y="-150" />
|
||||||
|
<di:waypoint x="712" y="-150" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1dk6oyl_di" bpmnElement="Flow_1dk6oyl">
|
||||||
|
<di:waypoint x="158" y="-150" />
|
||||||
|
<di:waypoint x="210" y="-150" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0sw85uk_di" bpmnElement="Flow_0sw85uk">
|
||||||
|
<di:waypoint x="310" y="-150" />
|
||||||
|
<di:waypoint x="370" y="-150" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_11uu31d_di" bpmnElement="Flow_11uu31d">
|
||||||
|
<di:waypoint x="590" y="-175" />
|
||||||
|
<di:waypoint x="590" y="-250" />
|
||||||
|
<di:waypoint x="438" y="-250" />
|
||||||
|
<di:waypoint x="303" y="-189" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_0d2d8pf">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_0ez33hq" bpmnElement="subprocess">
|
||||||
|
<bpmndi:BPMNShape id="Event_17df4es_di" bpmnElement="Event_17df4es">
|
||||||
|
<dc:Bounds x="212" y="172" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Event_1ehwj0c_di" bpmnElement="Event_1ehwj0c">
|
||||||
|
<dc:Bounds x="452" y="172" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_0va03mf_di" bpmnElement="subprocess_manual_task">
|
||||||
|
<dc:Bounds x="300" y="150" width="100" height="80" />
|
||||||
|
<bpmndi:BPMNLabel />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0ih1i19_di" bpmnElement="Flow_0ih1i19">
|
||||||
|
<di:waypoint x="248" y="190" />
|
||||||
|
<di:waypoint x="300" y="190" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0dua5j8_di" bpmnElement="Flow_0dua5j8">
|
||||||
|
<di:waypoint x="400" y="190" />
|
||||||
|
<di:waypoint x="452" y="190" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -696,14 +696,48 @@ class TestProcessInstanceProcessor(BaseTest):
|
||||||
assert len(process_instance.human_tasks) == 2
|
assert len(process_instance.human_tasks) == 2
|
||||||
human_task_two = process_instance.active_human_tasks[0]
|
human_task_two = process_instance.active_human_tasks[0]
|
||||||
|
|
||||||
# this is just asserting the way the functionality currently works in spiff.
|
|
||||||
# we would actually expect this to change one day if we stop reusing the same guid
|
|
||||||
# when we re-do a task.
|
|
||||||
# assert human_task_two.task_id == human_task_one.task_id
|
|
||||||
|
|
||||||
# EDIT: when using feature/remove-loop-reset branch of SpiffWorkflow, these should be different.
|
|
||||||
assert human_task_two.task_id != human_task_one.task_id
|
assert human_task_two.task_id != human_task_one.task_id
|
||||||
|
|
||||||
|
def test_it_can_loopback_to_previous_bpmn_subprocess_with_gateway(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
client: FlaskClient,
|
||||||
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
|
) -> None:
|
||||||
|
initiator_user = self.find_or_create_user("initiator_user")
|
||||||
|
process_model = load_test_spec(
|
||||||
|
process_model_id="test_group/loopback_to_subprocess",
|
||||||
|
process_model_source_directory="loopback_to_subprocess",
|
||||||
|
)
|
||||||
|
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
|
||||||
|
assert len(process_instance.human_tasks) == 1
|
||||||
|
human_task_one = process_instance.active_human_tasks[0]
|
||||||
|
|
||||||
|
spiff_task = processor.get_task_by_guid(human_task_one.task_id)
|
||||||
|
ProcessInstanceService.complete_form_task(processor, spiff_task, {}, initiator_user, human_task_one)
|
||||||
|
|
||||||
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
|
assert len(process_instance.active_human_tasks) == 1
|
||||||
|
assert len(process_instance.human_tasks) == 2
|
||||||
|
human_task_two = process_instance.active_human_tasks[0]
|
||||||
|
spiff_task = processor.get_task_by_guid(human_task_two.task_id)
|
||||||
|
ProcessInstanceService.complete_form_task(processor, spiff_task, {}, initiator_user, human_task_two)
|
||||||
|
|
||||||
|
import pdb; pdb.set_trace()
|
||||||
|
# ensure this does not raise a KeyError
|
||||||
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
|
assert len(process_instance.active_human_tasks) == 1
|
||||||
|
assert len(process_instance.human_tasks) == 3
|
||||||
|
human_task_three = process_instance.active_human_tasks[0]
|
||||||
|
spiff_task = processor.get_task_by_guid(human_task_three.task_id)
|
||||||
|
ProcessInstanceService.complete_form_task(processor, spiff_task, {}, initiator_user, human_task_three)
|
||||||
|
|
||||||
def test_task_data_is_set_even_if_process_instance_errors(
|
def test_task_data_is_set_even_if_process_instance_errors(
|
||||||
self,
|
self,
|
||||||
app: Flask,
|
app: Flask,
|
||||||
|
|
Loading…
Reference in New Issue