diff --git a/product/ERP5/mixin/builder.py b/product/ERP5/mixin/builder.py
index c70b26a052d829b6dd4195d2ccfaed09b85fa18f..99d4903c2cc277e7556151703b00887f5d373f48 100644
--- a/product/ERP5/mixin/builder.py
+++ b/product/ERP5/mixin/builder.py
@@ -167,8 +167,9 @@ class BuilderMixin(XMLObject, Amount, Predicate):
       delivery_module = getattr(self.getPortalObject(), self.getDeliveryModule())
       getattr(delivery_module, delivery_module_before_building_script_id)()
 
-  def generateMovementListForStockOptimisation(self, **kw):
+  def generateMovementListForStockOptimisation(self, group_by_node=1, **kw):
     from Products.ERP5Type.Document import newTempMovement
+    now = DateTime()
     movement_list = []
     for attribute, method in [('node_uid', 'getDestinationUid'),
                               ('section_uid', 'getDestinationSectionUid')]:
@@ -181,7 +182,7 @@ class BuilderMixin(XMLObject, Amount, Predicate):
     sql_list = self.portal_simulation.getFutureInventoryList(
                                                    group_by_variation=1,
                                                    group_by_resource=1,
-                                                   group_by_node=1,
+                                                   group_by_node=group_by_node,
                                                    group_by_section=0,
                                                    **kw)
     # min_flow and max_delay are stored on a supply line. By default
@@ -203,7 +204,7 @@ class BuilderMixin(XMLObject, Amount, Predicate):
       movement = newTempMovement(self.getPortalObject(), "temp")
       dumb_movement = inventory_item.getObject()
       resource_portal_type = resource.getPortalType()
-      assert resource_portal_type in (resource_portal_type_list), \
+      assert resource_portal_type in resource_portal_type_list, \
         "Builder %r does not support resource of type : %r" % (
         self.getRelativeUrl(), resource_portal_type)
       movement.edit(
@@ -232,17 +233,18 @@ class BuilderMixin(XMLObject, Amount, Predicate):
           stop_date = resource.getNextAlertInventoryDate(
                                reference_quantity=min_stock,
                                variation_text=inventory_item.variation_text,
-                               from_date=DateTime(),
+                               from_date=now,
+                               group_by_node=group_by_node,
                                **kw)
-          if stop_date != None:
-            movement = newMovement(inventory_item, resource)
-            max_delay = resource.getMaxDelay(0)
-            movement.edit(
-              start_date=stop_date-max_delay,
-              stop_date=stop_date,
-              quantity=max(min_flow, -inventory_item.inventory),
-            )
-            movement_list.append(movement)
+          if stop_date is None:
+            stop_date = now
+          movement = newMovement(inventory_item, resource)
+          movement.edit(
+            start_date=stop_date-max_delay,
+            stop_date=stop_date,
+            quantity=max(min_flow, -inventory_item.inventory),
+          )
+          movement_list.append(movement)
         # We could need to cancel automated stock optimization if for some reasons
         # previous optimisations are obsolete
         elif round(inventory_item.inventory, 5) > min_stock:
@@ -253,6 +255,7 @@ class BuilderMixin(XMLObject, Amount, Predicate):
                                variation_text=inventory_item.variation_text,
                                simulation_state="auto_planned",
                                sort_on=[("date", "descending")],
+                               group_by_node=group_by_node
                                )
           for optimized_inventory in optimized_inventory_list:
             movement = newMovement(inventory_item, resource)
diff --git a/product/ERP5/tests/testOrder.py b/product/ERP5/tests/testOrder.py
index fc7f5b16f0382a33dc94a3a4536f9c423188dfbd..018e70f013cc4b5768a38467dd358fbf662a8b96 100644
--- a/product/ERP5/tests/testOrder.py
+++ b/product/ERP5/tests/testOrder.py
@@ -68,7 +68,7 @@ class TestOrderMixin(SubcontentReindexingWrapper):
             'erp5_simulation', 'erp5_trade', 'erp5_apparel', 'erp5_project',
             'erp5_configurator_standard_solver',
             'erp5_configurator_standard_trade_template',
-            'erp5_simulation_test', 'erp5_administration')
+            'erp5_simulation_test', 'erp5_administration', 'erp5_dummy_movement')
 
   def setUpPreferences(self):
     #create apparel variation preferences
diff --git a/product/ERP5/tests/testOrderBuilder.py b/product/ERP5/tests/testOrderBuilder.py
index 66780709a50f5fa5dbd8e4fdde48ebf5a280c4b1..3690a9f8a7deb4cf728297644805e269e5e645b3 100644
--- a/product/ERP5/tests/testOrderBuilder.py
+++ b/product/ERP5/tests/testOrderBuilder.py
@@ -33,8 +33,10 @@ from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
 from DateTime import DateTime
 from Products.ERP5Type.tests.Sequence import SequenceList
 from Products.ERP5.tests.testOrder import TestOrderMixin
+from Products.ERP5.tests.testInventoryAPI import InventoryAPITestCase
+from Products.ERP5Type.tests.utils import createZODBPythonScript
 
-class TestOrderBuilderMixin(TestOrderMixin):
+class TestOrderBuilderMixin(TestOrderMixin, InventoryAPITestCase):
 
   run_all_test = 1
 
@@ -63,6 +65,10 @@ class TestOrderBuilderMixin(TestOrderMixin):
     """
     self.createCategories()
     self.validateRules()
+    InventoryAPITestCase.afterSetUp(self)
+    self.node_1 = self.portal.organisation_module.newContent(title="Node 1")
+    self.node_2 = self.portal.organisation_module.newContent(title="Node 2")
+    self.pinDateTime(None)
 
   def assertDateAlmostEquals(self, first_date, second_date):
     self.assertTrue(abs(first_date - second_date) < 1.0/86400,
@@ -73,7 +79,7 @@ class TestOrderBuilderMixin(TestOrderMixin):
     Sets max_delay on resource
     """
     resource = sequence.get('resource')
-    resource.edit(max_delay=self.max_delay)
+    resource.edit(purchase_supply_line_max_delay=self.max_delay)
 
   def stepSetMinFlowOnResource(self, sequence):
     """
@@ -83,12 +89,17 @@ class TestOrderBuilderMixin(TestOrderMixin):
     resource.edit(purchase_supply_line_min_flow=self.min_flow)
 
   def stepFillOrderBuilder(self, sequence):
+    self.fillOrderBuilder(sequence=sequence)
+
+  def fillOrderBuilder(self, sequence=None):
     """
     Fills Order Builder with proper quantites
     """
-    order_builder = sequence.get('order_builder')
-    organisation = sequence.get('organisation')
-    resource = sequence.get('resource')
+    order_builder = self.order_builder
+    if sequence is not None:
+      organisation = sequence.get('organisation')
+    else:
+      organisation = None
 
     order_builder.edit(
       delivery_module = self.order_module,
@@ -183,12 +194,17 @@ class TestOrderBuilderMixin(TestOrderMixin):
     generated_document_list = order_builder.build()
     sequence.set('generated_document_list', generated_document_list)
 
-  def stepCreateOrderBuilder(self, sequence):
+  def createOrderBuilder(self):
     """
     Creates empty Order Builder
     """
     order_builder = self.portal.portal_orders.newContent(
       portal_type=self.order_builder_portal_type)
+    self.order_builder = order_builder
+    return order_builder
+
+  def stepCreateOrderBuilder(self, sequence):
+    order_builder = self.createOrderBuilder()
     sequence.set('order_builder', order_builder)
 
   def stepDecreaseOrganisationResourceQuantityVariated(self, sequence):
@@ -409,6 +425,73 @@ class TestOrderBuilder(TestOrderBuilderMixin, ERP5TypeTestCase):
 
     sequence_list.play(self)
 
+  def createSelectMethodForBuilder(self):
+    portal = self.getPortal()
+
+  def checkOrderBuilderStockOptimisationResult(self, expected_result, **kw):
+    result_list = [(x.getResource(), x.getQuantity(),
+                    x.getStartDate().strftime("%Y/%m/%d"),
+                    x.getStopDate().strftime("%Y/%m/%d")) for x in \
+                    self.order_builder.generateMovementListForStockOptimisation(**kw)]
+    result_list.sort()
+    expected_result.sort()
+    self.assertEqual(expected_result, result_list)
+
+  def test_04_generateMovementListWithDateInThePast(self):
+    """
+    If we can not find a future date for stock optimisation, make sure to
+    take current date as default value (before if no date was found, no
+    result was returned, introducing risk to forget ordering something, this
+    could be big issue in real life)
+    """
+    node_1 = self.node_1
+    fixed_date = DateTime('2016/08/30')
+    self.pinDateTime(fixed_date)
+    self.createOrderBuilder()
+    self.fillOrderBuilder()
+    node_1_uid = node_1.getUid()
+    self.checkOrderBuilderStockOptimisationResult([], node_uid=node_1.getUid())
+    self._makeMovement(quantity=-3, destination_value=node_1, simulation_state='confirmed')
+    resource_url = self.resource.getRelativeUrl()
+    self.checkOrderBuilderStockOptimisationResult(
+       [(resource_url, 3.0, '2016/08/30', '2016/08/30')], node_uid=node_1.getUid())
+
+  def test_05_generateMovementListForStockOptimisationForSeveralNodes(self):
+    """
+    It's common to have a warehouse composed of subparts, each subpart could have
+    it's own subpart, etc. So we have to look at stock optimisation for the whole
+    warehouse, since every resource might be stored in several distinct sub parts.
+    Make sure that stock optimisation works fine in such case.
+    """
+    node_1 = self.node_1
+    node_2 = self.node_2
+    resource = self.resource
+    self.createOrderBuilder()
+    self.fillOrderBuilder()
+    fixed_date = DateTime('2016/08/10')
+    self.pinDateTime(fixed_date)
+    resource_url = self.resource.getRelativeUrl()
+    node_uid_list = [node_1.getUid(), self.node_2.getUid()]
+    def checkStockOptimisationForTwoNodes(expected_result):
+      self.checkOrderBuilderStockOptimisationResult(expected_result, node_uid=node_uid_list,
+                                                    group_by_node=0)
+    checkStockOptimisationForTwoNodes([])
+    self._makeMovement(quantity=-3, destination_value=node_1, simulation_state='confirmed',
+                       start_date=DateTime('2016/08/20'))
+    checkStockOptimisationForTwoNodes([(resource_url, 3.0, '2016/08/20', '2016/08/20')])
+    self._makeMovement(quantity=-2, destination_value=node_1, simulation_state='confirmed',
+                       start_date=DateTime('2016/08/18'))
+    checkStockOptimisationForTwoNodes([(resource_url, 5.0, '2016/08/18', '2016/08/18')])
+    self._makeMovement(quantity=-7, destination_value=node_2, simulation_state='confirmed',
+                       start_date=DateTime('2016/08/19'))
+    checkStockOptimisationForTwoNodes([(resource_url, 12.0, '2016/08/18', '2016/08/18')])
+    self._makeMovement(quantity=11, destination_value=node_2, simulation_state='confirmed',
+                       start_date=DateTime('2016/08/16'))
+    checkStockOptimisationForTwoNodes([(resource_url, 1.0, '2016/08/20', '2016/08/20')])
+    self._makeMovement(quantity=7, destination_value=node_1, simulation_state='confirmed',
+                       start_date=DateTime('2016/08/15'))
+    checkStockOptimisationForTwoNodes([])
+
 def test_suite():
   suite = unittest.TestSuite()
   suite.addTest(unittest.makeSuite(TestOrderBuilder))