diff --git a/SpiffWorkflow/bpmn/specs/event_definitions/item_aware_event.py b/SpiffWorkflow/bpmn/specs/event_definitions/item_aware_event.py index 9043c952..1c997b34 100644 --- a/SpiffWorkflow/bpmn/specs/event_definitions/item_aware_event.py +++ b/SpiffWorkflow/bpmn/specs/event_definitions/item_aware_event.py @@ -26,16 +26,18 @@ def reset(self, my_task): my_task.internal_data.pop(self.name, None) super().reset(my_task) -class ErrorEventDefinition(ItemAwareEventDefinition): - """ - Error events can occur only in subprocesses and as subprocess boundary events. They're - matched by code rather than name. - """ + +class CodeEventDefinition(ItemAwareEventDefinition): def __init__(self, name, code=None, **kwargs): - super(ErrorEventDefinition, self).__init__(name, **kwargs) + super().__init__(name, **kwargs) self.code = code + def throw(self, my_task): + payload = deepcopy(my_task.data) + event = BpmnEvent(self, payload=payload, target=my_task.workflow) + my_task.workflow.top_workflow.catch(event) + def details(self, my_task): return PendingBpmnEvent(self.name, self.__class__.__name__, self.code) @@ -43,27 +45,19 @@ def __eq__(self, other): return super().__eq__(other) and self.code in [None, other.code] -class EscalationEventDefinition(ItemAwareEventDefinition): +class ErrorEventDefinition(CodeEventDefinition): + """ + Error events can occur only in subprocesses and as subprocess boundary events. They're + matched by code rather than name. + """ + pass + +class EscalationEventDefinition(CodeEventDefinition): """ Escalation events have names, though they don't seem to be used for anything. Instead the spec says that the escalation code should be matched. """ - - def __init__(self, name, code=None, **kwargs): - """ - Constructor. - - :param escalation_code: The escalation code this event should - react to. If None then all escalations will activate this event. - """ - super(EscalationEventDefinition, self).__init__(name, **kwargs) - self.code = code - - def details(self, my_task): - return PendingBpmnEvent(self.name, self.__class__.__name__, self.code) - - def __eq__(self, other): - return super().__eq__(other) and self.code in [None, other.code] + pass class SignalEventDefinition(ItemAwareEventDefinition): diff --git a/SpiffWorkflow/bpmn/workflow.py b/SpiffWorkflow/bpmn/workflow.py index b2cc95cc..d98d6a65 100644 --- a/SpiffWorkflow/bpmn/workflow.py +++ b/SpiffWorkflow/bpmn/workflow.py @@ -24,6 +24,7 @@ from SpiffWorkflow.bpmn.specs.mixins.events.event_types import CatchingEvent from SpiffWorkflow.bpmn.specs.mixins.events.start_event import StartEvent from SpiffWorkflow.bpmn.specs.mixins.subworkflow_task import CallActivity +from SpiffWorkflow.bpmn.specs.event_definitions.item_aware_event import CodeEventDefinition from SpiffWorkflow.bpmn.specs.control import BoundaryEventSplit @@ -113,6 +114,9 @@ def catch(self, event): if event.target is not None: # This limits results to tasks in the specified workflow tasks = event.target.get_tasks(skip_subprocesses=True, state=TaskState.NOT_FINISHED_MASK, catches_event=event) + if isinstance(event.event_definition, CodeEventDefinition) and len(tasks) == 0: + event.target = event.target.parent_workflow + self.catch(event) else: self.update_collaboration(event) tasks = self.get_tasks(state=TaskState.NOT_FINISHED_MASK, catches_event=event) diff --git a/tests/SpiffWorkflow/bpmn/data/uncaught_escalation.bpmn b/tests/SpiffWorkflow/bpmn/data/uncaught_escalation.bpmn new file mode 100644 index 00000000..9f5b2bc3 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/data/uncaught_escalation.bpmn @@ -0,0 +1,58 @@ + + + + + Flow_0vt1twq + + + Flow_1udyjxo + + + + + Flow_0vt1twq + Flow_1udyjxo + + Flow_0w1tuap + + + + Flow_0w1tuap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SpiffWorkflow/bpmn/events/UncaughtEscalationTest.py b/tests/SpiffWorkflow/bpmn/events/UncaughtEscalationTest.py new file mode 100644 index 00000000..cec31a89 --- /dev/null +++ b/tests/SpiffWorkflow/bpmn/events/UncaughtEscalationTest.py @@ -0,0 +1,17 @@ +import unittest + +from SpiffWorkflow import TaskState +from SpiffWorkflow.bpmn import BpmnWorkflow + +from ..BpmnWorkflowTestCase import BpmnWorkflowTestCase + +class UncaughtEscalationTest(BpmnWorkflowTestCase): + + def test_uncaught_escalation(self): + spec, subprocess_specs = self.load_workflow_spec('uncaught_escalation.bpmn', 'top_level') + workflow = BpmnWorkflow(spec, subprocess_specs) + workflow.do_engine_steps() + self.assertTrue(workflow.completed) + event = workflow.get_events()[0] + self.assertEqual(event.event_definition.code, 'escalation-1') +