[Erp5-report] r26653 - /erp5/trunk/products/ERP5/Document/

nobody at svn.erp5.org nobody at svn.erp5.org
Mon Apr 27 11:48:25 CEST 2009


Author: luke
Date: Mon Apr 27 11:48:25 2009
New Revision: 26653

URL: http://svn.erp5.org?rev=26653&view=rev
Log:
 - Business Process Modelling documents

Added:
    erp5/trunk/products/ERP5/Document/BusinessPath.py
    erp5/trunk/products/ERP5/Document/BusinessProcess.py
    erp5/trunk/products/ERP5/Document/BusinessState.py

Added: erp5/trunk/products/ERP5/Document/BusinessPath.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BusinessPath.py?rev=26653&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/Document/BusinessPath.py (added)
+++ erp5/trunk/products/ERP5/Document/BusinessPath.py [utf8] Mon Apr 27 11:48:25 2009
@@ -1,0 +1,267 @@
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
+#                    Jean-Paul Smets-Solanes <jp at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+from Globals import InitializeClass, PersistentMapping
+from AccessControl import ClassSecurityInfo
+
+from Products.CMFCore.PortalFolder import ContentFilter
+from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
+from Products.ERP5.Document.Path import Path
+
+import zope.interface
+
+class BusinessPath(Path):
+  """
+    The BusinessPath class embeds all information related to 
+    lead times and parties involved at a give phase of a business
+    process.
+
+    BusinessPath are also used as helper to build buildable movements.
+    Here is the typical code of an alarm:
+   
+    Approach 1: explanation per explanation
+      builder = portal_deliveries.default_order_builder
+      for path in builder.getSpecialiseRelatedValueList() # or wharever category
+        for explanation in portal_catalog(buildable=1, portal_type='Order'):
+          path.build(explanation)
+
+      Pros: easy explanation based approach
+      Cons: buildable column added in delivery table
+            reexpand of a finished order might generate remaining buildable
+
+    Approach 2: isBuildable is indexed for SimulationMovements
+      isBuildable() method is added to SimulationMovement
+
+      Pros: global select is possible
+      Cons: reindex of simulation is required
+            slow indexing
+
+    Approach 3: isBuildable is invoked during build "after select" process
+      builder = portal_deliveries.default_order_builder
+      for path in builder.getSpecialiseRelatedValueList() # or wharever category
+        builder.build(causality_uid=path.getUid(),) # Select movemenents
+
+      Pros: global select is possible
+      Cons: global select retrieves long lists
+            slow build
+
+     Method 3 is best
+  """
+  meta_type = 'ERP5 Business Path'
+  portal_type = 'Business Path'
+  isPredicate = 1
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+  # Declarative properties
+  property_sheets = ( PropertySheet.Base
+                    , PropertySheet.XMLObject
+                    , PropertySheet.CategoryCore
+                    , PropertySheet.DublinCore
+                    , PropertySheet.Folder
+                    , PropertySheet.Comment
+                    , PropertySheet.Arrow
+                    , PropertySheet.Chain
+                    , PropertySheet.BusinessPath
+                    )
+
+  # Declarative interfaces
+  zope.interface.implements(Interface.ICategoryAccessProvider,
+                            Interface.IArrow)
+
+  # IBusinessPath Interface
+  security.declareProtected(Permissions.AccessContentsInformation, 'getSourceBaseCategoryList')
+  def getSourceBaseCategoryList(self):
+    """
+      Returns all categories which are used to define the source
+      of this Arrow
+    """
+    # Naive implementation - we must use category groups instead
+    return ('source', 'source_section', 'source_payment', 'source_project', )
+
+  security.declareProtected(Permissions.AccessContentsInformation, 'getDestinationBaseCategoryList')
+  def getDestinationBaseCategoryList(self):
+    """
+      Returns all categories which are used to define the destination
+      of this Arrow
+    """
+    # Naive implementation - we must use category groups instead
+    return ('destination', 'destination_section', 'destination_payment', 'destination_project', )
+
+  # ICategoryAccessProvider overriden methods
+  def _getCategoryMembershipList(self, category, **kw):
+    """
+      Overriden in order to take into account dynamic arrow
+      categories
+    """
+    context = kw.get('context')
+    result = Path._getCategoryMembershipList(self, category, **kw)
+    if context is not None:
+      dynamic_category_list = self._getDynamicCategoryList(context)
+      dynamic_category_list= self._filterCategoryList(dynamic_category_list, category, **kw)
+      # TODO: static categories should have priority over dynamic categories
+      result = dynamic_category_list + result
+    return result
+
+  def _getAcquiredCategoryMembershipList(self, category, **kw):
+    """
+      Overriden in order to take into account dynamic arrow
+      categories
+    """
+    context = kw.get('context')
+    result = Path._getAcquiredCategoryMembershipList(self, category, **kw)
+    if context is not None:
+      dynamic_category_list = self._getDynamicCategoryList(context)
+      dynamic_category_list= self._filterCategoryList(dynamic_category_list, category, **kw)
+      # TODO: static categories should have priority over dynamic categories
+      result = dynamic_category_list + result
+    return result
+
+  def _filterCategoryList(self, category_list, category, spec=(), filter=None, portal_type=(), base=0, 
+                         keep_default=1, checked_permission=None):
+    """
+      XXX - implementation missing
+      TBD - look at CategoryTool._buildFilter for inspiration
+    """
+    return category_list
+
+  # Dynamic context based categories
+  def _getDynamicCategoryList(self, context):
+    return self._getDynamicSourceCategoryList(context) \
+         + self._getDynamicDestinationCategoryList(context)
+
+  def _getDynamicSourceCategoryList(self, context):
+    method_id = self.getSourceMethodId()
+    if method_id:
+      method = getattr(self, method_id)
+      return method(context)
+    return ()
+
+  def _getDynamicDestinationCategoryList(self, context):
+    method_id = self.getDestinationMethodId()
+    if method_id:
+      method = getattr(self, method_id)
+      return method(context)
+    return ()
+
+  # Core API
+  def isBuildable(self, explanation):
+    """
+    """
+    if self.isCompleted(explanation):
+      return False # No need to build what was already built
+    if self.isFrozen(explanation):
+      return False # No need to build what is frozen
+    predecessor = self.getPredecessorValue()
+    if predecessor is None:
+      return True # No predecessor, let's build
+    if predecessor.isCompleted(explanation):
+      return True
+    return False
+
+  def isPartiallyBuildable(self, explanation):
+    """
+      Not sure if this will exist some day XXX
+    """
+
+  def _getRelatedSimulationMovementList(explanation):
+    """
+      
+    """
+    return self.getCausalityRelatedValueList(portal_type='Simulation Movement',
+                                             explanation_uid=explanation.getUid())
+
+  def isCompleted(self, explanation):
+    """
+      Looks at all simulation related movements
+      and checks the simulation_state of the delivery
+    """
+    acceptable_state_list = self.getCompletedStateIdList() # XXX Missing method / name
+    for movement in self._getRelatedSimulationMovementList(explanation):
+      if movement.getSimulationState() not in acceptable_state_list:
+        return False
+    return True
+
+  def isPartiallyCompleted(self, explanation):
+    """
+      Looks at all simulation related movements
+      and checks the simulation_state of the delivery
+    """
+    acceptable_state_list = self.getCompletedStateList() # XXX Missing method / name
+    for movement in self._getRelatedSimulationMovementList(explanation):
+      if movement.getSimulationState() in acceptable_state_list:
+        return True
+    return False
+
+  def isFrozen(self, explanation):
+    """
+      Looks at all simulation related movements
+      and checks if frozen
+    """
+    movement_list = self._getRelatedSimulationMovementList(explanation)
+    if len(movement_list) == 0:
+      return False # Nothing to be considered as Frozen
+    for movement in movement_list:
+      if not movement.isFrozen():
+        return False
+    return True
+
+  def build(self, explanation):
+    """
+      Build
+    """
+    builder_list = self.getBuilderList() # Missing method
+    for builder in builder_list:
+      builder.build(causality_uid=self.getUid()) # This is one way of doing
+      builder.build(movement_relative_url_list=
+        self._getRelatedSimulationMovementList(explanation)) # Another way
+
+  # Date calculation
+  def getExpectedStartDate(self, explanation, predecessor_date=None):
+    """
+      Returns the expected start date for this
+      path based on the explanation.
+
+      predecessor_date -- if provided, computes the date base on the
+                          date value provided
+    """
+    if predecessor_date is None:
+      predecessor_date = self.getPredecessorValue().getExpectedCompletionDate()
+    return predecessor_date + wait_time
+
+  def getExpectedStopDate(self, explanation, predecessor_date=None):
+    """
+      Returns the expected stop date for this
+      path based on the explanation.
+
+      predecessor_date -- if provided, computes the date base on the
+                          date value provided
+    """
+    return context.getExpectedStartDate(explanation, predecessor_date=predecessor_date) + lead_time

Added: erp5/trunk/products/ERP5/Document/BusinessProcess.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BusinessProcess.py?rev=26653&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/Document/BusinessProcess.py (added)
+++ erp5/trunk/products/ERP5/Document/BusinessProcess.py [utf8] Mon Apr 27 11:48:25 2009
@@ -1,0 +1,177 @@
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
+#                    Jean-Paul Smets-Solanes <jp at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+from Globals import InitializeClass, PersistentMapping
+from AccessControl import ClassSecurityInfo
+
+from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
+from Products.ERP5Type.XMLObject import XMLObject
+from Products.ERP5.Document.Path import Path
+
+class BusinessProcess(Path, XMLObject):
+  """
+    The BusinessProcess class is a container class which is used
+    to describe business processes in the area of trade, payroll
+    and production.
+  """
+  meta_type = 'ERP5 Business Process'
+  portal_type = 'Business Process'
+  isPredicate = 1
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+  # Declarative properties
+  property_sheets = ( PropertySheet.Base
+                    , PropertySheet.XMLObject
+                    , PropertySheet.CategoryCore
+                    , PropertySheet.DublinCore
+                    , PropertySheet.Folder
+                    , PropertySheet.Comment
+                    , PropertySheet.Arrow
+                    )
+
+  # Access to path and states of the business process
+  security.declareProtected(Permissions.AccessContentsInformation, 'getPathValueList')
+  def getPathValueList(self, trade_phase, context=None, **kw):
+    """
+      Returns all Path of the current BusinessProcess which
+      are matching the given trade_phase and the optional context.
+
+      trade_phase -- a single trade phase category or a list of
+                      trade phases
+
+      context -- the context to search matching predicates for
+
+      **kw -- same parameters as for searchValues / contentValues
+    """
+    # Naive implementation to redo XXX using contentValues
+    if type(trade_phase) is type(''): # XXX - bad, use isinstance
+      trade_phase = (trade_phase,)
+    result = []
+    for document in self.contentValues(portal_type="Business Path"):
+      for phase in trade_phase:
+        if document.isMemberOf('trade_phase/' + phase): # XXX - not so good, use filter if possible
+          result.append(document)
+          break
+    return result
+
+  security.declareProtected(Permissions.AccessContentsInformation, 'getStateValueList')
+  def getStateValueList(self, *args, **kw):
+    """
+      Returns all states of the business process. The method
+      **kw parameters follows the API of searchValues / contentValues
+    """
+    # Naive implementation to redo XXX
+    kw['portal_type'] = "Business State"
+    return self.contentValues(*args, **kw)
+
+  # Access to path and states of the business process
+  def isCompleted(self, explanation):
+    """
+      True if all states are completed
+    """
+    for state in self.getStateValueList():
+      if not state.isCompleted(explanation):
+        return False
+    return True
+  
+  def isBuildable(self, explanation):
+    """
+      True if all any path is buildable
+    """
+    return len(self.getBuildablePathValueList(explanation)) != 0
+
+  def getBuildablePathValueList(self, explanation):
+    """
+      Returns the list of Business Path which are ready to 
+      be built
+    """
+    return filter(lambda x:x.isBuildable(explanation), self.getPathValueList())
+
+  def getCompletedStateValueList(self, explanation):
+    """
+      Returns the list of Business States which are finished
+    """
+    return filter(lambda x:x.isCompleted(explanation), self.getStateValueList())
+
+  def getPartiallyCompletedStateValueList(self, explanation):
+    """
+      Returns the list of Business States which are finished
+    """
+    return filter(lambda x:x.isPartiallyCompleted(explanation), self.getStateValueList())
+
+  def getLatestCompletedStateValue(self, explanation):
+    """
+      Returns the most advanced completed state
+    """
+    for state in self.getCompletedStateValueList(explanation):
+      for path in state.getPredecessorRelatedValueList():
+        if not path.isCompleted(explanation):
+          return state
+    return None
+
+  def getLatestPartiallyCompletedStateValue(self, explanation):
+    """
+      Returns the most advanced completed state
+    """
+    for state in self.getCompletedStateValueList(explanation):
+      for path in state.getPredecessorRelatedValueList():
+        if not path.isPartiallyCompleted(explanation):
+          return state
+    return None
+
+  def getLatestCompletedStateValueList(self, explanation):
+    """
+      Returns the most advanced completed state
+    """
+    result = []
+    for state in self.getCompletedStateValueList(explanation):
+      for path in state.getPredecessorRelatedValueList():
+        if not path.isCompleted(explanation):
+          result.append(state)
+    return result
+
+  def getLatestPartiallyCompletedStateValueList(self, explanation):
+    """
+      Returns the most advanced completed state
+    """
+    result = []
+    for state in self.getCompletedStateValueList(explanation):
+      for path in state.getPredecessorRelatedValueList():
+        if not path.isPartiallyCompleted(explanation):
+          result.append(state)
+    return result
+
+  def build(self, explanation):
+    """
+      Build whatever is buildable
+    """
+    for path in self.getBuildablePathValueList(explanation):
+      path.build(explanation)

Added: erp5/trunk/products/ERP5/Document/BusinessState.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BusinessState.py?rev=26653&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/Document/BusinessState.py (added)
+++ erp5/trunk/products/ERP5/Document/BusinessState.py [utf8] Mon Apr 27 11:48:25 2009
@@ -1,0 +1,90 @@
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
+#                    Jean-Paul Smets-Solanes <jp at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+from Globals import InitializeClass, PersistentMapping
+from AccessControl import ClassSecurityInfo
+
+from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
+from Products.ERP5Type.XMLObject import XMLObject
+
+class BusinessState(XMLObject):
+  """
+    The BusinessProcess class is a container class which is used
+    to describe business processes in the area of trade, payroll
+    and production.
+  """
+  meta_type = 'ERP5 Business State'
+  portal_type = 'Business State'
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+  # Declarative properties
+  property_sheets = ( PropertySheet.Base
+                    , PropertySheet.XMLObject
+                    , PropertySheet.CategoryCore
+                    , PropertySheet.DublinCore
+                    , PropertySheet.Folder
+                    , PropertySheet.Comment
+                    )
+
+  # Core API
+  def isCompleted(self, explanation):
+    """
+      If all path which reach this state are completed
+      then this state is completed
+    """
+    for path in self.getSuccessorRelatedValueList():
+      if not path.isCompleted(explanation):
+        return False
+    return True
+
+
+  def isPartiallyCompleted(self, explanation):
+    """
+      If all path which reach this state are partially completed
+      then this state is completed
+    """
+    for path in self.getSuccessorRelatedValueList():
+      if not path.isPartiallyCompleted(explanation):
+        return False
+    return True
+
+  # Duration calculation
+  def getExpectedCompletionDate(self, explanation):
+    """
+      Returns the expected completion date for this
+      state based on the explanation.
+    """
+
+  def getExpectedCompletionDuration(self, explanation):
+    """
+      Returns the expected completion duration for this
+      state.
+    """




More information about the Erp5-report mailing list