removed uniqueness constraint from human task so we can loopback to a previous task with a gateway w/ burnettk

This commit is contained in:
jasquat 2023-01-24 11:03:55 -05:00
parent 73cbef3100
commit 81c3cfe172
6 changed files with 114 additions and 12 deletions

View File

@ -1,8 +1,8 @@
"""empty message
Revision ID: 49aae41d7992
Revision ID: 2ec4222f0012
Revises:
Create Date: 2023-01-23 14:23:17.989042
Create Date: 2023-01-24 10:31:26.693063
"""
from alembic import op
@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '49aae41d7992'
revision = '2ec4222f0012'
down_revision = None
branch_labels = None
depends_on = None
@ -206,8 +206,7 @@ def upgrade():
sa.ForeignKeyConstraint(['completed_by_user_id'], ['user.id'], ),
sa.ForeignKeyConstraint(['lane_assignment_id'], ['group.id'], ),
sa.ForeignKeyConstraint(['process_instance_id'], ['process_instance.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('task_id', 'process_instance_id', name='human_task_unique')
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_human_task_completed'), 'human_task', ['completed'], unique=False)
op.create_table('message_correlation',

View File

@ -26,9 +26,6 @@ class HumanTaskModel(SpiffworkflowBaseDBModel):
"""HumanTaskModel."""
__tablename__ = "human_task"
__table_args__ = (
db.UniqueConstraint("task_id", "process_instance_id", name="human_task_unique"),
)
id: int = db.Column(db.Integer, primary_key=True)
process_instance_id: int = db.Column(

View File

@ -790,7 +790,7 @@ class ProcessInstanceProcessor:
db.session.commit()
human_tasks = HumanTaskModel.query.filter_by(
process_instance_id=self.process_instance_model.id
process_instance_id=self.process_instance_model.id, completed=False
).all()
ready_or_waiting_tasks = self.get_all_ready_or_waiting_tasks()
process_model_display_name = ""

View File

@ -0,0 +1,65 @@
<?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:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Process_jm3qjay" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1w7l0lj</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1w7l0lj" sourceRef="StartEvent_1" targetRef="manual_task" />
<bpmn:exclusiveGateway id="loopback_gateway" default="flow_default">
<bpmn:incoming>Flow_1ouak9p</bpmn:incoming>
<bpmn:outgoing>flow_default</bpmn:outgoing>
<bpmn:outgoing>flow_x_equals_one</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_1ouak9p" sourceRef="manual_task" targetRef="loopback_gateway" />
<bpmn:endEvent id="Event_1we3snj">
<bpmn:incoming>flow_default</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="flow_default" sourceRef="loopback_gateway" targetRef="Event_1we3snj" />
<bpmn:manualTask id="manual_task" name="Manual task">
<bpmn:extensionElements>
<spiffworkflow:instructionsForEndUser>HEY</spiffworkflow:instructionsForEndUser>
<spiffworkflow:preScript>x = 1</spiffworkflow:preScript>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1w7l0lj</bpmn:incoming>
<bpmn:incoming>flow_x_equals_one</bpmn:incoming>
<bpmn:outgoing>Flow_1ouak9p</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:sequenceFlow id="flow_x_equals_one" sourceRef="loopback_gateway" targetRef="manual_task">
<bpmn:conditionExpression>x == 1</bpmn:conditionExpression>
</bpmn:sequenceFlow>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_jm3qjay">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_15tztve_di" bpmnElement="loopback_gateway" isMarkerVisible="true">
<dc:Bounds x="425" y="152" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1we3snj_di" bpmnElement="Event_1we3snj">
<dc:Bounds x="532" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1apgvvn_di" bpmnElement="manual_task">
<dc:Bounds x="270" y="137" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1w7l0lj_di" bpmnElement="Flow_1w7l0lj">
<di:waypoint x="215" y="177" />
<di:waypoint x="270" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1ouak9p_di" bpmnElement="Flow_1ouak9p">
<di:waypoint x="370" y="177" />
<di:waypoint x="425" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0icwqfm_di" bpmnElement="flow_default">
<di:waypoint x="475" y="177" />
<di:waypoint x="532" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0jnhclm_di" bpmnElement="flow_x_equals_one">
<di:waypoint x="450" y="152" />
<di:waypoint x="450" y="100" />
<di:waypoint x="348" y="137" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,4 +1,6 @@
"""Test_get_localtime."""
from operator import itemgetter
from flask.app import Flask
from flask.testing import FlaskClient
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
@ -57,6 +59,8 @@ class TestGetAllPermissions(BaseTest):
]
permissions = GetAllPermissions().run(script_attributes_context)
sorted_permissions = sorted(permissions, key=lambda x: x['uri'] or '')
sorted_expected_permissions = sorted(expected_permissions, key=lambda x: x['uri'] or '')
sorted_permissions = sorted(permissions, key=itemgetter("uri"))
sorted_expected_permissions = sorted(
expected_permissions, key=itemgetter("uri")
)
assert sorted_permissions == sorted_expected_permissions

View File

@ -177,7 +177,6 @@ class TestProcessInstanceProcessor(BaseTest):
)
processor = ProcessInstanceProcessor(process_instance)
processor.do_engine_steps(save=True)
processor.save()
assert len(process_instance.active_human_tasks) == 1
human_task = process_instance.active_human_tasks[0]
@ -340,3 +339,41 @@ class TestProcessInstanceProcessor(BaseTest):
).first()
assert process_instance.locked_by is None
assert process_instance.locked_at_in_seconds is None
def test_it_can_loopback_to_previous_bpmn_task_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_manual_task",
bpmn_file_name="loopback.bpmn",
process_model_source_directory="loopback_to_manual_task",
)
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.__class__.get_task_by_bpmn_identifier(
human_task_one.task_name, processor.bpmn_process_instance
)
ProcessInstanceService.complete_form_task(
processor, spiff_task, {}, initiator_user, human_task_one
)
assert len(process_instance.active_human_tasks) == 1
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