diff --git a/product/ERP5/Document/AppliedRule.py b/product/ERP5/Document/AppliedRule.py
index 9dffa3a55d97bcae31e43a64153a8aa44d8cbd7a..9fe7e89f09a5a0468591258dde3654471a33f762 100644
--- a/product/ERP5/Document/AppliedRule.py
+++ b/product/ERP5/Document/AppliedRule.py
@@ -28,8 +28,10 @@
 ##############################################################################
 
 from collections import deque
+import sys
+import transaction
 import zope.interface
-
+from zExceptions import ExceptionFormatter
 from AccessControl import ClassSecurityInfo
 from Products.ERP5Type import Permissions, PropertySheet, interfaces
 from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
@@ -485,3 +487,38 @@ class AppliedRule(XMLObject, ExplainableMixin):
       assert str not in map(type, old_dict), old_dict
       return dict((k, sum(v.values(), [])) for k, v in deleted), delivery_set
     simulation_tool._delObject(self.getId())
+
+  def _checkExpand(self):
+    """Check that expand() would not fail nor do major changes to the subobjects
+
+    Transaction is aborted after 'expand' is called.
+
+    See also SimulationTool._checkExpandAll
+    """
+    property_dict = {'Applied Rule': ('specialise',),
+                     'Simulation Movement': ('delivery', 'quantity')}
+    def fillRuleDict():
+      rule_dict = {}
+      object_list = deque((self,))
+      while object_list:
+        document = object_list.popleft()
+        portal_type = document.getPortalType()
+        document_dict = {'portal_type': portal_type}
+        for property in property_dict[portal_type]:
+          document_dict[property] = document.getProperty(property)
+        rule_dict[document.getRelativeUrl()] = document_dict
+        object_list += document.objectValues()
+      return rule_dict
+    initial_rule_dict = fillRuleDict()
+    try:
+      self.expand()
+    except ConflictError:
+      raise
+    except Exception:
+      msg = ''.join(ExceptionFormatter.format_exception(*sys.exc_info())[1:])
+    else:
+      final_rule_dict = fillRuleDict()
+      msg = "%r != %r" % (initial_rule_dict, final_rule_dict) \
+            if initial_rule_dict != final_rule_dict else None
+    transaction.abort()
+    return msg
diff --git a/product/ERP5/Tool/SimulationTool.py b/product/ERP5/Tool/SimulationTool.py
index 1fc4c38d89f3a897a6477a269c8a9d6947ef0d04..ace4b77b6bbba0f51e5dde7f6aa56c84e892e3da 100644
--- a/product/ERP5/Tool/SimulationTool.py
+++ b/product/ERP5/Tool/SimulationTool.py
@@ -2867,6 +2867,18 @@ class SimulationTool(BaseTool):
                           src__=src__))
       return sequence
 
+    def _checkExpandAll(self, activate_kw={}):
+      """Check all simulation trees using AppliedRule._checkExpand
+      """
+      portal = self.getPortalObject()
+      active_process = portal.portal_activities.newActiveProcess().getPath()
+      kw = dict(priority=3, tag='checkExpand')
+      kw.update(group_method_cost=1, max_retry=0,
+                active_process=active_process, **activate_kw)
+      self._recurseCallMethod('_checkExpand', min_depth=1, max_depth=1,
+                              activate_kw=kw)
+      return active_process
+
 from Products.ERP5Type.DateUtils import addToDate
 
 class SequenceItem: