Commit dfec1c6c authored by Jean-Paul Smets's avatar Jean-Paul Smets

Blind commit with various changes to make build work if erp5_bpm installed

git-svn-id: https://svn.erp5.org/repos/public/erp5/sandbox/amount_generator@37443 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent dc99420c
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved. # Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
# Jean-Paul Smets-Solanes <jp@nexedi.com> # Jean-Paul Smets-Solanes <jp@nexedi.com>
# Yusuke Muraoka <yusuke@nexedi.com> # Yusuke Muraoka <yusuke@nexedi.com>
# Łukasz Nowak <luke@nexedi.com> # ?ukasz Nowak <luke@nexedi.com>
# #
# WARNING: This program as such is intended to be used by professional # WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential # programmers who take the whole responsibility of assessing all potential
...@@ -231,13 +231,15 @@ class BusinessLink(Path, Predicate): ...@@ -231,13 +231,15 @@ class BusinessLink(Path, Predicate):
implicitely defines a simulation subtree and a union implicitely defines a simulation subtree and a union
business process. business process.
""" """
LOG('Entering BusinessLink.isDelivered ',0, repr(explanation))
for simulation_movement in self._getExplanationRelatedSimulationMovementValueList( for simulation_movement in self._getExplanationRelatedSimulationMovementValueList(
explanation): explanation):
LOG('in isDelivered with ',0, repr(simulation_movement))
if not simulation_movement.getDelivery(): if not simulation_movement.getDelivery():
return False return False
return True return True
def build(self, explanation): def build(self, explanation=None):
"""Builds all related movements in the simulation using the builders """Builds all related movements in the simulation using the builders
defined on the Business Link. defined on the Business Link.
...@@ -246,11 +248,8 @@ class BusinessLink(Path, Predicate): ...@@ -246,11 +248,8 @@ class BusinessLink(Path, Predicate):
business process. business process.
""" """
builder_list = self.getDeliveryBuilderValueList() builder_list = self.getDeliveryBuilderValueList()
explanation_cache = _getExplanationCache(explanation) for builder in builder_list: # XXX-JPS Do we really need a builder list ? wouldn't predicate be more useful ?
for builder in builder_list:
# Call build on each builder # Call build on each builder
# Provide 2 parameters: self and and explanation_cache # Provide 2 parameters: self and and explanation_cache
builder.build(select_method_dict={ LOG('Invoking Builder', 0, repr((builder, self, explanation)))
'business_link': self, builder.build(explanation=explanation, business_link=self)
'explanation_cache': explanation_cache,
})
...@@ -37,6 +37,7 @@ from Products.ERP5.MovementCollectionDiff import _getPropertyAndCategoryList ...@@ -37,6 +37,7 @@ from Products.ERP5.MovementCollectionDiff import _getPropertyAndCategoryList
import zope.interface import zope.interface
from zLOG import LOG
class BusinessProcess(Path, XMLObject): class BusinessProcess(Path, XMLObject):
"""The BusinessProcess class is a container class which is used """The BusinessProcess class is a container class which is used
...@@ -129,18 +130,23 @@ class BusinessProcess(Path, XMLObject): ...@@ -129,18 +130,23 @@ class BusinessProcess(Path, XMLObject):
**kw -- same arguments as those passed to searchValues / contentValues **kw -- same arguments as those passed to searchValues / contentValues
""" """
if trade_phase is None: if trade_phase is not None:
trade_phase = set() if not isinstance(trade_phase, (list, tuple)):
elif not isinstance(trade_phase, (list, tuple)): trade_phase = (trade_phase,)
trade_phase = (trade_phase,) trade_phase = set([x.split('trade_phase/', 1)[-1] \
trade_phase = set([x.split('trade_phase/', 1)[-1] \ for x in trade_phase])
for x in trade_phase])
result = [] result = []
if kw.get('portal_type', None) is None: if kw.get('portal_type', None) is None:
kw['portal_type'] = self.getPortalTradeModelPathTypeList() kw['portal_type'] = self.getPortalTradeModelPathTypeList()
if kw.get('sort_on', None) is None: if kw.get('sort_on', None) is None:
kw['sort_on'] = 'int_index' kw['sort_on'] = 'int_index'
original_path_list = self.objectValues(**kw) # Why Object Values ??? XXX-JPS original_path_list = self.objectValues(**kw) # Why Object Values ??? XXX-JPS
LOG('self', 0, repr(self))
LOG('objectValues', 0, repr(self.objectValues()))
LOG('portal_type', 0, repr(kw['portal_type']))
LOG('objectValues kw', 0, repr(self.objectValues(**kw)))
LOG('trade_phase', 0, trade_phase)
LOG('original_path_list', 0, original_path_list)
# Separate the selection of trade model paths into two steps # Separate the selection of trade model paths into two steps
# for easier debugging. # for easier debugging.
# First, collect trade model paths which can be applicable to a given context. # First, collect trade model paths which can be applicable to a given context.
...@@ -151,6 +157,7 @@ class BusinessProcess(Path, XMLObject): ...@@ -151,6 +157,7 @@ class BusinessProcess(Path, XMLObject):
accept_path = False # Filter our business path which trade phase does not match accept_path = False # Filter our business path which trade phase does not match
if accept_path: if accept_path:
path_list.append(path) path_list.append(path)
LOG('path_list', 0, path_list)
# Then, filter trade model paths by Predicate API. # Then, filter trade model paths by Predicate API.
# FIXME: Ideally, we should use the Domain Tool to search business paths, # FIXME: Ideally, we should use the Domain Tool to search business paths,
# and avoid using the low level Predicate API. But the Domain Tool does # and avoid using the low level Predicate API. But the Domain Tool does
...@@ -158,6 +165,7 @@ class BusinessProcess(Path, XMLObject): ...@@ -158,6 +165,7 @@ class BusinessProcess(Path, XMLObject):
for path in path_list: for path in path_list:
if path.test(context): if path.test(context):
result.append(path) result.append(path)
LOG('result', 0, result)
return result return result
security.declareProtected(Permissions.AccessContentsInformation, 'getExpectedTradeModelPathStartAndStopDate') security.declareProtected(Permissions.AccessContentsInformation, 'getExpectedTradeModelPathStartAndStopDate')
...@@ -189,6 +197,7 @@ class BusinessProcess(Path, XMLObject): ...@@ -189,6 +197,7 @@ class BusinessProcess(Path, XMLObject):
raise ValueError('a reference date method must be defined on every Trade Model Path') raise ValueError('a reference date method must be defined on every Trade Model Path')
explanation_cache = _getExplanationCache(explanation) explanation_cache = _getExplanationCache(explanation)
LOG('calling explanation_cache.getReferenceDate', 0, '%s %s %s %s' % (explanation, self, trade_date, reference_date_method_id))
reference_date = explanation_cache.getReferenceDate(self, trade_date, reference_date_method_id) reference_date = explanation_cache.getReferenceDate(self, trade_date, reference_date_method_id)
# Computer start_date and stop_date (XXX-JPS this could be cached and accelerated) # Computer start_date and stop_date (XXX-JPS this could be cached and accelerated)
...@@ -221,12 +230,11 @@ class BusinessProcess(Path, XMLObject): ...@@ -221,12 +230,11 @@ class BusinessProcess(Path, XMLObject):
**kw -- same arguments as those passed to searchValues / contentValues **kw -- same arguments as those passed to searchValues / contentValues
""" """
if trade_phase is None: if trade_phase is not None:
trade_phase = set() if not isinstance(trade_phase, (list, tuple)):
elif not isinstance(trade_phase, (list, tuple)): trade_phase = set((trade_phase,))
trade_phase = set((trade_phase,)) else:
else: trade_phase = set(trade_phase)
trade_phase = set(trade_phase)
result = [] result = []
if kw.get('portal_type', None) is None: if kw.get('portal_type', None) is None:
kw['portal_type'] = self.getPortalBusinessLinkTypeList() kw['portal_type'] = self.getPortalBusinessLinkTypeList()
...@@ -251,6 +259,10 @@ class BusinessProcess(Path, XMLObject): ...@@ -251,6 +259,10 @@ class BusinessProcess(Path, XMLObject):
# FIXME: Ideally, we should use the Domain Tool to search business links, # FIXME: Ideally, we should use the Domain Tool to search business links,
# and avoid using the low level Predicate API. But the Domain Tool does # and avoid using the low level Predicate API. But the Domain Tool does
# support the condition above without scripting? # support the condition above without scripting?
LOG('business_link_list', 0, repr(business_link_list))
if context is None:
LOG('context is None', 0, repr(business_link_list))
return business_link_list
for business_link in business_link_list: for business_link in business_link_list:
if business_link.test(context): if business_link.test(context):
result.append(business_link) result.append(business_link)
...@@ -266,6 +278,7 @@ class BusinessProcess(Path, XMLObject): ...@@ -266,6 +278,7 @@ class BusinessProcess(Path, XMLObject):
business_link -- a Business Link document business_link -- a Business Link document
""" """
LOG('In isBusinessLinkCompleted', 0, repr(business_link))
# Return False if Business Link is not completed # Return False if Business Link is not completed
if not business_link.isCompleted(explanation): if not business_link.isCompleted(explanation):
return False return False
...@@ -365,12 +378,14 @@ class BusinessProcess(Path, XMLObject): ...@@ -365,12 +378,14 @@ class BusinessProcess(Path, XMLObject):
business_link -- a Business Link document business_link -- a Business Link document
""" """
# If everything is delivered, no need to build # If everything is delivered, no need to build
LOG('In isBusinessLinkBuildable', 0, repr(business_link))
if business_link.isDelivered(explanation): if business_link.isDelivered(explanation):
LOG('In isBusinessLinkBuildable', 0, 'business link is delivered and thus False')
return False return False
# We must take the closure cause only way to combine business process # We must take the closure cause only way to combine business process
closure_process = _getBusinessLinkClosure(self, explanation, business_link) closure_process = _getBusinessLinkClosure(self, explanation, business_link)
predecessor = business_link.getPredecessor() predecessor = business_link.getPredecessor()
return closure_process.isTradeStateCompleted(predecessor) return closure_process.isTradeStateCompleted(explanation, predecessor)
security.declareProtected(Permissions.AccessContentsInformation, 'isBusinessLinkPartiallyBuildable') security.declareProtected(Permissions.AccessContentsInformation, 'isBusinessLinkPartiallyBuildable')
def isBusinessLinkPartiallyBuildable(self, explanation, business_link): def isBusinessLinkPartiallyBuildable(self, explanation, business_link):
...@@ -523,8 +538,10 @@ class BusinessProcess(Path, XMLObject): ...@@ -523,8 +538,10 @@ class BusinessProcess(Path, XMLObject):
trade_state -- a Trade State category trade_state -- a Trade State category
""" """
LOG('In isTradeStateCompleted', 0, repr(trade_state))
for business_link in self.getBusinessLinkValueList(successor=trade_state): for business_link in self.getBusinessLinkValueList(successor=trade_state):
if not self.isBusinessLinkCompleted(explanation, business_link): if not self.isBusinessLinkCompleted(explanation, business_link):
LOG('A business link is not completed', 0, repr(business_link))
return False return False
return True return True
...@@ -693,6 +710,9 @@ class BusinessProcess(Path, XMLObject): ...@@ -693,6 +710,9 @@ class BusinessProcess(Path, XMLObject):
kw = self._getPropertyAndCategoryDict(explanation, amount, trade_model_path, delay_mode=delay_mode) kw = self._getPropertyAndCategoryDict(explanation, amount, trade_model_path, delay_mode=delay_mode)
kw.update(update_property_dict) kw.update(update_property_dict)
movement._edit(**kw) movement._edit(**kw)
business_link = self.getBusinessLinkValueList(trade_phase=trade_phase, context=movement)
business_link = map(lambda x: x.getRelativeUrl(), business_link)
movement._setCausalityList(business_link + movement.getCausalityList())
result.append(movement) result.append(movement)
# result can not be empty # result can not be empty
...@@ -781,6 +801,7 @@ class BusinessProcess(Path, XMLObject): ...@@ -781,6 +801,7 @@ class BusinessProcess(Path, XMLObject):
# Set causality to trade model path # Set causality to trade model path
property_dict['causality'] = trade_model_path.getRelativeUrl() # XXX-JPS Will not work if we do not use real object property_dict['causality'] = trade_model_path.getRelativeUrl() # XXX-JPS Will not work if we do not use real object
#(ie. if we use kind of 'temp')
# Set trade_phase to the trade phase of trade_model_path # Set trade_phase to the trade phase of trade_model_path
property_dict['trade_phase'] = trade_model_path.getTradePhase() property_dict['trade_phase'] = trade_model_path.getTradePhase()
...@@ -826,5 +847,6 @@ class BusinessProcess(Path, XMLObject): ...@@ -826,5 +847,6 @@ class BusinessProcess(Path, XMLObject):
""" """
Build whatever is buildable Build whatever is buildable
""" """
LOG('In business process build', 0, repr(explanation))
for business_link in self.getBuildableBusinessLinkValueList(explanation): for business_link in self.getBuildableBusinessLinkValueList(explanation):
business_link.build(explanation) business_link.build(explanation=explanation)
...@@ -586,7 +586,7 @@ class SimulationMovement(Movement, PropertyRecordableMixin, ExplainableMixin): ...@@ -586,7 +586,7 @@ class SimulationMovement(Movement, PropertyRecordableMixin, ExplainableMixin):
if business_link is None or explanation_value is None: if business_link is None or explanation_value is None:
return True return True
predecessor_state = business_path.getPredecessorValue() predecessor_state = business_link.getPredecessorValue()
if predecessor_state is None: if predecessor_state is None:
# first one, can be built # first one, can be built
return True # XXX-JPS wrong cause root is marked return True # XXX-JPS wrong cause root is marked
......
...@@ -64,8 +64,8 @@ class ExplanationCache: ...@@ -64,8 +64,8 @@ class ExplanationCache:
self.union_cache = None self.union_cache = None
def _getDeliveryMovementList(self): def _getDeliveryMovementList(self):
"""Returns self is explanation is a delivery line """Returns self if explanation is a delivery line
of the list of explanation delivery lines if explanation or the list of explanation delivery lines if explanation
is a delivery is a delivery
""" """
explanation = self.explanation explanation = self.explanation
...@@ -92,8 +92,8 @@ class ExplanationCache: ...@@ -92,8 +92,8 @@ class ExplanationCache:
for simulation_movement in movement.getDeliveryRelatedValueList(): for simulation_movement in movement.getDeliveryRelatedValueList():
result.add(simulation_movement.getExplanationUid()) # XXX-JPS use new API later result.add(simulation_movement.getExplanationUid()) # XXX-JPS use new API later
# Return result # Return result
self.explanation_uid_cache = result self.explanation_uid_cache = tuple(result)
return tuple(result) return self.explanation_uid_cache
def getSimulationPathPatternList(self): def getSimulationPathPatternList(self):
"""Return the list of root path of simulation tree which are """Return the list of root path of simulation tree which are
...@@ -119,6 +119,8 @@ class ExplanationCache: ...@@ -119,6 +119,8 @@ class ExplanationCache:
simulation_movement_id = simulation_movement.getId() simulation_movement_id = simulation_movement.getId()
insert_movement = True insert_movement = True
for path_id in container_path: for path_id in container_path:
LOG('path_dict', 0, repr(path_dict))
LOG('local_path_dict', 0, repr(local_path_dict))
local_path_dict = local_path_dict.setdefault(path_id, {}) local_path_dict = local_path_dict.setdefault(path_id, {})
if type(local_path_dict) is not types.DictType: if type(local_path_dict) is not types.DictType:
# A movement was already inserted # A movement was already inserted
...@@ -126,6 +128,7 @@ class ExplanationCache: ...@@ -126,6 +128,7 @@ class ExplanationCache:
break break
if insert_movement: if insert_movement:
local_path_dict[simulation_movement_id] = simulation_movement local_path_dict[simulation_movement_id] = simulation_movement
LOG('path_dict result', 0, repr(path_dict))
# For each delivery movement # For each delivery movement
for movement in self._getDeliveryMovementList(): for movement in self._getDeliveryMovementList():
...@@ -137,15 +140,21 @@ class ExplanationCache: ...@@ -137,15 +140,21 @@ class ExplanationCache:
# assembling path '/erp5/portal_simulation/1/34/23/43%' # assembling path '/erp5/portal_simulation/1/34/23/43%'
result = [] result = []
def browsePathDict(prefix, local_path_dict): def browsePathDict(prefix, local_path_dict):
LOG('browsePathDict result in', 0, repr(result))
LOG('browsePathDict local_path_dict in', 0, repr(local_path_dict))
for key, value in local_path_dict.items(): for key, value in local_path_dict.items():
if type(value) is not types.DictType: if type(value) is not types.DictType:
# We have a real root # We have a real root
result.append('%s/%s%' % (prefix, key)) result.append('%s/%s' % (prefix, key))
result.append('%s/%s/%%' % (prefix, key))
# XXX-JPS here we must add all parent movements XXX-JPS # XXX-JPS here we must add all parent movements XXX-JPS
else: else:
browsePathDict('%s/%s' % (prefix, key), value) # Recursing with string append is slow XXX-JPS browsePathDict('%s/%s' % (prefix, key), value) # Recursing with string append is slow XXX-JPS
LOG('browsePathDict result out', 0, repr(result))
browsePathDict('/', path_dict) # path_dict is typically like this:
# {'': {'erp5': {'portal_simulation': {'3': {'4': <SimulationMovement at /erp5/portal_simulation/3/4>}}}}}
browsePathDict('', path_dict[''])
self.explanation_path_pattern_cache = result self.explanation_path_pattern_cache = result
return result return result
...@@ -204,6 +213,7 @@ class ExplanationCache: ...@@ -204,6 +213,7 @@ class ExplanationCache:
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: if kw.get('explanation_uid', None) is None:
kw['explanation_uid'] = self.getRootExplanationUidList() kw['explanation_uid'] = self.getRootExplanationUidList()
LOG('lookup movements', 0, repr(kw))
self.simulation_movement_cache[kw_tuple] = \ self.simulation_movement_cache[kw_tuple] = \
self.portal_catalog(portal_type="Simulation Movement", self.portal_catalog(portal_type="Simulation Movement",
**kw) **kw)
...@@ -308,6 +318,7 @@ class ExplanationCache: ...@@ -308,6 +318,7 @@ class ExplanationCache:
tv = getTransactionalVariable(self) tv = getTransactionalVariable(self)
reference_date_key = (trade_phase, reference_date_method_id, delay_mode, business_process.getPhysicalPath()) reference_date_key = (trade_phase, reference_date_method_id, delay_mode, business_process.getPhysicalPath())
reference_date_key = repr(reference_date_key) reference_date_key = repr(reference_date_key)
LOG('key', 0, reference_date_key)
if tv.get(reference_date_key, _UNDEFINED) is _UNDEFINED: if tv.get(reference_date_key, _UNDEFINED) is _UNDEFINED:
tv[reference_date_key] = _INFINITE_LOOP tv[reference_date_key] = _INFINITE_LOOP
else: else:
...@@ -334,6 +345,7 @@ class ExplanationCache: ...@@ -334,6 +345,7 @@ class ExplanationCache:
# whenever trade model path define time constraints within the same # whenever trade model path define time constraints within the same
# movement generator (ie. transformation with multiple phases) # movement generator (ie. transformation with multiple phases)
path_list = business_process.getTradeModelPathValueList(trade_phase=trade_phase) path_list = business_process.getTradeModelPathValueList(trade_phase=trade_phase)
LOG('path_list', 0, '%s' % trade_phase)
if not len(path_list): if not len(path_list):
raise ValueError('No Trade Model Path defines a reference data.') raise ValueError('No Trade Model Path defines a reference data.')
......
...@@ -102,6 +102,8 @@ class MovementGeneratorMixin: ...@@ -102,6 +102,8 @@ class MovementGeneratorMixin:
result = [] result = []
folder = self._applied_rule folder = self._applied_rule
# Build a list of movement and business path # Build a list of movement and business path
LOG('_getInputMovementList', 0, repr(self._getInputMovementList(movement_list=movement_list,
rounding=rounding)))
for input_movement in self._getInputMovementList(movement_list=movement_list, for input_movement in self._getInputMovementList(movement_list=movement_list,
rounding=rounding): rounding=rounding):
# Merge movement and business path properties (core implementation) # Merge movement and business path properties (core implementation)
...@@ -109,7 +111,6 @@ class MovementGeneratorMixin: ...@@ -109,7 +111,6 @@ class MovementGeneratorMixin:
business_process = input_movement.asComposedDocument() business_process = input_movement.asComposedDocument()
explanation = self._applied_rule # We use applied rule as local explanation explanation = self._applied_rule # We use applied rule as local explanation
trade_phase = self._getTradePhaseList(input_movement, business_process) # XXX-JPS not convenient to handle trade_phase = self._getTradePhaseList(input_movement, business_process) # XXX-JPS not convenient to handle
# XXX-JPS trade phase of movement should be provided by movement
update_property_dict = self._getUpdatePropertyDict(input_movement) update_property_dict = self._getUpdatePropertyDict(input_movement)
result.extend(business_process.getTradePhaseMovementList(explanation, input_movement, result.extend(business_process.getTradePhaseMovementList(explanation, input_movement,
trade_phase=trade_phase, delay_mode=None, trade_phase=trade_phase, delay_mode=None,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment