added api endpoint to get previously completed user tasks

This commit is contained in:
jasquat 2022-07-20 15:18:57 -04:00
parent 78cde23612
commit 2bbdf8a0d6
6 changed files with 780 additions and 24 deletions

View File

@ -672,9 +672,9 @@ paths:
items: items:
# $ref: "#/components/schemas/ActiveTask" # $ref: "#/components/schemas/ActiveTask"
$ref: "#/components/schemas/Task" $ref: "#/components/schemas/Task"
/tasks/{task_id}: /tasks/{active_task_id}:
parameters: parameters:
- name: task_id - name: active_task_id
in: path in: path
required: true required: true
description: The unique id of an existing process group. description: The unique id of an existing process group.
@ -690,9 +690,33 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/Task" $ref: "#/components/schemas/Task"
/tasks/{task_id}/submit: /tasks/completed_user_task/{process_instance_id}/{spiffworkflow_task_id}:
parameters: parameters:
- name: task_id - name: process_instance_id
in: path
required: true
description: The unique id of an existing process instance.
schema:
type: integer
- name: spiffworkflow_task_id
in: path
required: true
description: The unique id of an existing process group.
schema:
type: string
get:
operationId: spiffworkflow_backend.routes.process_api_blueprint.task_show_completed_user_task
summary: Gets one task that a user wants to complete
responses:
"200":
description: One task
content:
application/json:
schema:
$ref: "#/components/schemas/Task"
/tasks/{active_task_id}/submit:
parameters:
- name: active_task_id
in: path in: path
required: true required: true
description: The unique id of an existing process group. description: The unique id of an existing process group.

View File

@ -26,6 +26,8 @@ class ActiveTaskModel(SpiffworkflowBaseDBModel):
form_json: str | None = "" form_json: str | None = ""
bpmn_json: str = "" bpmn_json: str = ""
preceding_spiffworkflow_user_task_id: int | None = None
assigned_principal: RelationshipProperty[PrincipalModel] = relationship( assigned_principal: RelationshipProperty[PrincipalModel] = relationship(
PrincipalModel PrincipalModel
) )

View File

@ -110,6 +110,12 @@ class Task:
multi_instance_index: str, multi_instance_index: str,
process_name: str, process_name: str,
properties: dict, properties: dict,
process_instance_id: int | None = None,
form_schema: str | None = None,
form_ui_schema: str | None = None,
preceding_spiffworkflow_user_task_id: str | int | None = None,
following_spiffworkflow_user_task_id: str | int | None = None,
current_active_task_id: int | None = None,
): ):
"""__init__.""" """__init__."""
self.id = id self.id = id
@ -121,6 +127,14 @@ class Task:
self.documentation = documentation self.documentation = documentation
self.data = data self.data = data
self.lane = lane self.lane = lane
self.process_instance_id = process_instance_id
self.form_schema = form_schema
self.form_ui_schema = form_ui_schema
self.preceding_spiffworkflow_user_task_id = preceding_spiffworkflow_user_task_id
self.following_spiffworkflow_user_task_id = following_spiffworkflow_user_task_id
self.current_active_task_id = current_active_task_id
self.multi_instance_type = ( self.multi_instance_type = (
multi_instance_type # Some tasks have a repeat behavior. multi_instance_type # Some tasks have a repeat behavior.
) )
@ -228,6 +242,12 @@ class TaskSchema(Schema):
"multi_instance_index", "multi_instance_index",
"process_name", "process_name",
"properties", "properties",
"process_instance_id",
"form_schema",
"form_ui_schema",
"preceding_spiffworkflow_user_task_id",
"following_spiffworkflow_user_task_id",
"current_active_task_id",
] ]
multi_instance_type = EnumField(MultiInstanceType) multi_instance_type = EnumField(MultiInstanceType)

View File

@ -35,6 +35,7 @@ from spiffworkflow_backend.models.process_instance_report import (
) )
from spiffworkflow_backend.models.process_model import ProcessModelInfo from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
from spiffworkflow_backend.models.task import TaskSchema
from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService
from spiffworkflow_backend.services.process_instance_processor import ( from spiffworkflow_backend.services.process_instance_processor import (
ProcessInstanceProcessor, ProcessInstanceProcessor,
@ -550,11 +551,13 @@ def task_list_my_tasks(page: int = 1, per_page: int = 100) -> flask.wrappers.Res
return make_response(jsonify(response_json), 200) return make_response(jsonify(response_json), 200)
def task_show(task_id: int) -> flask.wrappers.Response: def task_show(active_task_id: int) -> flask.wrappers.Response:
"""Task_list_my_tasks.""" """Task_list_my_tasks."""
principal = find_principal_or_raise() principal = find_principal_or_raise()
active_task_assigned_to_me = find_active_task_by_id_or_raise(task_id, principal.id) active_task_assigned_to_me = find_active_task_by_id_or_raise(
active_task_id, principal.id
)
process_instance = find_process_instance_by_id_or_raise( process_instance = find_process_instance_by_id_or_raise(
active_task_assigned_to_me.process_instance_id active_task_assigned_to_me.process_instance_id
@ -568,35 +571,120 @@ def task_show(task_id: int) -> flask.wrappers.Response:
raise ( raise (
ApiError( ApiError(
code="missing_form_file", code="missing_form_file",
message=f"Cannot find a form file for active task {task_id}", message=f"Cannot find a form file for active task {active_task_id}",
status_code=500, status_code=500,
) )
) )
file_contents = SpecFileService.get_data( form_contents = prepare_form_data(
process_model, active_task_assigned_to_me.form_file_name active_task_assigned_to_me.form_file_name,
).decode("utf-8") json.loads(active_task_assigned_to_me.spiffworkflow_task_data),
process_model,
spiffworkflow_data_json = json.loads(
active_task_assigned_to_me.spiffworkflow_task_data
) )
if form_contents:
active_task_assigned_to_me.form_json = form_contents
# trade out pieces like "{{variable_name}}" for the corresponding form data value # FIXME: This should be stored in the db when the active task is created
for key, value in spiffworkflow_data_json.items(): processor = ProcessInstanceProcessor(process_instance)
if isinstance(value, str) or isinstance(value, int): if processor.completed_user_tasks():
file_contents = file_contents.replace("{{" + key + "}}", str(value)) active_task_assigned_to_me.preceding_spiffworkflow_user_task_id = (
processor.completed_user_tasks()[0].id
active_task_assigned_to_me.form_json = file_contents )
return make_response(jsonify(active_task_assigned_to_me), 200) return make_response(jsonify(active_task_assigned_to_me), 200)
def task_show_completed_user_task(
process_instance_id: int, spiffworkflow_task_id: str
) -> flask.wrappers.Response:
"""Task_show_completed_user_task."""
process_instance = find_process_instance_by_id_or_raise(process_instance_id)
processor = ProcessInstanceProcessor(process_instance)
if processor.completed_user_tasks() is None:
raise (
ApiError(
code="no_completed_user_tasks",
message=f"This process instance does not have any completed user tasks: {process_instance_id}",
status_code=400,
)
)
spiffworkflow_task = None
preceding_spiffworkflow_user_task_id = None
following_spiffworkflow_user_task_id = None
for index, completed_user_task in enumerate(processor.completed_user_tasks()):
if str(completed_user_task.id) == spiffworkflow_task_id:
spiffworkflow_task = completed_user_task
preceding_spiffworkflow_user_task_id = get_value_from_array_with_index(
processor.completed_user_tasks(), index + 1
)
following_spiffworkflow_user_task_id = get_value_from_array_with_index(
processor.completed_user_tasks(), index - 1
)
if spiffworkflow_task is None:
raise (
ApiError(
code="no_completed_user_task_with_id",
message=f"This process instance does not have a completed user task with given id: {spiffworkflow_task_id}",
status_code=400,
)
)
process_model = get_process_model(
process_instance.process_model_identifier,
process_instance.process_group_identifier,
)
task = ProcessInstanceService.spiff_task_to_api_task(
spiffworkflow_task, add_docs_and_forms=True
)
form_contents = prepare_form_data(
task.properties["properties"]["formJsonSchemaFilename"],
spiffworkflow_task.data,
process_model,
)
if form_contents is not None:
task.form_schema = form_contents
task.data = spiffworkflow_task.data
if preceding_spiffworkflow_user_task_id:
task.preceding_spiffworkflow_user_task_id = (
preceding_spiffworkflow_user_task_id.id
)
if following_spiffworkflow_user_task_id:
task.following_spiffworkflow_user_task_id = (
following_spiffworkflow_user_task_id.id
)
principal = find_principal_or_raise()
active_task = (
ActiveTaskModel.query.filter_by(
assigned_principal_id=principal.id, process_instance_id=process_instance_id
).order_by(
desc(ActiveTaskModel.id)
) # type: ignore
).first()
task.current_active_task_id = active_task.id
return Response(
json.dumps(TaskSchema().dump(task)), status=200, mimetype="application/json"
)
def task_submit_user_data( def task_submit_user_data(
task_id: int, body: Dict[str, Any], terminate_loop: bool = False active_task_id: int, body: Dict[str, Any], terminate_loop: bool = False
) -> flask.wrappers.Response: ) -> flask.wrappers.Response:
"""Task_submit_user_data.""" """Task_submit_user_data."""
principal = find_principal_or_raise() principal = find_principal_or_raise()
active_task_assigned_to_me = find_active_task_by_id_or_raise(task_id, principal.id) active_task_assigned_to_me = find_active_task_by_id_or_raise(
active_task_id, principal.id
)
process_instance = find_process_instance_by_id_or_raise( process_instance = find_process_instance_by_id_or_raise(
active_task_assigned_to_me.process_instance_id active_task_assigned_to_me.process_instance_id
@ -701,17 +789,17 @@ def find_principal_or_raise() -> PrincipalModel:
def find_active_task_by_id_or_raise( def find_active_task_by_id_or_raise(
task_id: int, principal_id: PrincipalModel active_task_id: int, principal_id: PrincipalModel
) -> ActiveTaskModel: ) -> ActiveTaskModel:
"""Find_active_task_by_id_or_raise.""" """Find_active_task_by_id_or_raise."""
active_task_assigned_to_me = ActiveTaskModel.query.filter_by( active_task_assigned_to_me = ActiveTaskModel.query.filter_by(
id=task_id, assigned_principal_id=principal_id id=active_task_id, assigned_principal_id=principal_id
).first() ).first()
if active_task_assigned_to_me is None: if active_task_assigned_to_me is None:
raise ( raise (
ApiError( ApiError(
code="task_not_found", code="task_not_found",
message=f"Task not found for principal user: {principal_id} and id: {task_id}", message=f"Task not found for principal user: {principal_id} and id: {active_task_id}",
status_code=400, status_code=400,
) )
) )
@ -734,3 +822,28 @@ def find_process_instance_by_id_or_raise(
) )
) )
return process_instance # type: ignore return process_instance # type: ignore
def get_value_from_array_with_index(array: list, index: int) -> Any:
"""Get_value_from_array_with_index."""
if index < 0:
return None
if index >= len(array):
return None
return array[index]
def prepare_form_data(
form_file: str, spiffworkflow_data_json: dict, process_model: ProcessModelInfo
) -> str:
"""Prepare_form_data."""
file_contents = SpecFileService.get_data(process_model, form_file).decode("utf-8")
# trade out pieces like "{{variable_name}}" for the corresponding form data value
for key, value in spiffworkflow_data_json.items():
if isinstance(value, str) or isinstance(value, int):
file_contents = file_contents.replace("{{" + key + "}}", str(value))
return file_contents

1
test.json Normal file

File diff suppressed because one or more lines are too long

596
test2.json Normal file
View File

@ -0,0 +1,596 @@
{
"data": {
"validate_only": false,
"process_instance_id": 614
},
"last_task": "2d449bc3-5825-49d5-8954-0e4aa965a41a",
"success": true,
"tasks": {
"5cf148e9-8a18-4e30-b70a-0f379e3914f0": {
"id": "5cf148e9-8a18-4e30-b70a-0f379e3914f0",
"parent": null,
"children": [
"d77d94a6-9174-433b-95a9-09536f315cff"
],
"last_state_change": 1658326560.4419284,
"state": 32,
"task_spec": "Root",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {}
},
"d77d94a6-9174-433b-95a9-09536f315cff": {
"id": "d77d94a6-9174-433b-95a9-09536f315cff",
"parent": "5cf148e9-8a18-4e30-b70a-0f379e3914f0",
"children": [
"82a5f501-dad6-4b1f-b6db-fdc1900ce8a5"
],
"last_state_change": 1658326560.4565284,
"state": 32,
"task_spec": "Start",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {
"current_user": {
"id": "1",
"username": "test_user1"
}
}
},
"82a5f501-dad6-4b1f-b6db-fdc1900ce8a5": {
"id": "82a5f501-dad6-4b1f-b6db-fdc1900ce8a5",
"parent": "d77d94a6-9174-433b-95a9-09536f315cff",
"children": [
"36f9305b-a50b-477a-bdf7-80ec8ae9fcd6"
],
"last_state_change": 1658326560.4569082,
"state": 32,
"task_spec": "StartEvent_1",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {
"event_fired": true
},
"data": {
"current_user": {
"id": "1",
"username": "test_user1"
}
}
},
"36f9305b-a50b-477a-bdf7-80ec8ae9fcd6": {
"id": "36f9305b-a50b-477a-bdf7-80ec8ae9fcd6",
"parent": "82a5f501-dad6-4b1f-b6db-fdc1900ce8a5",
"children": [
"b548f004-b536-41b2-b757-cc3d2b77bb1f"
],
"last_state_change": 1658326560.457242,
"state": 32,
"task_spec": "set_system_generated_number",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {
"current_user": {
"id": "1",
"username": "test_user1"
},
"system_generated_number": 4
}
},
"b548f004-b536-41b2-b757-cc3d2b77bb1f": {
"id": "b548f004-b536-41b2-b757-cc3d2b77bb1f",
"parent": "36f9305b-a50b-477a-bdf7-80ec8ae9fcd6",
"children": [
"2d449bc3-5825-49d5-8954-0e4aa965a41a"
],
"last_state_change": 1658326894.542517,
"state": 32,
"task_spec": "get_user_generated_number",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {
"current_user": {
"id": "1",
"username": "test_user1"
},
"system_generated_number": 4,
"user_generated_number": 2
}
},
"2d449bc3-5825-49d5-8954-0e4aa965a41a": {
"id": "2d449bc3-5825-49d5-8954-0e4aa965a41a",
"parent": "b548f004-b536-41b2-b757-cc3d2b77bb1f",
"children": [
"e8890437-f835-4a70-97ae-017c203444e7"
],
"last_state_change": 1658326894.5578055,
"state": 32,
"task_spec": "multiply",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {
"current_user": {
"id": "1",
"username": "test_user1"
},
"system_generated_number": 4,
"user_generated_number": 2,
"product": 8
}
},
"e8890437-f835-4a70-97ae-017c203444e7": {
"id": "e8890437-f835-4a70-97ae-017c203444e7",
"parent": "2d449bc3-5825-49d5-8954-0e4aa965a41a",
"children": [
"cf0ddaf1-aee6-4393-aa48-5425a76f85f0"
],
"last_state_change": 1658326894.5580246,
"state": 16,
"task_spec": "Activity_05z7ccx",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {
"current_user": {
"id": "1",
"username": "test_user1"
},
"system_generated_number": 4,
"user_generated_number": 2,
"product": 8
}
},
"cf0ddaf1-aee6-4393-aa48-5425a76f85f0": {
"id": "cf0ddaf1-aee6-4393-aa48-5425a76f85f0",
"parent": "e8890437-f835-4a70-97ae-017c203444e7",
"children": [
"310e155e-238b-4627-a228-10f302e39ae4"
],
"last_state_change": 1658326560.4422436,
"state": 4,
"task_spec": "Activity_00mekhp",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {}
},
"310e155e-238b-4627-a228-10f302e39ae4": {
"id": "310e155e-238b-4627-a228-10f302e39ae4",
"parent": "cf0ddaf1-aee6-4393-aa48-5425a76f85f0",
"children": [
"250180b0-f8ac-4bf3-b1ed-d369ed0beba6"
],
"last_state_change": 1658326560.4422898,
"state": 4,
"task_spec": "EndEvent_0q4qzl9",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {}
},
"250180b0-f8ac-4bf3-b1ed-d369ed0beba6": {
"id": "250180b0-f8ac-4bf3-b1ed-d369ed0beba6",
"parent": "310e155e-238b-4627-a228-10f302e39ae4",
"children": [
"bff8b7dc-f1f8-4345-a50d-fe07560083e4"
],
"last_state_change": 1658326560.4423366,
"state": 4,
"task_spec": "test_form.EndJoin",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {}
},
"bff8b7dc-f1f8-4345-a50d-fe07560083e4": {
"id": "bff8b7dc-f1f8-4345-a50d-fe07560083e4",
"parent": "250180b0-f8ac-4bf3-b1ed-d369ed0beba6",
"children": [],
"last_state_change": 1658326560.4423747,
"state": 4,
"task_spec": "End",
"triggered": false,
"workflow_name": "test_form",
"internal_data": {},
"data": {}
}
},
"root": "5cf148e9-8a18-4e30-b70a-0f379e3914f0",
"spec": {
"name": "test_form",
"description": "Test Form",
"file": "test_form.bpmn",
"task_specs": {
"Start": {
"id": "test_form_1",
"name": "Start",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [],
"outputs": [
"StartEvent_1"
],
"typename": "StartTask"
},
"test_form.EndJoin": {
"id": "test_form_2",
"name": "test_form.EndJoin",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"EndEvent_0q4qzl9"
],
"outputs": [
"End"
],
"typename": "_EndJoin"
},
"End": {
"id": "test_form_3",
"name": "End",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"test_form.EndJoin"
],
"outputs": [],
"typename": "Simple"
},
"StartEvent_1": {
"id": "test_form_4",
"name": "StartEvent_1",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Start"
],
"outputs": [
"set_system_generated_number"
],
"lane": null,
"documentation": null,
"loopTask": false,
"position": {
"x": 112,
"y": 99
},
"outgoing_sequence_flows": {
"set_system_generated_number": {
"id": "SequenceFlow_0lvudp8",
"name": null,
"documentation": null,
"target_task_spec": "set_system_generated_number",
"typename": "SequenceFlow"
}
},
"outgoing_sequence_flows_by_id": {
"SequenceFlow_0lvudp8": {
"id": "SequenceFlow_0lvudp8",
"name": null,
"documentation": null,
"target_task_spec": "set_system_generated_number",
"typename": "SequenceFlow"
}
},
"data_input_associations": [],
"data_output_associations": [],
"event_definition": {
"internal": false,
"external": false,
"typename": "NoneEventDefinition"
},
"typename": "StartEvent",
"extensions": {}
},
"set_system_generated_number": {
"id": "test_form_5",
"name": "set_system_generated_number",
"description": "set_system_generated_number",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"StartEvent_1"
],
"outputs": [
"get_user_generated_number"
],
"lane": null,
"documentation": null,
"loopTask": false,
"position": {
"x": 190,
"y": 77
},
"outgoing_sequence_flows": {
"get_user_generated_number": {
"id": "Flow_0kk2hzj",
"name": null,
"documentation": null,
"target_task_spec": "get_user_generated_number",
"typename": "SequenceFlow"
}
},
"outgoing_sequence_flows_by_id": {
"Flow_0kk2hzj": {
"id": "Flow_0kk2hzj",
"name": null,
"documentation": null,
"target_task_spec": "get_user_generated_number",
"typename": "SequenceFlow"
}
},
"data_input_associations": [],
"data_output_associations": [],
"script": "system_generated_number = 4",
"typename": "ScriptTask",
"extensions": {}
},
"get_user_generated_number": {
"id": "test_form_6",
"name": "get_user_generated_number",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"set_system_generated_number"
],
"outputs": [
"multiply"
],
"lane": null,
"documentation": null,
"loopTask": false,
"position": {
"x": 320,
"y": 77
},
"outgoing_sequence_flows": {
"multiply": {
"id": "Flow_1cck1pb",
"name": null,
"documentation": null,
"target_task_spec": "multiply",
"typename": "SequenceFlow"
}
},
"outgoing_sequence_flows_by_id": {
"Flow_1cck1pb": {
"id": "Flow_1cck1pb",
"name": null,
"documentation": null,
"target_task_spec": "multiply",
"typename": "SequenceFlow"
}
},
"data_input_associations": [],
"data_output_associations": [],
"prescript": null,
"postscript": null,
"typename": "UserTask",
"extensions": {
"properties": {
"formJsonSchemaFilename": "give_me_a_number_form.json"
}
}
},
"multiply": {
"id": "test_form_7",
"name": "multiply",
"description": "multiply",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"get_user_generated_number"
],
"outputs": [
"Activity_05z7ccx"
],
"lane": null,
"documentation": null,
"loopTask": false,
"position": {
"x": 450,
"y": 77
},
"outgoing_sequence_flows": {
"Activity_05z7ccx": {
"id": "Flow_16gxvwr",
"name": null,
"documentation": null,
"target_task_spec": "Activity_05z7ccx",
"typename": "SequenceFlow"
}
},
"outgoing_sequence_flows_by_id": {
"Flow_16gxvwr": {
"id": "Flow_16gxvwr",
"name": null,
"documentation": null,
"target_task_spec": "Activity_05z7ccx",
"typename": "SequenceFlow"
}
},
"data_input_associations": [],
"data_output_associations": [],
"script": "product = system_generated_number * user_generated_number",
"typename": "ScriptTask",
"extensions": {}
},
"Activity_05z7ccx": {
"id": "test_form_8",
"name": "Activity_05z7ccx",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"multiply"
],
"outputs": [
"Activity_00mekhp"
],
"lane": null,
"documentation": null,
"loopTask": false,
"position": {
"x": 580,
"y": 77
},
"outgoing_sequence_flows": {
"Activity_00mekhp": {
"id": "Flow_0k1q81g",
"name": null,
"documentation": null,
"target_task_spec": "Activity_00mekhp",
"typename": "SequenceFlow"
}
},
"outgoing_sequence_flows_by_id": {
"Flow_0k1q81g": {
"id": "Flow_0k1q81g",
"name": null,
"documentation": null,
"target_task_spec": "Activity_00mekhp",
"typename": "SequenceFlow"
}
},
"data_input_associations": [],
"data_output_associations": [],
"prescript": null,
"postscript": null,
"typename": "UserTask",
"extensions": {
"properties": {
"formJsonSchemaFilename": "give_me_another_number_form.json"
}
}
},
"Activity_00mekhp": {
"id": "test_form_9",
"name": "Activity_00mekhp",
"description": "multiply",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Activity_05z7ccx"
],
"outputs": [
"EndEvent_0q4qzl9"
],
"lane": null,
"documentation": null,
"loopTask": false,
"position": {
"x": 730,
"y": 77
},
"outgoing_sequence_flows": {
"EndEvent_0q4qzl9": {
"id": "Flow_1hp8s94",
"name": null,
"documentation": null,
"target_task_spec": "EndEvent_0q4qzl9",
"typename": "SequenceFlow"
}
},
"outgoing_sequence_flows_by_id": {
"Flow_1hp8s94": {
"id": "Flow_1hp8s94",
"name": null,
"documentation": null,
"target_task_spec": "EndEvent_0q4qzl9",
"typename": "SequenceFlow"
}
},
"data_input_associations": [],
"data_output_associations": [],
"script": "final_product = product * second_user_generated_number",
"typename": "ScriptTask",
"extensions": {}
},
"EndEvent_0q4qzl9": {
"id": "test_form_10",
"name": "EndEvent_0q4qzl9",
"description": null,
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [
"Activity_00mekhp"
],
"outputs": [
"test_form.EndJoin"
],
"lane": null,
"documentation": null,
"loopTask": false,
"position": {
"x": 862,
"y": 99
},
"outgoing_sequence_flows": {
"test_form.EndJoin": {
"id": "EndEvent_0q4qzl9.ToEndJoin",
"name": null,
"documentation": null,
"target_task_spec": "test_form.EndJoin",
"typename": "SequenceFlow"
}
},
"outgoing_sequence_flows_by_id": {
"EndEvent_0q4qzl9.ToEndJoin": {
"id": "EndEvent_0q4qzl9.ToEndJoin",
"name": null,
"documentation": null,
"target_task_spec": "test_form.EndJoin",
"typename": "SequenceFlow"
}
},
"data_input_associations": [],
"data_output_associations": [],
"event_definition": {
"internal": false,
"external": false,
"typename": "NoneEventDefinition"
},
"typename": "EndEvent",
"extensions": {}
},
"Root": {
"id": "test_form_11",
"name": "Root",
"description": "",
"manual": false,
"internal": false,
"lookahead": 2,
"inputs": [],
"outputs": [],
"typename": "Simple"
}
},
"data_inputs": [],
"data_outputs": [],
"data_objects": [],
"typename": "BpmnProcessSpec"
},
"subprocess_specs": {},
"subprocesses": {},
"serializer_version": "1.0-CRC"
}