[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