diff --git a/product/ERP5/Interaction.py b/product/ERP5/Interaction.py
index 81433a3c3f74ff69729d2cfabc0e60c473c488b7..0115f33f5e81e74b1c976536ff5af7c91f65ee06 100755
--- a/product/ERP5/Interaction.py
+++ b/product/ERP5/Interaction.py
@@ -34,14 +34,10 @@ from Products.CMFCore.CMFCorePermissions import ManagePortal
 from Products.DCWorkflow.ContainerTab import ContainerTab
 from Products.DCWorkflow.Guard import Guard
 from Products.DCWorkflow.Expression import Expression
+from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC, TRIGGER_WORKFLOW_METHOD
 
 from Products.ERP5 import _dtmldir
 
-TRIGGER_AUTOMATIC = 0
-TRIGGER_USER_ACTION = 1 # useless for interaction
-TRIGGER_WORKFLOW_METHOD = 2
-
-
 class InteractionDefinition (SimpleItem):
     meta_type = 'Workflow Interaction'
 
@@ -51,14 +47,16 @@ class InteractionDefinition (SimpleItem):
     title = ''
     description = ''
     new_state_id = ''
-    trigger_type = TRIGGER_USER_ACTION
+    trigger_type = TRIGGER_WORKFLOW_METHOD
     guard = None
     actbox_name = ''
     actbox_url = ''
     actbox_category = 'workflow'
     var_exprs = None  # A mapping.
-    script_name = None  # Executed before transition
-    after_script_name = None  # Executed after transition
+    script_name = ()  # Executed before transition
+    after_script_name = ()  # Executed after transition
+    activate_script_name = ()  # Executed as activity
+    method_id = None
 
     manage_options = (
         {'label': 'Properties', 'action': 'manage_properties'},
@@ -115,20 +113,29 @@ class InteractionDefinition (SimpleItem):
                                      manage_tabs_message=manage_tabs_message,
                                      )
 
-    def setProperties(self, title, new_state_id,
-                      trigger_type=TRIGGER_USER_ACTION, script_name='',
-                      after_script_name='',
+    def setProperties(self, title,
+                      portal_type_filter=None,
+                      trigger_type=TRIGGER_AUTOMATIC,
+                      script_name=(),
+                      after_script_name=(),
+                      activate_script_name=(),
                       actbox_name='', actbox_url='',
                       actbox_category='workflow',
+                      method_id=None,
                       props=None, REQUEST=None, description=''):
         '''
+          Update transition properties
+          XXX - then make sure that method_id is WorkflowMethod for portal_type_filter
+          XXX - this will likely require dynamic
         '''
+        self.method_id = method_id
+        self.portal_type_filter = portal_type_filter
         self.title = str(title)
         self.description = str(description)
-        self.new_state_id = str(new_state_id)
         self.trigger_type = int(trigger_type)
-        self.script_name = str(script_name)
-        self.after_script_name = str(after_script_name)
+        self.script_name = map(lambda x: str(x), script_name)
+        self.after_script_name = map(lambda x: str(x), after_script_name)
+        self.activate_script_name = map(lambda x: str(x), activate_script_name)
         g = Guard()
         if g.changeFromProperties(props or REQUEST):
             self.guard = g
diff --git a/product/ERP5/InteractionWorkflow.py b/product/ERP5/InteractionWorkflow.py
index f421fb3a1c4e93209e9ef3a63d63e6c6831d9a83..f5f3a4c747bf645246f4fc75b5fe8f11bba178f0 100755
--- a/product/ERP5/InteractionWorkflow.py
+++ b/product/ERP5/InteractionWorkflow.py
@@ -18,16 +18,21 @@
 
 import Globals
 import App
-from AccessControl import ClassSecurityInfo
+from AccessControl import getSecurityManager, ClassSecurityInfo
 from Products.CMFCore.utils import getToolByName, _getAuthenticatedUser
 from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
 from Acquisition import aq_base, aq_parent, aq_inner, aq_acquire
 from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
+from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC, TRIGGER_WORKFLOW_METHOD
+from Products.CMFCore.WorkflowCore import WorkflowException, \
+     ObjectDeleted, ObjectMoved
+from Products.DCWorkflow.Expression import StateChangeInfo, createExprContext
 from Products.CMFCore.WorkflowTool import addWorkflowFactory
+from Products.CMFActivity.ActiveObject import ActiveObject
 
 from zLOG import LOG
 
-class InteractionWorkflowDefinition (DCWorkflowDefinition):
+class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
     """
     The InteractionTool implements portal object
     interaction policies.
@@ -95,7 +100,6 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition):
         {'label': 'Interactions', 'action': 'interactions/manage_main'},
         {'label': 'Variables', 'action': 'variables/manage_main'},
         {'label': 'Scripts', 'action': 'scripts/manage_main'},
-        {'label': 'Permissions', 'action': 'manage_permissions'},
         ) + App.Undo.UndoSupport.manage_options
 
     def __init__(self, id):
@@ -109,6 +113,313 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition):
         from Products.DCWorkflow.Scripts import Scripts
         self._addObject(Scripts('scripts'))
 
+    def _executeTransition(self, ob, tdef=None, kwargs=None):
+        '''
+        Private method.
+        Puts object in a new state.
+        '''
+        sci = None
+        econtext = None
+        moved_exc = None
+
+        # Figure out the old and new states.
+        old_sdef = self._getWorkflowStateOf(ob)
+        old_state = old_sdef.getId()
+        if tdef is None:
+            new_state = self.initial_state
+            former_status = {}
+        else:
+            new_state = tdef.new_state_id
+            if not new_state:
+                # Stay in same state.
+                new_state = old_state
+            former_status = self._getStatusOf(ob)
+        new_sdef = self.states.get(new_state, None)
+        if new_sdef is None:
+            raise WorkflowException, (
+                'Destination state undefined: ' + new_state)
+
+        # Execute the "before" script.
+        if tdef is not None:
+          for script_name in tdef.script_name:
+            script = self.scripts[script_name]
+            # Pass lots of info to the script in a single parameter.
+            sci = StateChangeInfo(
+                ob, self, former_status, tdef, old_sdef, new_sdef, kwargs)
+            try:
+                script(sci)  # May throw an exception.
+            except ObjectMoved, moved_exc:
+                ob = moved_exc.getNewObject()
+                # Re-raise after transition
+
+        # Update variables.
+        state_values = new_sdef.var_values
+        if state_values is None: state_values = {}
+        tdef_exprs = None
+        if tdef is not None: tdef_exprs = tdef.var_exprs
+        if tdef_exprs is None: tdef_exprs = {}
+        status = {}
+        for id, vdef in self.variables.items():
+            if not vdef.for_status:
+                continue
+            expr = None
+            if state_values.has_key(id):
+                value = state_values[id]
+            elif tdef_exprs.has_key(id):
+                expr = tdef_exprs[id]
+            elif not vdef.update_always and former_status.has_key(id):
+                # Preserve former value
+                value = former_status[id]
+            else:
+                if vdef.default_expr is not None:
+                    expr = vdef.default_expr
+                else:
+                    value = vdef.default_value
+            if expr is not None:
+                # Evaluate an expression.
+                if econtext is None:
+                    # Lazily create the expression context.
+                    if sci is None:
+                        sci = StateChangeInfo(
+                            ob, self, former_status, tdef,
+                            old_sdef, new_sdef, kwargs)
+                    econtext = createExprContext(sci)
+                value = expr(econtext)
+            status[id] = value
+
+        # Update state.
+        status[self.state_var] = new_state
+        tool = aq_parent(aq_inner(self))
+        tool.setStatusOf(self.id, ob, status)
+
+        # Update role to permission assignments.
+        self.updateRoleMappingsFor(ob)
+
+        # Execute the "after" script.
+        if tdef is not None:
+          for after_script_name in tdef.after_script_name:
+              script = self.scripts[after_script_name]
+              # Pass lots of info to the script in a single parameter.
+              sci = StateChangeInfo(
+                  ob, self, status, tdef, old_sdef, new_sdef, kwargs)
+              script(sci)  # May throw an exception.
+
+        # Execute the "activate" script.
+        if tdef is not None:
+          for after_script_name in tdef.activate_script_name:
+              script = self.scripts[after_script_name]
+              # Pass lots of info to the script in a single parameter.
+              sci = StateChangeInfo(
+                  ob.activate(activity='SQLQueue'), None, status, tdef, old_sdef, new_sdef, kwargs)
+              script(sci)  # May throw an exception.
+        
+        # Return the new state object.
+        if moved_exc is not None:
+            # Propagate the notification that the object has moved.
+            raise moved_exc
+        else:
+            return new_sdef
+
+    security.declarePrivate('listObjectActions')
+    def listObjectActions(self, info):
+        return []
+
+    security.declarePrivate('isInfoSupported')
+    def isInfoSupported(self, ob, name):
+        '''
+        Returns a true value if the given info name is supported.
+        '''
+        vdef = self.variables.get(name, None)
+        if vdef is None:
+            return 0
+        return 1
+    
+    security.declarePrivate('getInfoFor')
+    def getInfoFor(self, ob, name, default):
+        '''
+        Allows the user to request information provided by the
+        workflow.  This method must perform its own security checks.
+        '''
+        vdef = self.variables[name]
+        if vdef.info_guard is not None and not vdef.info_guard.check(
+            getSecurityManager(), self, ob):
+            return default
+        status = self._getStatusOf(ob)
+        if status is not None and status.has_key(name):
+            value = status[name]
+        # Not set yet.  Use a default.
+        elif vdef.default_expr is not None:
+            ec = createExprContext(StateChangeInfo(ob, self, status))
+            value = vdef.default_expr(ec)
+        else:
+            value = vdef.default_value
+
+        return value
+    
+    security.declarePrivate('isWorkflowMethodSupported')
+    def isWorkflowMethodSupported(self, ob, method_id):
+        '''
+        Returns a true value if the given workflow is 
+        automatic with the propper method_id
+        '''
+        return 0
+        for t in self.interactions.values():
+            if t.trigger_type == TRIGGER_WORKFLOW_METHOD:
+                if t.method_id == method_id:
+                    if t.portal_type_filter is None:
+                      return 1
+                    elif ob.getPortalType() in t.portal_type_filter:
+                      return 1
+        return 0                
+
+
+    security.declarePrivate('wrapWorkflowMethod')
+    def wrapWorkflowMethod(self, ob, method_id, func, args, kw):
+        '''
+        Allows the user to request a workflow action.  This method
+        must perform its own security checks.
+        '''
+        
+        for t in self.interactions.values():
+            tdef = None
+            if t.trigger_type == TRIGGER_WORKFLOW_METHOD:
+                if t.method_id == 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:
+                # Only execute if guard OK
+                if self._checkTransitionGuard(tdef, ob):
+                    res = apply(func, args, kw)
+                    try:
+                        self._changeStateOf(ob, tdef)
+                    except ObjectDeleted:
+                        # Re-raise with a different result.
+                        raise ObjectDeleted(res)
+                    except ObjectMoved, ex:
+                        # Re-raise with a different result.
+                        raise ObjectMoved(ex.getNewObject(), res)
+                    return res
+
+    security.declarePrivate('notifyBefore')
+    def notifyBefore(self, ob, action, args=None, kw=None):
+        '''
+        Notifies this workflow of an action before it happens,
+        allowing veto by exception.  Unless an exception is thrown, either
+        a notifySuccess() or notifyException() can be expected later on.
+        The action usually corresponds to a method name.
+        '''
+        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 t.method_id == action:
+                    if t.portal_type_filter is None:
+                      tdef = t
+                    elif ob.getPortalType() in t.portal_type_filter:
+                      tdef = t
+            if tdef is not None:
+                former_status = self._getStatusOf(ob)
+                # Execute the "before" script.
+                for script_name in tdef.script_name:
+                    script = self.scripts[script_name]
+                    # Pass lots of info to the script in a single parameter.
+                    sci = StateChangeInfo(
+                        ob, self, former_status, tdef, None, None, None)
+                    try:
+                        script(sci)  # May throw an exception.
+                    except ObjectMoved, moved_exc:
+                        ob = moved_exc.getNewObject()
+                        # Re-raise after transition
+                return                      
+
+    security.declarePrivate('notifySuccess')
+    def notifySuccess(self, ob, action, result, args=None, kw=None):
+        '''
+        Notifies this workflow that an action has taken place.
+        '''
+        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 t.method_id == action:
+                    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.
+                former_status = self._getStatusOf(ob)
+                tdef_exprs = tdef.var_exprs
+                if tdef_exprs is None: tdef_exprs = {}
+                status = {}
+                for id, vdef in self.variables.items():
+                    if not vdef.for_status:
+                        continue
+                    expr = None
+                    if tdef_exprs.has_key(id):
+                        expr = tdef_exprs[id]
+                    elif not vdef.update_always and former_status.has_key(id):
+                        # Preserve former value
+                        value = former_status[id]
+                    else:
+                        if vdef.default_expr is not None:
+                            expr = vdef.default_expr
+                        else:
+                            value = vdef.default_value
+                    if expr is not None:
+                        # Evaluate an expression.
+                        if econtext is None:
+                            # Lazily create the expression context.
+                            if sci is None:
+                                sci = StateChangeInfo(
+                                    ob, self, former_status, tdef,
+                                    None, None, None)
+                            econtext = createExprContext(sci)
+                        value = expr(econtext)
+                    status[id] = value
+        
+                # Update state.
+                tool = aq_parent(aq_inner(self))
+                tool.setStatusOf(self.id, ob, status)
+        
+                # Execute the "after" script.
+                for script_name in tdef.after_script_name:
+                    script = self.scripts[script_name]
+                    # Pass lots of info to the script in a single parameter.
+                    sci = StateChangeInfo(
+                        ob, self, status, tdef, None, None, None)
+                    try:
+                        script(sci)  # May throw an exception.
+                    except ObjectMoved, moved_exc:
+                        ob = moved_exc.getNewObject()
+                        # Re-raise after transition
+
+                # Execute the "after" script.
+                for script_name in tdef.activate_script_name:
+                    self.activate(activity='SQLQueue').activeScript(script_name, ob.getRelativeUrl(), status, tdef.id)
+                
+                return
+    
+    security.declarePrivate('activeScript')
+    def activeScript(self, script_name, ob_url, status, tdef_id):
+          script = self.scripts[script_name]
+          ob = self.restrictedTraverse(ob_url)
+          tdef = self.interactions.get(tdef_id)
+          sci = StateChangeInfo(
+                        ob, self, status, tdef, None, None, None)                        
+          script(sci)                         
+  
+          
 Globals.InitializeClass(InteractionWorkflowDefinition)
 
 addWorkflowFactory(InteractionWorkflowDefinition, id='interaction_workflow',