Commit e666cb6f authored by Sebastien Robin's avatar Sebastien Robin

* update getRemainingTradePhaseList API, trade_phase_list parameter

  is removed because it is not used, and anyway the name of this
  parameter is not good
* review code of getRemainingTradePhaseList in order to match API,
  we do not take into account an "explanation" argument any more
* update unit tests in order to test what the API describe. Also
  simplify unit test

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@44376 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 3f4134ff
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5.Document.Path import Path from Products.ERP5.Document.Path import Path
from Products.ERP5.ExplanationCache import _getExplanationCache, _getBusinessLinkClosure from Products.ERP5.ExplanationCache import _getExplanationCache, _getBusinessLinkClosure
...@@ -594,8 +595,9 @@ class BusinessProcess(Path, XMLObject): ...@@ -594,8 +595,9 @@ class BusinessProcess(Path, XMLObject):
return False return False
return True return True
security.declareProtected(Permissions.AccessContentsInformation, 'getRemainingTradePhaseList') security.declareProtected(Permissions.AccessContentsInformation,
def getRemainingTradePhaseList(self, explanation, business_link, trade_phase_list=None): 'getRemainingTradePhaseList')
def getRemainingTradePhaseList(self, business_link):
"""Returns the list of remaining trade phases which to be achieved """Returns the list of remaining trade phases which to be achieved
as part of a business process. This list is calculated by analysing as part of a business process. This list is calculated by analysing
the graph of business link and trade states, starting from a given the graph of business link and trade states, starting from a given
...@@ -608,11 +610,6 @@ class BusinessProcess(Path, XMLObject): ...@@ -608,11 +610,6 @@ class BusinessProcess(Path, XMLObject):
business_link -- a Business Link document business_link -- a Business Link document
trade_phase_list -- if provided, the result is filtered by it after
being collected - XXX-JPS - is this really useful ?
NOTE: this code has not been reviewed and needs review
NOTE: explanation is not involved here because we consider here that NOTE: explanation is not involved here because we consider here that
self is the result of asUnionBusinessProcess and thus only contains self is the result of asUnionBusinessProcess and thus only contains
applicable Business Link to a given simulation subtree. Since the list applicable Business Link to a given simulation subtree. Since the list
...@@ -622,25 +619,39 @@ class BusinessProcess(Path, XMLObject): ...@@ -622,25 +619,39 @@ class BusinessProcess(Path, XMLObject):
""" """
remaining_trade_phase_list = [] remaining_trade_phase_list = []
trade_state = business_link.getSuccessor() trade_state = business_link.getSuccessor()
for link in [x for x in self.objectValues(portal_type="Business Link") \ tv = getTransactionalVariable(self)
if x.getPredecessor() == trade_state]: # We might need a key which depends on the explanation
# XXX When no simulations related to link, what should link.isCompleted return? key = 'BusinessProcess_predecessor_successor_%s' % self.getRelativeUrl()
# if True we don't have way to add remaining trade phases to new movement predecessor_successor_dict = tv.get(key, None)
if not (link.getRelatedSimulationMovementValueList(explanation) and if predecessor_successor_dict is None:
link.isCompleted(explanation)): predecessor_successor_dict = {'predecessor':{},
remaining_trade_phase_list += link.getTradePhaseValueList() 'successor':{}}
for business_link in self.objectValues(portal_type="Business Link"):
for property_name in ('predecessor', 'successor'):
property_value = business_link.getProperty(property_name)
if property_value:
business_link_list = predecessor_successor_dict[property_name].\
setdefault(property_value, [])
business_link_list.append(business_link)
tv[key] = predecessor_successor_dict
business_link_list = predecessor_successor_dict['predecessor'].\
get(trade_state, [])
assert len(business_link_list) <= 1, \
"code is not able yet to manage this case"
for link in business_link_list:
remaining_trade_phase_list += link.getTradePhaseValueList()
# collect to successor direction recursively # collect to successor direction recursively
state = link.getSuccessorValue() state = link.getSuccessor()
if state is not None: if state is not None:
next_business_link_list = predecessor_successor_dict['successor'].\
get(state, [])
assert len(next_business_link_list) == 1, \
"code is not able yet to manage this case"
remaining_trade_phase_list.extend( remaining_trade_phase_list.extend(
self.getRemainingTradePhaseList(explanation, state, None)) self.getRemainingTradePhaseList(
next_business_link_list[0]))
# filter just at once if given
if trade_phase_list is not None:
remaining_trade_phase_list = filter(
lambda x : x.getLogicalPath() in trade_phase_list,
remaining_trade_phase_list)
return remaining_trade_phase_list return remaining_trade_phase_list
......
...@@ -356,7 +356,7 @@ class ITradePhaseProcess(Interface): ...@@ -356,7 +356,7 @@ class ITradePhaseProcess(Interface):
trade_phase -- a Trade Phase category trade_phase -- a Trade Phase category
""" """
def getRemainingTradePhaseList(business_link, trade_phase_list=None): def getRemainingTradePhaseList(business_link):
"""Returns the list of remaining trade phases which to be achieved """Returns the list of remaining trade phases which to be achieved
as part of a business process. This list is calculated by analysing as part of a business process. This list is calculated by analysing
the graph of business link and trade states, starting from a given the graph of business link and trade states, starting from a given
...@@ -366,9 +366,6 @@ class ITradePhaseProcess(Interface): ...@@ -366,9 +366,6 @@ class ITradePhaseProcess(Interface):
business_link -- a Business Link document business_link -- a Business Link document
trade_phase_list -- if provided, the result is filtered by it after
being collected - ???? useful ? XXX-JPS ?
NOTE: explanation is not involved here because we consider here that NOTE: explanation is not involved here because we consider here that
self is the result of asUnionBusinessProcess and thus only contains self is the result of asUnionBusinessProcess and thus only contains
applicable Business Link to a given simulation subtree. Since the list applicable Business Link to a given simulation subtree. Since the list
...@@ -491,4 +488,4 @@ class IBusinessProcess(ITradeModelPathProcess, IBusinessLinkProcess, IBuildableB ...@@ -491,4 +488,4 @@ class IBusinessProcess(ITradeModelPathProcess, IBusinessLinkProcess, IBuildableB
include_partially_buildable -- if set to True, also build partially include_partially_buildable -- if set to True, also build partially
buildable business link. Else buildable business link. Else
only build strictly buildable link. only build strictly buildable link.
""" """
\ No newline at end of file
...@@ -302,129 +302,42 @@ class TestBPMImplementation(TestBPMMixin): ...@@ -302,129 +302,42 @@ class TestBPMImplementation(TestBPMMixin):
self.assertEquals('something', self.assertEquals('something',
business_path.getSource(context=context_movement, default='something')) business_path.getSource(context=context_movement, default='something'))
@newSimulationExpectedFailure
def test_BusinessState_getRemainingTradePhaseList(self): def test_BusinessState_getRemainingTradePhaseList(self):
""" """
This test case is described for what trade_phase is remaining after the state. This test case is described for what trade_phase is remaining after the
In this case, root explanation is path of between "b" and "d", and given business link.
path of between "a" and "b" has a condition which simulation state of
explanation must be "ordered" to pass the path. (*1)
But this test case will be passed the condition.
(root explanation)
default/discount default/invoicing default/accounting
a ------------------ b ------------------- d -------------------- e
(cond="ordered") \ /
\ /
default/delivery \ / default/payment
\ /
\ /
\ /
\ /
\ /
\ /
\ /
c
""" """
# define business process # define business process
category_tool = self.getCategoryTool() category_tool = self.getCategoryTool()
business_process = self.createBusinessProcess() business_process = self.createBusinessProcess()
business_link_a_b = self.createBusinessLink(business_process) business_link_order = self.createBusinessLink(business_process,
business_link_b_c = self.createBusinessLink(business_process) title='order', id='order',
business_link_b_d = self.createBusinessLink(business_process) trade_phase='default/order')
business_link_c_d = self.createBusinessLink(business_process) business_link_deliver = self.createBusinessLink(business_process,
business_link_d_e = self.createBusinessLink(business_process) title='deliver', id='deliver',
business_state_a = category_tool.trade_state.state_a trade_phase='default/delivery')
business_state_b = category_tool.trade_state.state_b business_link_invoice = self.createBusinessLink(business_process,
business_state_c = category_tool.trade_state.state_c title='invoice', id='invoice',
business_state_d = category_tool.trade_state.state_d trade_phase='default/invoicing')
business_state_e = category_tool.trade_state.state_e trade_state = category_tool.trade_state
business_link_a_b.setPredecessorValue(business_state_a) business_link_order.setSuccessorValue(trade_state.ordered)
business_link_b_c.setPredecessorValue(business_state_b) business_link_deliver.setPredecessorValue(trade_state.ordered)
business_link_b_d.setPredecessorValue(business_state_b) business_link_deliver.setSuccessorValue(trade_state.delivered)
business_link_c_d.setPredecessorValue(business_state_c) business_link_invoice.setPredecessorValue(trade_state.delivered)
business_link_d_e.setPredecessorValue(business_state_d) business_link_invoice.setSuccessorValue(trade_state.invoiced)
business_link_a_b.setSuccessorValue(business_state_b)
business_link_b_c.setSuccessorValue(business_state_c) trade_phase = category_tool.trade_phase.default
business_link_b_d.setSuccessorValue(business_state_d)
business_link_c_d.setSuccessorValue(business_state_d) self.assertEquals([trade_phase.delivery,
business_link_d_e.setSuccessorValue(business_state_e) trade_phase.invoicing],
business_process.getRemainingTradePhaseList(
# set title for debug business_process.order))
business_link_a_b.edit(title="a_b") self.assertEquals([trade_phase.invoicing],
business_link_b_c.edit(title="b_c") business_process.getRemainingTradePhaseList(
business_link_b_d.edit(title="b_d") business_process.deliver))
business_link_c_d.edit(title="c_d") self.assertEquals([],
business_link_d_e.edit(title="d_e") business_process.getRemainingTradePhaseList(
business_process.invoice))
# set trade_phase
business_link_a_b.edit(trade_phase=['default/discount'],
completed_state=['ordered']) # (*1)
business_link_b_c.edit(trade_phase=['default/delivery'])
business_link_b_d.edit(trade_phase=['default/invoicing'])
business_link_c_d.edit(trade_phase=['default/payment'])
business_link_d_e.edit(trade_phase=['default/accounting'])
# mock order
order = self.portal.sale_order_module.newContent(portal_type="Sale Order")
order_line = order.newContent(portal_type="Sale Order Line", quantity=1)
# make simulation
order.order()
self.stepTic()
applied_rule = order.getCausalityRelatedValue()
sm = applied_rule.contentValues(portal_type="Simulation Movement")[0]
sm.edit(causality_value=business_link_a_b)
# make other movements for each business path
applied_rule.newContent(portal_type="Simulation Movement",
causality_value=business_link_b_c,
order_value=order_line)
applied_rule.newContent(portal_type="Simulation Movement",
causality_value=business_link_b_d,
order_value=order_line)
applied_rule.newContent(portal_type="Simulation Movement",
causality_value=business_link_c_d,
order_value=order_line)
applied_rule.newContent(portal_type="Simulation Movement",
causality_value=business_link_d_e,
order_value=order_line)
self.stepTic()
trade_phase = self.portal.portal_categories.trade_phase.default
# assertion which getRemainingTradePhaseList must return category which will be passed
# discount is passed, business_link_a_b is already completed, because simulation state is "ordered"
self.assertEquals(set([trade_phase.delivery,
trade_phase.invoicing,
trade_phase.payment,
trade_phase.accounting]),
set(business_process.getRemainingTradePhaseList(order,
business_state_a)))
self.assertEquals(set([trade_phase.delivery,
trade_phase.invoicing,
trade_phase.payment,
trade_phase.accounting]),
set(business_process.getRemainingTradePhaseList(order,
business_state_b)))
self.assertEquals(set([trade_phase.payment,
trade_phase.accounting]),
set(business_process.getRemainingTradePhaseList(order,
business_state_c)))
self.assertEquals(set([trade_phase.accounting]),
set(business_process.getRemainingTradePhaseList(order,
business_state_d)))
# when trade_phase_list is defined in arguments, the result is filtered by base category.
self.assertEquals(set([trade_phase.delivery,
trade_phase.accounting]),
set(business_process\
.getRemainingTradePhaseList(order, business_state_a,
trade_phase_list=['default/delivery',
'default/accounting'])))
@newSimulationExpectedFailure @newSimulationExpectedFailure
def test_BusinessLink_calculateExpectedDate(self): def test_BusinessLink_calculateExpectedDate(self):
......
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