diff --git a/product/ERP5/ExplanationCache.py b/product/ERP5/ExplanationCache.py index cc087b00f91eed5eecd7f91e2bb70c61a788fbb0..231d9455ef6f4f87081aa031ae27f4fd9c884a12 100644 --- a/product/ERP5/ExplanationCache.py +++ b/product/ERP5/ExplanationCache.py @@ -32,6 +32,8 @@ import types from Products.CMFCore.utils import getToolByName from Products.ERP5Type.TransactionalVariable import getTransactionalVariable +from zLOG import LOG + class ExplanationCache: """ExplanationCache provides a central access to all parameters and values which are needed to process @@ -51,8 +53,8 @@ class ExplanationCache: self.simulation_movement_cache = {} # Simulation Movement Cache self.explanation_uid_cache = [] self.explanation_path_pattern_cache = [] - self.closure_cache = [] - self.union_cache = None + self.closure_cache = {} + self.union_cache = None def _getDeliveryMovementList(self): """Returns self is explanation is a delivery line @@ -84,7 +86,7 @@ class ExplanationCache: result.add(simulation_movement.getExplanationUid()) # XXX-JPS use new API later # Return result self.explanation_uid_cache = result - return result + return tuple(result) def getSimulationPathPatternList(self): """Return the list of root path of simulation tree which are @@ -134,6 +136,7 @@ class ExplanationCache: if type(value) is not types.DictType: # We have a real root result.append('%s/%s%' % (prefix, key)) + # XXX-JPS here we must add all parent movements XXX-JPS else: browsePathDict('%s/%s' % (prefix, key), value) # Recursing with string append is slow XXX-JPS @@ -147,21 +150,32 @@ class ExplanationCache: """ return self.getSimulationMovementValueList(causality_uid=business_path.getUid()) + def getBusinessPathRelatedMovementValueList(self, business_path): + """Returns the list of delivery movements related to a business_path + in the context the our explanation. + """ + #XXXXXXXXXXX BAD + return self.getSimulationMovementValueList(causality_uid=business_path.getUid()) + def getSimulationMovementValueList(self, **kw): """Search Simulation Movements related to our explanation. Cache result so that the second time we saarch for the same list we need not involve the catalog again. + + NOTE: + - this method can be made catalog independent + in case explanation is an applied rule, we can + browse parent and child movement """ kw_tuple = tuple(kw.items()) # We hope that no sorting is needed if kw.get('path', None) is None: - kw['path'] = self.getSimulationPathPatternList(), # XXX-JPS Explicit Query is better + kw['path'] = self.getSimulationPathPatternList() # XXX-JPS Explicit Query is better if kw.get('explanation_uid', None) is None: kw['explanation_uid'] = self.getRootExplanationUidList() - if self.simulation_movement_list.get(kw_tuple, None) is None: + LOG('getSimulationMovementValueList', 0, repr(kw)) + if self.simulation_movement_cache.get(kw_tuple, None) is None: self.simulation_movement_cache[kw_tuple] = \ self.portal_catalog(portal_type="Simulation Movement", - explanation_uid=explanation_uid, - path=path, **kw) return self.simulation_movement_cache[kw_tuple] @@ -179,23 +193,34 @@ class ExplanationCache: **kw) return business_path_list - def geBusinessPathClosure(business_process, business_path): + def getBusinessPathClosure(self, business_process, business_path): """Creates a Business Process by filtering out all Business Path in 'business_process' which are not related to a simulation movement - which is either or parent or a child of explanation simulations movements + which is either a parent or a child of explanation simulations movements caused by 'business_path' + + NOTE: Business Path Closure must be at least as "big" as composed + business path. The appropriate calculation is still not clear. + Options are: + - take all path of composed business path (even not yet expanded) + - take all path of composed business path which phase is not yet expanded """ # Try to return cached value first new_business_process = self.closure_cache.get(business_path, None) + LOG('Inside getBusinessPathClosure cache: new_business_process', 0, repr(new_business_process)) if new_business_process is not None: + LOG('Leaving getBusinessPathClosure new_business_process', 0, repr(new_business_process)) return new_business_process # Build a list of path patterns which apply to current business_path path_list = self.getSimulationPathPatternList() + LOG('Inside getBusinessPathClosure path_list', 0, repr(path_list)) path_list = map(lambda x:x[0:-1], path_list) # Remove trailing % path_set = set() + LOG('Inside getBusinessPathClosure _getExplanationRelatedSimulationMovementValueList', 0, repr(business_path.\ + _getExplanationRelatedSimulationMovementValueList(self.explanation))) for simulation_movement in business_path.\ - _getExplanationRelatedSimulationMovementValueList(explanation): + _getExplanationRelatedSimulationMovementValueList(self.explanation): simulation_path = simulation_movement.getPath() for path in path_list: if simulation_path.startswith(path): @@ -210,10 +235,13 @@ class ExplanationCache: # Build a new closure business process def hasMatchingMovement(business_path): - return len(self.getSimulationMovementValueList(path=path_set, + return len(self.getSimulationMovementValueList(path=path_tuple, causality_uid=business_path.getUid())) - new_business_process = business_process.getParentValue().newContent(temp_object=True) # XXX-JPS is this really OK with union business processes + module = business_process.getPortalObject().business_process_module # XXX-JPS + LOG('module', 0, repr(module)) + new_business_process = module.newContent(portal_type="Business Process", + temp_object=True) # XXX-JPS is this really OK with union business processes i = 0 for business_path in business_process.getBusinessPathValueList(): if hasMatchingMovement(business_path): @@ -223,6 +251,7 @@ class ExplanationCache: self.closure_cache[business_path] = new_business_process self.closure_cache[path_tuple] = new_business_process + LOG('Leaving getBusinessPathClosure new_business_process', 0, repr(new_business_process)) return new_business_process def getUnionBusinessProcess(self): @@ -262,6 +291,11 @@ def _getBusinessPathClosure(business_process, explanation, business_path): contains only those Business Path which are related to business_path in the context of explanation. """ + if explanation.getPortalType() == "Applied Rule": + # There is no way to guess the closure during expand + # since some movements may not be generated. The resulting + # closure might be smaller than expexted + return business_process explanation_cache = _getExplanationCache(explanation) return explanation_cache.getBusinessPathClosure(business_process, business_path)