added test for loopback to subprocess and fixed issue w/ burnettk
This commit is contained in:
parent
3d595c3e43
commit
be5bf31974
|
@ -1897,6 +1897,11 @@ class ProcessInstanceProcessor:
|
|||
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]]
|
||||
|
||||
def get_task_by_guid(
|
||||
self, task_guid: str
|
||||
) -> Optional[SpiffTask]:
|
||||
return self.bpmn_process_instance.get_task_from_id(UUID(task_guid))
|
||||
|
||||
@classmethod
|
||||
def get_task_by_bpmn_identifier(
|
||||
cls, bpmn_task_identifier: str, bpmn_process_instance: BpmnWorkflow
|
||||
|
|
|
@ -60,7 +60,7 @@ class TaskService:
|
|||
spiff_task: SpiffTask,
|
||||
) -> None:
|
||||
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()
|
||||
|
||||
def process_spiff_task_children(
|
||||
|
@ -68,9 +68,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
|
||||
# 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,
|
||||
)
|
||||
|
@ -78,10 +78,15 @@ class TaskService:
|
|||
spiff_task=child_spiff_task,
|
||||
)
|
||||
|
||||
def process_spiff_task_parents(
|
||||
def process_spiff_task_parent_subprocess_tasks(
|
||||
self,
|
||||
spiff_task: SpiffTask,
|
||||
) -> 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)
|
||||
if parent_subprocess_guid is not None:
|
||||
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(
|
||||
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,
|
||||
)
|
||||
|
||||
|
@ -391,9 +399,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):
|
||||
cls.remove_spiff_task_from_parent(spiff_task, new_task_models)
|
||||
continue
|
||||
# if spiff_task._has_state(TaskState.PREDICTED_MASK):
|
||||
# cls.remove_spiff_task_from_parent(spiff_task, new_task_models)
|
||||
# continue
|
||||
|
||||
task_model = TaskModel.query.filter_by(guid=task_id).first()
|
||||
if task_model is None:
|
||||
|
|
|
@ -110,8 +110,8 @@ class TaskModelSavingDelegate(EngineStepDelegate):
|
|||
# ):
|
||||
# self._update_task_model_with_spiff_task(waiting_spiff_task)
|
||||
if self.last_completed_spiff_task is not None:
|
||||
import pdb; pdb.set_trace()
|
||||
self.task_service.process_spiff_task_parents(self.last_completed_spiff_task)
|
||||
# import pdb; pdb.set_trace()
|
||||
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)
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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(
|
||||
self,
|
||||
app: Flask,
|
||||
|
|
Loading…
Reference in New Issue