Commit bf54b83b authored by Jean-Paul Smets's avatar Jean-Paul Smets

New WorkflowMethod implementation. This new implementation solves most issues...

New WorkflowMethod implementation. This new implementation solves most issues which existed previously and related to multiple workflows for a single workflow method ID. It should also be faster but will require some more work so that changes in workflow definition are reflected automatically in workflow methods registration. Added support in interaction workflows for once per transaction execution and regular expressions in trigger method IDs.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@15825 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 843d058b
...@@ -32,7 +32,7 @@ from Products.ERP5Type.Permissions import ManagePortal ...@@ -32,7 +32,7 @@ from Products.ERP5Type.Permissions import ManagePortal
from Products.DCWorkflow.ContainerTab import ContainerTab from Products.DCWorkflow.ContainerTab import ContainerTab
from Products.DCWorkflow.Guard import Guard from Products.DCWorkflow.Guard import Guard
from Products.DCWorkflow.Expression import Expression from Products.DCWorkflow.Expression import Expression
from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC, TRIGGER_WORKFLOW_METHOD from Products.DCWorkflow.Transitions import TRIGGER_WORKFLOW_METHOD
from Products.ERP5 import _dtmldir from Products.ERP5 import _dtmldir
from Products.ERP5Type.Base import _aq_reset from Products.ERP5Type.Base import _aq_reset
...@@ -57,6 +57,7 @@ class InteractionDefinition (SimpleItem): ...@@ -57,6 +57,7 @@ class InteractionDefinition (SimpleItem):
activate_script_name = () # Executed as activity activate_script_name = () # Executed as activity
method_id = () method_id = ()
portal_type_filter = None portal_type_filter = None
once_per_transaction = False
manage_options = ( manage_options = (
{'label': 'Properties', 'action': 'manage_properties'}, {'label': 'Properties', 'action': 'manage_properties'},
...@@ -116,6 +117,7 @@ class InteractionDefinition (SimpleItem): ...@@ -116,6 +117,7 @@ class InteractionDefinition (SimpleItem):
def setProperties(self, title, def setProperties(self, title,
portal_type_filter=None, portal_type_filter=None,
trigger_type=TRIGGER_WORKFLOW_METHOD, trigger_type=TRIGGER_WORKFLOW_METHOD,
once_per_transaction=False,
script_name=(), script_name=(),
after_script_name=(), after_script_name=(),
activate_script_name=(), activate_script_name=(),
...@@ -144,6 +146,7 @@ class InteractionDefinition (SimpleItem): ...@@ -144,6 +146,7 @@ class InteractionDefinition (SimpleItem):
self.title = str(title) self.title = str(title)
self.description = str(description) self.description = str(description)
self.trigger_type = int(trigger_type) self.trigger_type = int(trigger_type)
self.once_per_transaction = bool(once_per_transaction)
self.script_name = script_name self.script_name = script_name
self.after_script_name = after_script_name self.after_script_name = after_script_name
self.activate_script_name = activate_script_name self.activate_script_name = activate_script_name
......
...@@ -21,7 +21,7 @@ import App ...@@ -21,7 +21,7 @@ import App
from AccessControl import getSecurityManager, ClassSecurityInfo from AccessControl import getSecurityManager, ClassSecurityInfo
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC, TRIGGER_WORKFLOW_METHOD from Products.DCWorkflow.Transitions import TRIGGER_WORKFLOW_METHOD
from Products.DCWorkflow.Expression import StateChangeInfo, createExprContext from Products.DCWorkflow.Expression import StateChangeInfo, createExprContext
from Products.CMFCore.WorkflowTool import addWorkflowFactory from Products.CMFCore.WorkflowTool import addWorkflowFactory
from Products.CMFActivity.ActiveObject import ActiveObject from Products.CMFActivity.ActiveObject import ActiveObject
...@@ -174,8 +174,10 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject): ...@@ -174,8 +174,10 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
''' '''
Returns a true value if the given workflow is Returns a true value if the given workflow is
automatic with the propper method_id automatic with the propper method_id
NOTE: this method is not used in ERP5 because
of transition_list approach
''' '''
#return 0 # Why this line ??? # I guess it should be used
for t in self.interactions.values(): for t in self.interactions.values():
if t.trigger_type == TRIGGER_WORKFLOW_METHOD: if t.trigger_type == TRIGGER_WORKFLOW_METHOD:
if method_id in t.method_id: if method_id in t.method_id:
...@@ -193,28 +195,36 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject): ...@@ -193,28 +195,36 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
''' '''
return return
security.declarePrivate('notifyWorkflowMethod')
def notifyWorkflowMethod(self, ob, action, args=None, kw=None, transition_list=None):
"""
InteractionWorkflow is stateless. Thus, this function should do nothing.
"""
return
security.declarePrivate('notifyBefore') security.declarePrivate('notifyBefore')
def notifyBefore(self, ob, action, args=None, kw=None): def notifyBefore(self, ob, action, args=None, kw=None, transition_list=None):
''' '''
Notifies this workflow of an action before it happens, Notifies this workflow of an action before it happens,
allowing veto by exception. Unless an exception is thrown, either allowing veto by exception. Unless an exception is thrown, either
a notifySuccess() or notifyException() can be expected later on. a notifySuccess() or notifyException() can be expected later on.
The action usually corresponds to a method name. The action usually corresponds to a method name.
''' '''
for t in self.interactions.values(): if not transition_list: return
tdef = None # Wrap args into kw since this is the only way
if t.trigger_type == TRIGGER_AUTOMATIC: # to be compatible with DCWorkflow
if t.portal_type_filter is None: # A better approach consists in extending DCWorkflow
tdef = t kw = kw.copy()
elif ob.getPortalType() in t.portal_type_filter: kw['workflow_method_args'] = args
tdef = t filtered_transition_list = []
elif t.trigger_type == TRIGGER_WORKFLOW_METHOD:
if action in t.method_id: for t_id in transition_list:
if t.portal_type_filter is None: tdef = self.interactions[t_id]
tdef = t if tdef.trigger_type == TRIGGER_WORKFLOW_METHOD:
elif ob.getPortalType() in t.portal_type_filter: if (tdef.portal_type_filter is None or \
tdef = t ob.getPortalType() in tdef.portal_type_filter) and \
if tdef is not None: self._checkTransitionGuard(tdef, ob, **kw):
filtered_transition_list.append(tdef.id)
former_status = self._getStatusOf(ob) former_status = self._getStatusOf(ob)
# Execute the "before" script. # Execute the "before" script.
for script_name in tdef.script_name: for script_name in tdef.script_name:
...@@ -222,32 +232,32 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject): ...@@ -222,32 +232,32 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
# Pass lots of info to the script in a single parameter. # Pass lots of info to the script in a single parameter.
sci = StateChangeInfo( sci = StateChangeInfo(
ob, self, former_status, tdef, None, None, kwargs=kw) ob, self, former_status, tdef, None, None, kwargs=kw)
script(sci) # May throw an exception. script(sci) # May throw an exception
return filtered_transition_list
security.declarePrivate('notifySuccess') security.declarePrivate('notifySuccess')
def notifySuccess(self, ob, action, result, args=None, kw=None): def notifySuccess(self, ob, action, result, args=None, kw=None, transition_list=None):
''' '''
Notifies this workflow that an action has taken place. Notifies this workflow that an action has taken place.
''' '''
# initialize variables if not transition_list: return
kw = kw.copy()
kw['workflow_method_args'] = args
kw['workflow_method_result'] = result
for t_id in transition_list:
tdef = self.interactions[t_id]
if tdef.trigger_type == TRIGGER_WORKFLOW_METHOD:
if (tdef.portal_type_filter is None or \
ob.getPortalType() in tdef.portal_type_filter):
# Initialize variables
former_status = self._getStatusOf(ob)
econtext = None econtext = None
sci = None sci = None
for t in self.interactions.values():
tdef = None
if t.trigger_type == TRIGGER_AUTOMATIC:
if t.portal_type_filter is None:
tdef = t
elif ob.getPortalType() in t.portal_type_filter:
tdef = t
elif t.trigger_type == TRIGGER_WORKFLOW_METHOD:
if action in t.method_id:
if t.portal_type_filter is None:
tdef = t
elif ob.getPortalType() in t.portal_type_filter:
tdef = t
if tdef is not None:
# Update variables. # Update variables.
former_status = self._getStatusOf(ob)
tdef_exprs = tdef.var_exprs tdef_exprs = tdef.var_exprs
if tdef_exprs is None: tdef_exprs = {} if tdef_exprs is None: tdef_exprs = {}
status = {} status = {}
...@@ -277,20 +287,19 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject): ...@@ -277,20 +287,19 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
value = expr(econtext) value = expr(econtext)
status[id] = value status[id] = value
# Execute "after" scripts # Execute the "after" script.
for script_name in tdef.after_script_name: for script_name in tdef.after_script_name:
script = self.scripts[script_name] script = self.scripts[script_name]
# Pass lots of info to the script in a single parameter. # Pass lots of info to the script in a single parameter.
sci = StateChangeInfo( sci = StateChangeInfo(
ob, self, status, tdef, None, None, kwargs=kw) ob, self, former_status, tdef, None, None, kwargs=kw)
script(sci) # May throw an exception. script(sci) # May throw an exception
# Execute "activity" scripts # Execute "activity" scripts
for script_name in tdef.activate_script_name: for script_name in tdef.activate_script_name:
self.activate(activity='SQLQueue')\ self.activate(activity='SQLQueue')\
.activeScript(script_name, ob.getRelativeUrl(), status, tdef.id) .activeScript(script_name, ob.getRelativeUrl(), status, tdef.id)
security.declarePrivate('activeScript') security.declarePrivate('activeScript')
def activeScript(self, script_name, ob_url, status, tdef_id): def activeScript(self, script_name, ob_url, status, tdef_id):
script = self.scripts[script_name] script = self.scripts[script_name]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment