diff --git a/product/ERP5/Document/SolverProcess.py b/product/ERP5/Document/SolverProcess.py
index 4cd5a1ed347ab6ad0e6faabef6659648cf4ca43a..3d6a9061ec764316061aea5ffaf3924279992526 100644
--- a/product/ERP5/Document/SolverProcess.py
+++ b/product/ERP5/Document/SolverProcess.py
@@ -82,64 +82,94 @@ class SolverProcess(XMLObject, ActiveProcess):
     """
     movement_dict = {}
     types_tool = self.portal_types
+    message_list = []
 
     # First create a mapping between delivery movements and solvers
     #   in order to know for each movements which solvers are needed
     #   and which parameters with
+    #
+    #   movement_dict[movement] = {
+    #              solver : [((c1, v1), (c2, v2 )),
+    #                        ((c1, v1), (c2, v2 )),
+    #                       ],
     for decision in self.contentValues(portal_type="Solver Decision"):
       solver = decision.getSolverValue()
       # do nothing if solver is not yet set.
       if solver is None:
         continue
-      solver_type = solver.getId() # ex. Postpone Production Solver
       solver_conviguration_dict = decision.getConfigurationPropertyDict()
-      solver_conviguration_key = tuple(solver_conviguration_dict.items())
+      configuration_mapping = solver_conviguration_dict.items()
+      configuration_mapping.sort() # Make sure the list is sorted in canonical way
+      configuration_mapping = tuple(configuration_mapping)
       for movement in decision.getDeliveryValueList():
         # Detect incompatibilities
-        movement_solver_dict = movement_dict.setdefault(movement.getRelativeUrl(), {})
-        movement_solver_configuration_list = movement_solver_dict.setdefault(solver_type, [])
-        if solver_conviguration_key not in movement_solver_configuration_list:
-          movement_solver_configuration_list.append(solver_conviguration_key)
+        movement_solver_dict = movement_dict.setdefault(movement, {})
+        movement_solver_configuration_list = movement_solver_dict.setdefault(solver, [])
+        if configuration_mapping not in movement_solver_configuration_list:
+          movement_solver_configuration_list.append(configuration_mapping)
 
-    # Second, make sure solvers do not conflict and configuration is valid
-    # Build a movement and configuration structure per solver type
+    # Second, create a mapping between solvers and movements 
+    # and their configuration
+    #
+    #   solver_dict[solver] = {
+    #     movement : [((c1, v1), (c2, v2 )),
+    #                 ((c1, v1), (c2, v2 )),
+    #                ],
+    #   }
+    #
     solver_dict = {}
-    for movement_url, movement_solver_dict in movement_dict.items():
-      for solver_type, movement_solver_configuration_list in movement_solver_dict.items():
-        solver_movement_dict = solver_dict.setdefault(solver_type, {})
-        configuration_list = solver_movement_dict.setdefault(movement_url, [])
-        configuration_list.extend(movement_solver_configuration_list) # XXX-JPS WRONG
-    # Then start the grouping procedure
-    solver_dict = {}
-    for movement_url, movement_solver_dict in movement_dict.items():
-      for solver_type, movement_solver_configuration_list in movement_solver_dict.items():
-        solver = types_tool[solver_type]
-        for other_solver_type in movement_solver_dict.keys():
-          if other_solver_type == solver_type:
-            continue
-          if solver.conflictsWithSolver(types_tool[other_solver_type]):
-            # XXX6PJS REDO HERE
-            raise ValueError, "Solver %s conflicts with solver %s on movement %s" % (solver_type, other_solver_type, movement_url)
-        # Make sure multiple configuration are possible
-        try:
-          # Solver key contains only those properties which differentiate
-          # solvers (ex. there should be only Production Reduction Solver)
-          solver_key = solver.getSolverProcessGroupingKey(movement_url, movement_solver_configuration_list, movement_solver_dict)
-        except: # Raise the exception generated by the solver in case of failure of grouping
-          raise
-        solver_key_dict = solver_dict.setdefault(solver_type, {})
-        solver_movement_dict = solver_key_dict.setdefault(solver_key, {})
-        solver_movement_dict[movement_url] = movement_solver_configuration_list
-
-    # Third, build target solvers
-    for solver_type, solver_key_dict in solver_dict.items():
+    for movement, movement_solver_dict in movement_dict.items():
+      for solver, movement_solver_configuration_list in movement_solver_dict.items():
+        solver_movement_dict = solver_dict.setdefault(solver, {})
+        solver_movement_dict[movement] = movement_solver_configuration_list
+
+    # Third, group solver configurations and make sure solvers do not conflict
+    # by creating a mapping between solvers and movement configuration grouped
+    # by a key which is used to aggregate multiple configurations
+    #
+    #   grouped_solver_dict[solver] = {
+    #     solver_key: {
+    #        movement : [((c1, v1), (c2, v2 )),
+    #                    ((c1, v1), (c2, v2 )),
+    #                   ],
+    #          }
+    #   }
+    grouped_solver_dict = {}
+    for movement, movement_solver_dict in movement_dict.items():
+      for solver, movement_solver_configuration_list in movement_solver_dict.items():
+        for configuration_mapping in movement_solver_configuration_list:
+          solver_message_list = solver.getSolverConflictMessageList(movement, configuration_mapping, solver_dict)
+          if solver_message_list:
+            message_list.extend(solver_message_list)
+            continue # No need to keep on
+          # Make sure multiple configuration are possible
+          try:
+            # Solver key contains only those properties which differentiate
+            # solvers (ex. there should be only Production Reduction Solver)
+            solver_key = solver.getSolverProcessGroupingKey(movement, configuration_mapping, solver_dict)
+          except: # Raise the exception generated by the solver in case of failure of grouping
+            raise
+          solver_key_dict = grouped_solver_dict.setdefault(solver, {})
+          solver_movement_dict = solver_key_dict.setdefault(solver_key, {})
+          movement_solver_configuration_list = movement_solver_dict.setdefault(solver, [])
+          if configuration_mapping not in movement_solver_configuration_list:
+            movement_solver_configuration_list.append(configuration_mapping)
+
+    # Return empty list of conflicts
+    if message_list: return message_list
+
+    # Fourth, build target solvers
+    for solver, solver_key_dict in grouped_solver_dict.items():
       for solver_key, solver_movement_dict in solver_key_dict.items():
-         solver_instance = self.newContent(portal_type=solver_type)
-         solver_instance._setDeliveryList(solver_movement_dict.keys())
-         for movement_url, configuration_list in solver_movement_dict.iteritems():
-           for configuration_kw in configuration_list:
-             if len(configuration_kw):
-               solver_instance.updateConfiguration(**dict(configuration_kw))
+         solver_instance = self.newContent(portal_type=solver.getId())
+         solver_instance._setDeliveryValueList(solver_movement_dict.keys())
+         for movement, configuration_list in solver_movement_dict.iteritems():
+           for configuration_mapping in configuration_list:
+             if len(configuration_mapping):
+               solver_instance.updateConfiguration(**dict(configuration_mapping))
+
+    # Return empty list of conflicts
+    return []
 
   # ISolver implementation
   # Solver Process Workflow Interface 
diff --git a/product/ERP5/Document/SolverTypeInformation.py b/product/ERP5/Document/SolverTypeInformation.py
index 89b366bd2594594d4102287aecb1b6126b3a489a..dae03dc79b4a7405da8dd58ade1b110383054a1d 100644
--- a/product/ERP5/Document/SolverTypeInformation.py
+++ b/product/ERP5/Document/SolverTypeInformation.py
@@ -52,31 +52,45 @@ class SolverTypeInformation(ERP5TypeInformation):
                     , PropertySheet.Configurable
                     )
 
-  def conflictsWithSolver(self, movement, configuration_dict, other_configuration_list):
+  def getSolverConflictMessageList(self, movement, configuration_mapping, solver_dict, movement_dict):
     """
-    Returns True if the solver conflicts with other_solver. False else.
+    Returns the list of conflictings messgaes if the solver and configuration_mapping
+    conflicts with another solver
 
-    movement -- a movement or a movement relative url
+    movement -- a movement
+
+    configuration_mapping -- a mapping of configuration parameters sorted in
+                             canonical way. ((c1, v1), (c2, v2 ))
   
-    configuration_dict -- a dictionary of configuration parameters to
-                          solve the current movement with self
-                          
-    other_configuration_list -- a list of solvers and their configuration
-                                for the same movement
+    solver_dict -- a dictionary of configuration parameters for 
+                   each solver
+                      solver_dict[solver] = {
+                         movement : [((c1, v1), (c2, v2 )),
+                                     ((c1, v1), (c2, v2 )),
+                                    ],}
+
+    movement_dict -- a dictionary of solver and configuration parameters for 
+                     each movement
+                       movement_dict[movement] = {
+                                     solver : [((c1, v1), (c2, v2 )),
+                                               ((c1, v1), (c2, v2 )),
+                                              ],}
     """
-    method = self._getTypeBasedMethod('conflictsWithSolver')
+    method = self._getTypeBasedMethod('getSolverConflictMessageList')
     if method is not None:
-      return method(movement, configuration_dict, other_configuration_list)
+      return method(movement, configuration_mapping, solver_dict, movement_dict)
 
     # Default Implementation (use categories and trivial case)
-    for solver_type, configuration_dict in other_configuration_list:
-      if solver.getTestedProperty() == self.getTestedProperty():
-        return True
+    #  this default implementation should be applicable to most 
+    #  solvers so that use of Type Based methods is very rare
+    for solver, configuration_list in movement_dict[movement].items():
+      if solver is not self and solver.getTestedProperty() == self.getTestedProperty():
+        return AppropriateUIMessage(whatever) # XXX-TODO
 
-    # Return False by Default
-    return False
+    # Return emtpty message list
+    return ()
 
-  def getSolverProcessGroupingKey(self, movement, configuration_dict, other_configuration_list):
+  def getSolverProcessGroupingKey(self, movement, configuration_mapping, solver_dict, movement_dict):
     """
     Returns a key which can be used to group solvers during the 
     process to build Targer Solver instances from Solver Decisions.
@@ -98,26 +112,34 @@ class SolverTypeInformation(ERP5TypeInformation):
     Adopt, Accept) which tested property is configurable, is the 
     tested property itself.
 
-    movement -- a movement or a movement relative url
-  
-    configuration_dict -- a dictionary of configuration parameters
+    movement -- a movement
 
-    other_configuration_list -- a list of movements and their configuration
-                                which are solved by the same solve type. 
-                                [(m1, c1), (m2, c2), ...] 
+    configuration_mapping -- a mapping of configuration parameters sorted in
+                             canonical way. ((c1, v1), (c2, v2 ))
+  
+    solver_dict -- a dictionary of configuration parameters for 
+                   each solver
+                      solver_dict[solver] = {
+                         movement : [((c1, v1), (c2, v2 )),
+                                     ((c1, v1), (c2, v2 )),
+                                    ],}
+
+    movement_dict -- a dictionary of solver and configuration parameters for 
+                     each movement
+                       movement_dict[movement] = {
+                                     solver : [((c1, v1), (c2, v2 )),
+                                               ((c1, v1), (c2, v2 )),
+                                              ],}
     """
     method = self._getTypeBasedMethod('getSolverProcessGroupingKey')
     if method is not None:
-      return method(movement, configuration_dict, other_configuration_list)
+      return method(movement, configuration_mapping, solver_dict, movement_dict)
 
-    # Default Implementation (read properties and implement XXX)
+    # Default Implementation (read solver type properties and implement XXX-TODO)
     if self.isLineGroupable():
       return ()
 
-    if isinstance(movement, str):
-      return movement
-    else:
-      return movement.getRelativeUrl()
+    return movement.getRelativeUrl()
 
   def getDefaultConfigurationPropertyDict(self, configurable):
     """