diff --git a/product/ERP5/Document/BusinessPath.py b/product/ERP5/Document/BusinessPath.py
index 39b6f9e5bb5cfbe3dab91cffbbe241a849fbc816..94aea11dc3679cefe457eeb6e99ebdf6a81962d6 100644
--- a/product/ERP5/Document/BusinessPath.py
+++ b/product/ERP5/Document/BusinessPath.py
@@ -251,7 +251,7 @@ class BusinessPath(Path, Predicate):
     #
     # Such cases are Business Processes using sequence not related
     # to simulation tree with much of compensations
-    if predecessor.isPartiallyCompleted(explanation):
+    if self.isStatePartiallyCompleted(explanation, predecessor):
       return result
     return False
 
@@ -437,14 +437,16 @@ class BusinessPath(Path, Predicate):
     if predecessor_date is None:
       node = self.getPredecessorValue()
       if node is not None:
-        predecessor_date = node.getExpectedCompletionDate(explanation, *args, **kwargs)
+        predecessor_date = self.getParentValue().getExpectedStateCompletionDate(
+          explanation, node, *args, **kwargs)
     if predecessor_date is not None:
       return predecessor_date + self.getWaitTime()
 
   def _getSuccessorExpectedStartDate(self, explanation, *args, **kwargs):
     node = self.getSuccessorValue()
     if node is not None:
-      expected_date =  node.getExpectedBeginningDate(explanation, *args, **kwargs)
+      expected_date =  self.getParentValue().getExpectedStateBeginningDate(
+        explanation, node, *args, **kwargs)
       if expected_date is not None:
         return expected_date - self.getLeadTime()
 
@@ -474,14 +476,16 @@ class BusinessPath(Path, Predicate):
   def _getPredecessorExpectedStopDate(self, explanation, *args, **kwargs):
     node = self.getPredecessorValue()
     if node is not None:
-      expected_date = node.getExpectedCompletionDate(explanation, *args, **kwargs)
+      expected_date = self.getParentValue().getExpectedStateCompletionDate(
+         explanation, node, *args, **kwargs)
       if expected_date is not None:
         return expected_date + self.getWaitTime() + self.getLeadTime()
 
   def _getSuccessorExpectedStopDate(self, explanation, *args, **kwargs):
     node = self.getSuccessorValue()
     if node is not None:
-      return node.getExpectedBeginningDate(explanation, *args, **kwargs)
+      return self.getParentValue().getExpectedStateBeginningDate(
+         explanation, node, *args, **kwargs)
 
   def _getExpectedDate(self, explanation, root_explanation_method,
                        predecessor_method, successor_method,
diff --git a/product/ERP5/Document/BusinessProcess.py b/product/ERP5/Document/BusinessProcess.py
index 38fc571c9558da6b8824d17109b74caa9094d871..e3ad02b798b40d0dc0f71674cd1c86bdf622d4f9 100644
--- a/product/ERP5/Document/BusinessProcess.py
+++ b/product/ERP5/Document/BusinessProcess.py
@@ -256,3 +256,121 @@ class BusinessProcess(Path, XMLObject):
     for next_path in node.getPredecessorRelatedValueList():
       _list += self._getHeadPathValueList(next_path, trade_phase_set)
     return _list
+
+  def getRemainingTradePhaseList(self, explanation, trade_state, trade_phase_list=None):
+    """
+      Returns the list of remaining trade phase for this
+      state based on the explanation.
+
+      trade_phase_list -- if provide, the result is filtered by it after collected
+    """
+    remaining_trade_phase_list = []
+    for path in [x for x in self.objectValues(portal_type="Business Path") \
+        if x.getPredecessorValue() == trade_state]:
+      # XXX When no simulations related to path, what should path.isCompleted return?
+      #     if True we don't have way to add remaining trade phases to new movement
+      if not (path.getRelatedSimulationMovementValueList(explanation) and
+              path.isCompleted(explanation)):
+        remaining_trade_phase_list += path.getTradePhaseValueList()
+
+      # collect to successor direction recursively
+      state = path.getSuccessorValue()
+      if state is not None:
+        remaining_trade_phase_list.extend(
+          self.getRemainingTradePhaseList(explanation, state, None))
+
+    # 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
+
+  def isStatePartiallyCompleted(self, explanation, trade_state):
+    """
+      If all path which reach this state are partially completed
+      then this state is completed
+    """
+    for path in [x for x in self.objectValues(portal_type="Business Path") \
+        if x.getSuccessorValue() == trade_state]:
+      if not path.isPartiallyCompleted(explanation):
+        return False
+    return True
+
+  def getExpectedStateCompletionDate(self, explanation, trade_state, *args, **kwargs):
+    """
+      Returns the expected completion date for this
+      state based on the explanation.
+
+      explanation -- the document
+    """
+    # Should be re-calculated?
+    # XXX : what is the purpose of the two following lines ? comment it until there is
+    # good answer
+    if 'predecessor_date' in kwargs:
+      del kwargs['predecessor_date']
+    successor_list = [x for x in self.objectValues(portal_type="Business Path") \
+        if x.getSuccessorValue() == trade_state]
+    date_list = self._getExpectedDateList(explanation,
+                                          successor_list,
+                                          self._getExpectedCompletionDate,
+                                          *args,
+                                          **kwargs)
+    if len(date_list) > 0:
+      return min(date_list)
+
+  def getExpectedStateBeginningDate(self, explanation, trade_state, *args, **kwargs):
+    """
+      Returns the expected beginning date for this
+      state based on the explanation.
+
+      explanation -- the document
+    """
+    # Should be re-calculated?
+    # XXX : what is the purpose of the two following lines ? comment it until there is
+    # good answer
+    if 'predecessor_date' in kwargs:
+      del kwargs['predecessor_date']
+    predecessor_list = [x for x in self.objectValues(portal_type="Business Path") \
+        if x.getPredecessorValue() == trade_state]
+    date_list = self._getExpectedDateList(explanation,
+                                          predecessor_list,
+                                          self._getExpectedBeginningDate,
+                                          *args,
+                                          **kwargs)
+    if len(date_list) > 0:
+      return min(date_list)
+
+  def _getExpectedBeginningDate(self, path, *args, **kwargs):
+    expected_date = path.getExpectedStartDate(*args, **kwargs)
+    if expected_date is not None:
+      return expected_date - path.getWaitTime()
+
+  def _getExpectedDateList(self, explanation, path_list, path_method,
+                           visited=None, *args, **kwargs):
+    """
+      getExpected(Beginning/Completion)Date are same structure
+      expected date of each path should be returned.
+
+      explanation -- the document
+      path_list -- list of target business path
+      path_method -- used to get expected date on each path
+      visited -- only used to prevent infinite recursion internally
+    """
+    if visited is None:
+      visited = []
+
+    expected_date_list = []
+    for path in path_list:
+      # filter paths without path of root explanation
+      if path not in visited or path.isDeliverable():
+        expected_date = path_method(path, explanation, visited=visited, *args, **kwargs)
+        if expected_date is not None:
+          expected_date_list.append(expected_date)
+
+    return expected_date_list
+
+  def _getExpectedCompletionDate(self, path, *args, **kwargs):
+    return path.getExpectedStopDate(*args, **kwargs)
+
diff --git a/product/ERP5/tests/testBPMCore.py b/product/ERP5/tests/testBPMCore.py
index d828a3b819d9fc54a3506f15589705ed926931c9..b554a8d0360e30b344856ff39bdffc8215a4a833 100644
--- a/product/ERP5/tests/testBPMCore.py
+++ b/product/ERP5/tests/testBPMCore.py
@@ -68,6 +68,9 @@ class TestBPMMixin(ERP5TypeTestCase):
     self.createCategoriesInCategory(category_tool.trade_phase, ['default',])
     self.createCategoriesInCategory(category_tool.trade_phase.default,
         ['accounting', 'delivery', 'invoicing', 'discount', 'tax', 'payment'])
+    self.createCategoriesInCategory(category_tool.trade_state,
+        ['ordered', 'invoiced', 'delivered',
+         'state_a', 'state_b', 'state_c', 'state_d', 'state_e'])
 
   @reindex
   def createBusinessProcess(self, **kw):
@@ -88,14 +91,6 @@ class TestBPMMixin(ERP5TypeTestCase):
       portal_type=self.business_path_portal_type, **kw)
     return business_path
 
-  @reindex
-  def createBusinessState(self, business_process=None, **kw):
-    if business_process is None:
-      business_process = self.createBusinessProcess()
-    business_path = business_process.newContent(
-        portal_type=self.business_state_portal_type, **kw)
-    return business_path
-
   def createMovement(self):
     # returns a movement for testing
     applied_rule = self.portal.portal_simulation.newContent(
@@ -348,17 +343,18 @@ class TestBPMImplementation(TestBPMMixin):
                                     c
     """
     # define business process
+    category_tool = self.getCategoryTool()
     business_process = self.createBusinessProcess()
     business_path_a_b = self.createBusinessPath(business_process)
     business_path_b_c = self.createBusinessPath(business_process)
     business_path_b_d = self.createBusinessPath(business_process)
     business_path_c_d = self.createBusinessPath(business_process)
     business_path_d_e = self.createBusinessPath(business_process)
-    business_state_a = self.createBusinessState(business_process)
-    business_state_b = self.createBusinessState(business_process)
-    business_state_c = self.createBusinessState(business_process)
-    business_state_d = self.createBusinessState(business_process)
-    business_state_e = self.createBusinessState(business_process)
+    business_state_a = category_tool.trade_state.state_a
+    business_state_b = category_tool.trade_state.state_b
+    business_state_c = category_tool.trade_state.state_c
+    business_state_d = category_tool.trade_state.state_d
+    business_state_e = category_tool.trade_state.state_e
     business_path_a_b.setPredecessorValue(business_state_a)
     business_path_b_c.setPredecessorValue(business_state_b)
     business_path_b_d.setPredecessorValue(business_state_b)
@@ -376,11 +372,6 @@ class TestBPMImplementation(TestBPMMixin):
     business_path_b_d.edit(title="b_d")
     business_path_c_d.edit(title="c_d")
     business_path_d_e.edit(title="d_e")
-    business_state_a.edit(title="a")
-    business_state_b.edit(title="b")
-    business_state_c.edit(title="c")
-    business_state_d.edit(title="d")
-    business_state_e.edit(title="e")
     
     # set trade_phase
     business_path_a_b.edit(trade_phase=['default/discount'],
@@ -427,23 +418,27 @@ class TestBPMImplementation(TestBPMMixin):
                            trade_phase.invoicing,
                            trade_phase.payment,
                            trade_phase.accounting]),
-                      set(business_state_a.getRemainingTradePhaseList(order)))
+                      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_state_b.getRemainingTradePhaseList(order)))
+                      set(business_process.getRemainingTradePhaseList(order,
+                          business_state_b)))
     self.assertEquals(set([trade_phase.payment,
                            trade_phase.accounting]),
-                      set(business_state_c.getRemainingTradePhaseList(order)))
+                      set(business_process.getRemainingTradePhaseList(order,
+                          business_state_c)))
     self.assertEquals(set([trade_phase.accounting]),
-                      set(business_state_d.getRemainingTradePhaseList(order)))
+                      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_state_a\
-                          .getRemainingTradePhaseList(order,
+                      set(business_process\
+                          .getRemainingTradePhaseList(order, business_state_a,
                                                       trade_phase_list=['default/delivery',
                                                                         'default/accounting'])))
 
@@ -473,17 +468,18 @@ class TestBPMImplementation(TestBPMMixin):
                            c
     """
     # define business process
+    category_tool = self.getCategoryTool()
     business_process = self.createBusinessProcess()
     business_path_a_b = self.createBusinessPath(business_process)
     business_path_b_c = self.createBusinessPath(business_process)
     business_path_b_d = self.createBusinessPath(business_process)
     business_path_c_d = self.createBusinessPath(business_process)
     business_path_d_e = self.createBusinessPath(business_process)
-    business_state_a = self.createBusinessState(business_process)
-    business_state_b = self.createBusinessState(business_process)
-    business_state_c = self.createBusinessState(business_process)
-    business_state_d = self.createBusinessState(business_process)
-    business_state_e = self.createBusinessState(business_process)
+    business_state_a = category_tool.trade_state.state_a
+    business_state_b = category_tool.trade_state.state_b
+    business_state_c = category_tool.trade_state.state_c
+    business_state_d = category_tool.trade_state.state_d
+    business_state_e = category_tool.trade_state.state_e
     business_path_a_b.setPredecessorValue(business_state_a)
     business_path_b_c.setPredecessorValue(business_state_b)
     business_path_b_d.setPredecessorValue(business_state_b)
@@ -496,11 +492,6 @@ class TestBPMImplementation(TestBPMMixin):
     business_path_d_e.setSuccessorValue(business_state_e)
 
     business_process.edit(referential_date='stop_date')
-    business_state_a.edit(title='a')
-    business_state_b.edit(title='b')
-    business_state_c.edit(title='c')
-    business_state_d.edit(title='d')
-    business_state_e.edit(title='e')
     business_path_a_b.edit(title='a_b', lead_time=2, wait_time=1)
     business_path_b_c.edit(title='b_c', lead_time=2, wait_time=1)
     business_path_b_d.edit(title='b_d', lead_time=3, wait_time=1)
@@ -635,9 +626,10 @@ class TestBPMDummyDeliveryMovementMixin(TestBPMMixin):
   def _createOrderedDeliveredInvoicedBusinessProcess(self):
     # simple business process preparation
     business_process = self.createBusinessProcess()
-    ordered = self.createBusinessState(business_process)
-    delivered = self.createBusinessState(business_process)
-    invoiced = self.createBusinessState(business_process)
+    category_tool = self.getCategoryTool()
+    ordered = category_tool.trade_state.ordered
+    delivered = category_tool.trade_state.delivered
+    invoiced = category_tool.trade_state.invoiced
 
     # path which is completed, as soon as related simulation movements are in
     # proper state
@@ -660,9 +652,10 @@ class TestBPMDummyDeliveryMovementMixin(TestBPMMixin):
 
   def _createOrderedInvoicedDeliveredBusinessProcess(self):
     business_process = self.createBusinessProcess()
-    ordered = self.createBusinessState(business_process)
-    delivered = self.createBusinessState(business_process)
-    invoiced = self.createBusinessState(business_process)
+    category_tool = self.getCategoryTool()
+    ordered = category_tool.trade_state.ordered
+    delivered = category_tool.trade_state.delivered
+    invoiced = category_tool.trade_state.invoiced
 
     self.order_path = self.createBusinessPath(business_process,
         successor_value = ordered,