mirror of
https://github.com/status-im/spiff-arena.git
synced 2025-02-11 01:06:36 +00:00
cd4da465 Merge pull request #264 from sartography/bugfix/dmn-equality-with-boolean 414a59eb disambiguate DMN expressions eea53c91 Merge pull request #263 from sartography/feature/cleanup-task-completion d248d5b1 execute postscript before other complete hook tasks c09f1a90 streamline predict & remove some duplicated calls to it 64c21791 remove duplicate calls to update 4ca1076d move task update to _on_complete to ensure data is copied consistently after task related activities are done d037a7eb small changes for readability 025bc30f Quick patch -- is_executable needs to be accurate immediately. 14d3d8c3 Merge pull request #262 from sartography/feature/parser_info_features 849c223e We are jumping through a lot of complex xml parsing in SpiffWorkflow-Backend because we need to know some basic information about a BPMN process at the moment it is saved. Rather than do that work in the backend, it seems better to have SpiffWorkflow handle parsing the xml and providing a bit of metadata, including: git-subtree-dir: SpiffWorkflow git-subtree-split: cd4da465e125ca1ae1b57d227bfa324d9d4c507c
129 lines
4.4 KiB
Python
129 lines
4.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
from copy import deepcopy
|
|
|
|
from SpiffWorkflow.task import TaskState
|
|
from .BpmnSpecMixin import BpmnSpecMixin
|
|
from ...specs.base import TaskSpec
|
|
|
|
|
|
class SubWorkflowTask(BpmnSpecMixin):
|
|
"""
|
|
Task Spec for a bpmn node containing a subworkflow.
|
|
"""
|
|
def __init__(self, wf_spec, name, subworkflow_spec, transaction=False, **kwargs):
|
|
"""
|
|
Constructor.
|
|
|
|
:param bpmn_wf_spec: the BpmnProcessSpec for the sub process.
|
|
:param bpmn_wf_class: the BpmnWorkflow class to instantiate
|
|
"""
|
|
super(SubWorkflowTask, self).__init__(wf_spec, name, **kwargs)
|
|
self.spec = subworkflow_spec
|
|
self.transaction = transaction
|
|
|
|
@property
|
|
def spec_type(self):
|
|
return 'Subprocess'
|
|
|
|
def test(self):
|
|
TaskSpec.test(self)
|
|
|
|
def _on_ready_before_hook(self, my_task):
|
|
subworkflow = my_task.workflow.create_subprocess(my_task, self.spec, self.name)
|
|
subworkflow.completed_event.connect(self._on_subworkflow_completed, my_task)
|
|
subworkflow.data = deepcopy(my_task.workflow.data)
|
|
|
|
def _on_ready_hook(self, my_task):
|
|
|
|
super()._on_ready_hook(my_task)
|
|
self.start_workflow(my_task)
|
|
|
|
def _on_subworkflow_completed(self, subworkflow, my_task):
|
|
|
|
# Shouldn't this always be true?
|
|
if isinstance(my_task.parent.task_spec, BpmnSpecMixin):
|
|
my_task.parent.task_spec._child_complete_hook(my_task)
|
|
|
|
if len(subworkflow.spec.data_outputs) == 0:
|
|
# Copy all workflow data if no outputs are specified
|
|
my_task.data = deepcopy(subworkflow.last_task.data)
|
|
else:
|
|
end = subworkflow.get_tasks_from_spec_name('End', workflow=subworkflow)
|
|
# Otherwise only copy data with the specified names
|
|
for var in subworkflow.spec.data_outputs:
|
|
var.copy(end[0], my_task, data_output=True)
|
|
|
|
my_task._set_state(TaskState.READY)
|
|
|
|
def _update_hook(self, my_task):
|
|
wf = my_task.workflow._get_outermost_workflow(my_task)
|
|
if my_task.id not in wf.subprocesses:
|
|
super()._update_hook(my_task)
|
|
|
|
def _predict_hook(self, my_task):
|
|
# The base Subworkflow task predict doesn't work with the loop reset task
|
|
BpmnSpecMixin._predict_hook(self, my_task)
|
|
|
|
def _on_complete_hook(self, my_task):
|
|
BpmnSpecMixin._on_complete_hook(self, my_task)
|
|
|
|
def _on_cancel(self, my_task):
|
|
subworkflow = my_task.workflow.get_subprocess(my_task)
|
|
if subworkflow is not None:
|
|
subworkflow.cancel()
|
|
|
|
def start_workflow(self, my_task):
|
|
|
|
subworkflow = my_task.workflow.get_subprocess(my_task)
|
|
start = subworkflow.get_tasks_from_spec_name('Start', workflow=subworkflow)
|
|
|
|
if len(subworkflow.spec.data_inputs) == 0:
|
|
# Copy all task data into start task if no inputs specified
|
|
start[0].set_data(**my_task.data)
|
|
else:
|
|
# Otherwise copy only task data with the specified names
|
|
for var in subworkflow.spec.data_inputs:
|
|
var.copy(my_task, start[0], data_input=True)
|
|
|
|
for child in subworkflow.task_tree.children:
|
|
child.task_spec._update(child)
|
|
|
|
my_task._set_state(TaskState.WAITING)
|
|
|
|
def serialize(self, serializer):
|
|
return serializer.serialize_subworkflow_task(self)
|
|
|
|
@classmethod
|
|
def deserialize(self, serializer, wf_spec, s_state):
|
|
return serializer.deserialize_subworkflow_task(wf_spec, s_state, SubWorkflowTask)
|
|
|
|
def task_will_set_children_future(self, my_task):
|
|
my_task.workflow.delete_subprocess(my_task)
|
|
|
|
|
|
class CallActivity(SubWorkflowTask):
|
|
|
|
def __init__(self, wf_spec, name, subworkflow_spec, **kwargs):
|
|
super(CallActivity, self).__init__(wf_spec, name, subworkflow_spec, False, **kwargs)
|
|
|
|
@property
|
|
def spec_type(self):
|
|
return 'Call Activity'
|
|
|
|
@classmethod
|
|
def deserialize(cls, serializer, wf_spec, s_state):
|
|
return serializer.deserialize_subworkflow_task(wf_spec, s_state, CallActivity)
|
|
|
|
class TransactionSubprocess(SubWorkflowTask):
|
|
|
|
def __init__(self, wf_spec, name, subworkflow_spec, **kwargs):
|
|
super(TransactionSubprocess, self).__init__(wf_spec, name, subworkflow_spec, True, **kwargs)
|
|
|
|
@property
|
|
def spec_type(self):
|
|
return 'Transactional Subprocess'
|
|
|
|
@classmethod
|
|
def deserialize(cls, serializer, wf_spec, s_state):
|
|
return serializer.deserialize_subworkflow_task(wf_spec, s_state, TransactionSubprocess)
|