From 914bda0a8ed00869ed2bc57e9732df198381ba4f Mon Sep 17 00:00:00 2001
From: Jean-Paul Smets <jp@nexedi.com>
Date: Tue, 10 Aug 2004 10:14:29 +0000
Subject: [PATCH] Imp)lemented dynamic workflow status / transiton method
 generation

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@1332 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5Type/Base.py | 96 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 88 insertions(+), 8 deletions(-)

diff --git a/product/ERP5Type/Base.py b/product/ERP5Type/Base.py
index a841abd40b..43c8c0fbcc 100755
--- a/product/ERP5Type/Base.py
+++ b/product/ERP5Type/Base.py
@@ -33,6 +33,9 @@ from Acquisition import aq_base, aq_inner, aq_acquire, aq_chain
 
 from Products.CMFCore.WorkflowCore import WorkflowMethod
 from Products.CMFCore.PortalContent import PortalContent
+from Products.CMFCore.utils import getToolByName
+
+from Products.DCWorkflow.Transitions import TRIGGER_WORKFLOW_METHOD
 
 from Products.CMFActivity.ActiveObject import ActiveObject
 
@@ -40,10 +43,11 @@ from Products.ERP5Type import _dtmldir
 from Products.ERP5Type import PropertySheet
 from Products.ERP5Type import Permissions
 from Products.ERP5Type.Utils import UpperCase
-from Products.ERP5Type.Utils import convertToUpperCase
+from Products.ERP5Type.Utils import convertToUpperCase, convertToMixedCase
 from Products.ERP5Type.Utils2 import _getListFor
 from Products.ERP5Type.Accessor.TypeDefinition import list_types
 from Products.ERP5Type.XMLExportImport import Base_asXML
+from Accessor import WorkflowState
 
 from Products.Base18.Base18 import Base18
 
@@ -63,20 +67,86 @@ from email import Encoders
 from socket import gethostname, gethostbyaddr
 import random
 
-from zLOG import LOG
+from zLOG import LOG, INFO, ERROR, WARNING
 
 # Dynamic method acquisition system (code generation)
 aq_method_generated = {}
 
-def _initializeDefaultProperties(klass):
+def initializeDynamicProperties(self, klass):
+  id = ''
+  LOG('before aq_method_generated %s' % id, 0, str(klass.__name__))
   if not aq_method_generated.has_key(klass):
+    aq_method_generated[klass] = 1                      
+    # Recurse to superclasses                
+    for super_klass in klass.__bases__:      
+      if getattr(super_klass, 'isRADContent', 0): initializeDynamicProperties(None, super_klass)         
+    # Initialize default properties
     LOG('in aq_method_generated %s' % id, 0, str(klass.__name__))
     from Utils import initializeDefaultProperties
     initializeDefaultProperties([klass])
-    aq_method_generated[klass] = 1  
-    for super_klass in klass.__bases__:
-      _initializeDefaultProperties(super_klass)         
-
+    if self is not None:
+      # We should now make sure workflow methods are defined
+      # and also make sure simulation state is defined     
+      portal_workflow = getToolByName(self, 'portal_workflow')
+      for wf in portal_workflow.getWorkflowsFor(self):      
+        wf_id = wf.id
+        try:
+          #LOG('in aq_method_generated %s' % id, 0, "found state workflow %s" % wf.id)
+          if wf.__class__.__name__ in ('DCWorkflowDefinition', ):
+            # Create state var accessor
+            state_var = wf.variables.getStateVar()
+            method_id = 'get%s' % UpperCase(state_var)                    
+            if not hasattr(klass, method_id):
+              method = WorkflowState.Getter(method_id, wf_id)
+              setattr(klass, method_id, method)
+              klass.security.declareProtected( Permissions.AccessContentsInformation, method_id )
+              #LOG('in aq_method_generated %s' % id, 0, "added state method %s" % method_id)
+        except:
+          LOG('Base', ERROR,
+              'Could not generate worklow state method for workflow %s on class %s.' % (wf_id, klass),
+                error=sys.exc_info())                            
+        try:
+          LOG('in aq_method_generated %s' % id, 0, "found transition workflow %s" % wf.id)
+          if wf.__class__.__name__ in ('DCWorkflowDefinition', ):            
+            for tr_id in wf.transitions.objectIds():
+              tdef = wf.transitions.get(tr_id, None)            
+              if tdef.trigger_type == TRIGGER_WORKFLOW_METHOD:
+                method_id = convertToMixedCase(tr_id)
+                if not hasattr(klass, method_id):
+                  method = WorkflowMethod(klass._doNothing, method_id)
+                  setattr(klass, method_id, method)                               
+                  klass.security.declareProtected( Permissions.AccessContentsInformation, method_id )
+                  #LOG('in aq_method_generated %s' % id, 0, "added transition method %s" % method_id)
+                else:
+                  # Wrap method into WorkflowMethod is needed
+                  method = getattr(klass, method_id)
+                  if callable(method):
+                    if not isinstance(method, WorkflowMethod):
+                      setattr(klass, method_id, WorkflowMethod(method))   
+          elif wf.__class__.__name__ in ('InteractionWorkflowDefinition', ):            
+            for tr_id in wf.interactions.objectIds():
+              tdef = wf.interactions.get(tr_id, None)            
+              if tdef.trigger_type == TRIGGER_WORKFLOW_METHOD:
+                for imethod_id in tdef.method_id:
+                  method_id = convertToMixedCase(imethod_id)
+                  if not hasattr(klass, method_id):
+                    method = WorkflowMethod(klass._doNothing, method_id)
+                    setattr(klass, method_id, method)                               
+                    klass.security.declareProtected( Permissions.AccessContentsInformation, method_id )
+                    #LOG('in aq_method_generated %s' % id, 0, "added interaction method %s" % method_id)
+                  else:
+                    # Wrap method into WorkflowMethod is needed
+                    method = getattr(klass, method_id)
+                    if callable(method):
+                      if not isinstance(method, WorkflowMethod):
+                        setattr(klass, method_id, WorkflowMethod(method))   
+        except:
+          LOG('Base', ERROR,
+              'Could not generate worklow transition methods for workflow %s on class %s.' % (wf_id, klass),
+                error=sys.exc_info())                            
+    # Mark as generated
+    aq_method_generated[klass] = 1                      
+    
 class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyManager ):
   """
     This is the base class for all ERP5 Zope objects.
@@ -123,11 +193,17 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
   # We want to use a default property view
   manage_propertiesForm = DTMLFile( 'dtml/properties', _dtmldir )
 
+  security.declareProtected( Permissions.AccessContentsInformation, 'test_dyn' )
+  def test_dyn(self):
+    """
+    """
+    initializeDynamicProperties(self, self.__class__)
+  
   def _aq_dynamic(self, id):  
     global aq_method_generated  
     klass = self.__class__
     if not aq_method_generated.has_key(klass):      
-      _initializeDefaultProperties(klass)
+      initializeDynamicProperties(self, klass)
       return getattr(self, id)
     return None    
     
@@ -149,6 +225,10 @@ class Base( CopyContainer, PortalContent, Base18, ActiveObject, ERP5PropertyMana
   def _getCategoryTool(self):
     return aq_inner(self.getPortalObject().portal_categories)
 
+  def _doNothing(self):
+    # A method which does nothing (and can be used to build WorkflowMethods which trigger worklow transitions)
+    pass
+  
   # Generic accessor
   def _getDefaultAcquiredProperty(self, key, default_value, null_value, 
         base_category=None, portal_type=None, copy_value=0, mask_value=0, sync_value=0,
-- 
2.30.9