diff --git a/product/ERP5/mixin/movement_generator.py b/product/ERP5/mixin/movement_generator.py
deleted file mode 100644
index b15a9edeffa39ccd33ed350cef8100b8dece99e0..0000000000000000000000000000000000000000
--- a/product/ERP5/mixin/movement_generator.py
+++ /dev/null
@@ -1,201 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsibility 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
-# guarantees 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-##############################################################################
-
-from Products.ERP5.MovementCollectionDiff import _getPropertyAndCategoryList
-
-class MovementGeneratorMixin:
-  """
-  This class provides a generic implementation of IMovementGenerator.
-  It is used by rules to generate a collection of movements from
-  the context of an applied rule.
-
-  TODO:
-    Deliveries ? Movements ? Items ?
-    Does it depend by default on IAmountGeneratorMixin
-  """
-  # Default values
-  _applied_rule = None
-  _rule = None
-  _trade_phase_list = None
-
-  def __init__(self, applied_rule=None, rule=None, trade_phase_list=None):
-    self._trade_phase_list = trade_phase_list # XXX
-    self._applied_rule = applied_rule
-    if rule is None and applied_rule is not None:
-      self._rule = applied_rule.getSpecialiseValue()
-    else:
-      self._rule = rule # for rule specific stuff
-
-  # Implementation of IMovementGenerator
-  def getGeneratedMovementList(self, movement_list=None, rounding=False):
-    """
-    Returns an IMovementList generated by a model applied to the context
-
-    context - an IMovementCollection, an IMovementList or an IMovement
-
-    movement_list - optional IMovementList which can be passed explicitely
-                    whenever context is an IMovementCollection and whenever
-                    we want to filter context.getMovementList
-
-    rounding - boolean argument, which controls if rounding shall be applied on
-               generated movements or not
-
-    NOTE:
-      - implement rounding appropriately (True or False seems
-        simplistic)
-    """
-    # Default implementation bellow can be overriden by subclasses
-    # however it should be generic enough not to be overriden
-    # by most classes
-    # Results will be appended to result, objects created inside folder
-    from Products.ERP5Type.Document import newTempMovement
-    result = []
-    if self._applied_rule is None:
-      folder = self # Really useful ?
-    else:
-      folder = self._applied_rule
-    # Build a list of movement and business path
-    id_index = 0
-    for input_movement, business_path in self \
-            ._getInputMovementAndPathTupleList(movement_list=movement_list, 
-                                               rounding=rounding):
-      # Merge movement and business path properties (core implementation)
-      kw = self._getPropertyAndCategoryDict(input_movement, business_path)
-      # Update movement properties (class overridable)
-      kw.update(self._getUpdatePropertyDict(input_movement))
-      # And build temp movement of appropriate type
-      simulation_movement = newTempMovement(folder,
-                                          'generated_movement_%s' % id_index)
-      simulation_movement._edit(**kw)
-      result.append(simulation_movement)
-      id_index += 1
-    return result
-
-  def _getUpdatePropertyDict(self, input_movement):
-    # Default implementation bellow can be overriden by subclasses
-    return {'delivery': input_movement.getRelativeUrl(), # XXX-JPS empty is better
-            }
-
-  def _getTradePhaseList(self, input_movement, business_process):
-    if self._trade_phase_list:
-      return self._trade_phase_list
-    if self._rule:
-      self._rule.getTradePhaseList()
-    return business_process.getTradePhaseList()
-
-  def _getInputMovementAndPathTupleList(self, movement_list=None, rounding=None):
-    """
-    Returns list of tuples (movement, business_path)
-    """
-    # Init result
-    result = []
-    # First generate a list of movements with any appropriate method
-    input_movement_list = self._getInputMovementList(movement_list=movement_list, rounding=rounding)
-    # For each input movement
-    for input_movement in input_movement_list:
-      # Find its business process, if any
-      business_process = input_movement.asComposedDocument() # This produces a business process ideally      
-      # Initialise trade phase list for a movement and business process
-      trade_phase_list = self._getTradePhaseList(input_movement, business_process)
-
-      if business_process is None or len(trade_phase_list) == 0:
-        result.append((input_movement, None))
-      else:
-        for business_path in business_process.getPathValueList(
-                          trade_phase_list,
-                          input_movement) or [None]:
-          result.append((input_movement, business_path))
-
-    return result
-
-  def _getInputMovementList(self, movement_list=None, rounding=None):
-    raise NotImplementedError
-    # Default implementation takes amounts ?
-    # Use TradeModelRuleMovementGenerator._getInputMovementList as default implementation
-    # and potentially use trade phase for that.... as a way to filter out
-
-  def _getPropertyAndCategoryDict(self, movement, business_path):
-    """
-    Merge a movement and a business_path and return a dict of
-    properties and categories whch can be used to create a new movement.
-
-    movement -- an IMovement instance
- 
-    business_path -- an IBusinessPath instance
-
-    rule -- optional rule parameter which can be used to 
-            narrow down properties to be copied
-    """
-    rule = self._rule
-    if rule is None:
-      property_dict = _getPropertyAndCategoryList(movement)
-    else:
-      property_dict = {}
-      for tester in rule._getUpdatingTesterList(exclude_quantity=False):
-        property_dict.update(tester.getUpdatablePropertyDict(
-          movement, None))
-
-    if business_path is None:
-      return property_dict
-
-    # Arrow
-    for base_category, category_url_list in \
-            business_path.getArrowCategoryDict(context=movement).iteritems():
-      property_dict[base_category] = category_url_list
-
-    # Amount
-    if business_path.getQuantity():
-      property_dict['quantity'] = business_path.getQuantity()
-    elif business_path.getEfficiency():
-      property_dict['quantity'] = movement.getQuantity() *\
-        business_path.getEfficiency()
-    else:
-      property_dict['quantity'] = movement.getQuantity()
-
-    movement_start_date = movement.getStartDate()
-    movement_stop_date = movement.getStopDate()
-    if movement_start_date == movement_stop_date:
-      property_dict['start_date'] = business_path.getExpectedStartDate(
-          movement)
-      property_dict['stop_date'] = business_path.getExpectedStopDate(movement)
-      # in case of not fully working BPM get dates from movement
-      # XXX: as soon as BPM will be fully operational this hack will not be
-      #      needed anymore
-      if property_dict['start_date'] is None:
-        property_dict['start_date'] = movement_start_date
-      if property_dict['stop_date'] is None:
-        property_dict['stop_date'] = movement_stop_date
-    else: # XXX shall not be used, but business_path.getExpectedStart/StopDate
-          # do not works on second path...
-      property_dict['start_date'] = movement_start_date
-      property_dict['stop_date'] = movement_stop_date
-
-    # save a relation to business path
-    property_dict['causality'] = [business_path.getRelativeUrl()]
-
-    return property_dict
diff --git a/product/ERP5/mixin/rule.py b/product/ERP5/mixin/rule.py
index 0363db9bca3568138e06bde81c788ed83abc094c..7634f118c2a382aec1cd3cc43b9570e01b5be64f 100644
--- a/product/ERP5/mixin/rule.py
+++ b/product/ERP5/mixin/rule.py
@@ -32,6 +32,9 @@ from Acquisition import aq_base
 from Products.CMFCore.utils import getToolByName
 from Products.ERP5Type import Permissions, interfaces
 from Products.ERP5.Document.Predicate import Predicate
+from Products.ERP5.MovementCollectionDiff import _getPropertyAndCategoryList
+
+from zLOG import LOG
 
 def _compare(tester_list, prevision_movement, decision_movement):
   for tester in tester_list:
@@ -39,6 +42,97 @@ def _compare(tester_list, prevision_movement, decision_movement):
       return False
   return True
 
+class MovementGeneratorMixin:
+  """
+  This class provides a generic implementation of IMovementGenerator
+  which can be used together the Rule mixin class bellow. It does not
+  have any pretention to provide more than that.
+  """
+  # Default values
+  _applied_rule = None
+  _rule = None
+  _trade_phase_list = None
+  _explanation = None
+
+  def __init__(self, applied_rule, explanation=None, rule=None, trade_phase_list=None):
+    self._trade_phase_list = trade_phase_list # XXX-JPS Why a list ?
+    self._applied_rule = applied_rule
+    if rule is None and applied_rule is not None:
+      self._rule = applied_rule.getSpecialiseValue()
+    else:
+      self._rule = rule # for rule specific stuff
+    if explanation is None:
+      self._explanation = applied_rule.getRootExplanationValue()
+    else:
+      self._explanation = explanation
+    # XXX-JPS handle delay_mode
+
+  # Implementation of IMovementGenerator
+  def getGeneratedMovementList(self, movement_list=None, rounding=False):
+    """
+    Returns an IMovementList generated by a model applied to the context
+
+    context - an IMovementCollection, an IMovementList or an IMovement
+
+    movement_list - optional IMovementList which can be passed explicitely
+                    whenever context is an IMovementCollection and whenever
+                    we want to filter context.getMovementList
+
+    rounding - boolean argument, which controls if rounding shall be applied on
+               generated movements or not
+
+    NOTE:
+      - implement rounding appropriately (True or False seems
+        simplistic)
+    """
+    # Default implementation bellow can be overriden by subclasses
+    # however it should be generic enough not to be overriden
+    # by most classes
+    # Results will be appended to result, objects created inside folder
+    from Products.ERP5Type.Document import newTempMovement
+    result = []
+    folder = self._applied_rule
+    # Build a list of movement and business path
+    for input_amount in self._getInputAmountList(movement_list=movement_list, 
+                                                   rounding=rounding):
+      # Merge movement and business path properties (core implementation)
+      LOG('getGeneratedMovementList input_movement', 0, repr(input_movement))
+      # Lookup Business Process through composition (NOT UNION)
+      business_process = input_movement.asComposedDocument()
+      explanation = self._explanation
+      LOG('getGeneratedMovementList business_process', 0, repr(business_process))
+      trade_phase = self._getTradePhaseList(input_movement, business_process) # XXX-JPS not convenient to handle
+      result.extend(business_process.getTradePhaseMovementList(explanation, input_amount, 
+                                                 trade_phase=trade_phase, delay_mode=None))
+
+    # Extend movement properties
+    for movement in result:
+      movement._edit(self._getUpdatePropertyDict(movement))
+      
+    # And return list of generated movements
+    return result
+
+  def _getUpdatePropertyDict(self, input_movement):
+    # Default implementation bellow can be overriden by subclasses
+    return {'delivery': input_movement.getRelativeUrl(), # XXX-JPS empty is better
+            }
+
+  def _getTradePhaseList(self, input_movement, business_process): # XXX-JPS WEIRD
+    LOG('_getTradePhaseList _trade_phase_list', 0, str(self._trade_phase_list))
+    if self._trade_phase_list:
+      return self._trade_phase_list
+    if self._rule:
+      LOG('_getTradePhaseList _trade_phase_list', 0, str(self._rule.getTradePhaseList()))
+      return self._rule.getTradePhaseList()
+    return business_process.getTradePhaseList()
+
+  def _getInputMovementList(self, movement_list=None, rounding=None):
+    raise NotImplementedError
+    # Default implementation takes amounts ?
+    # Use TradeModelRuleMovementGenerator._getInputMovementList as default implementation
+    # and potentially use trade phase for that.... as a way to filter out
+
+
 class RuleMixin:
   """
   Provides generic methods and helper methods to implement
@@ -161,6 +255,7 @@ class RuleMixin:
   def _getMovementGeneratorContext(self, applied_rule):
     """
     Return the movement generator context to use for expand
+    XXX-JPS likely useless
     """
     raise NotImplementedError