diff --git a/product/ERP5/Document/Delivery.py b/product/ERP5/Document/Delivery.py
index 5cd2ffe622ddf15910a370e7672011ac1f271234..cc67a8d11cb023003410b33768b3918102e823b7 100755
--- a/product/ERP5/Document/Delivery.py
+++ b/product/ERP5/Document/Delivery.py
@@ -38,6 +38,7 @@ from Products.ERP5.Document.DeliveryCell import DeliveryCell
 from Acquisition import Explicit, Implicit
 from Products.PythonScripts.Utility import allow_class
 from DateTime import DateTime
+#from Products.ERP5.ERP5Globals import movement_type_list, draft_order_state, planned_order_state
 
 from zLOG import LOG
 
@@ -231,70 +232,6 @@ class Delivery(XMLObject):
                       , PropertySheet.Reference
                       )
 
-    # CMF Factory Type Information
-    factory_type_information = \
-      {    'id'             : portal_type
-         , 'meta_type'      : meta_type
-         , 'description'    : """\
-une liste de mouvements..."""
-         , 'icon'           : 'delivery_icon.gif'
-         , 'product'        : 'ERP5'
-         , 'factory'        : 'addDelivery'
-         , 'immediate_view' : 'delivery_view'
-         , 'allow_discussion'     : 1
-         , 'allowed_content_types': ('Movement',
-                                      )
-         , 'filter_content_types' : 1
-         , 'global_allow'   : 1
-         , 'actions'        :
-        ( { 'id'            : 'view'
-          , 'name'          : 'View'
-          , 'category'      : 'object_view'
-          , 'action'        : 'delivery_view'
-          , 'permissions'   : (
-              Permissions.View, )
-          }
-        , { 'id'            : 'list'
-          , 'name'          : 'Object Contents'
-          , 'category'      : 'object_action'
-          , 'action'        : 'folder_contents'
-          , 'permissions'   : (
-              Permissions.View, )
-          }
-        , { 'id'            : 'print'
-          , 'name'          : 'Print'
-          , 'category'      : 'object_print'
-          , 'action'        : 'delivery_print'
-          , 'permissions'   : (
-              Permissions.View, )
-          }
-        , { 'id'            : 'metadata'
-          , 'name'          : 'Metadata'
-          , 'category'      : 'object_view'
-          , 'action'        : 'metadata_edit'
-          , 'permissions'   : (
-              Permissions.View, )
-          }
-        , { 'id'            : 'translate'
-          , 'name'          : 'Translate'
-          , 'category'      : 'object_action'
-          , 'action'        : 'translation_template_view'
-          , 'permissions'   : (
-              Permissions.TranslateContent, )
-          }
-        )
-      }
-
-
-#     security.declareProtected(Permissions.AccessContentsInformation, 'getCausalitySate')
-#     def getCausalityState(self, id_only=1):
-#       """
-#         Returns the current state in causality
-#       """
-#       portal_workflow = getToolByName(self, 'portal_workflow')
-#       wf = portal_workflow.getWorkflowById('causality_workflow')
-#       return wf._getWorkflowStateOf(self, id_only=id_only)
-
     security.declareProtected(Permissions.AccessContentsInformation, 'getSimulationState')
     def getSimulationState(self, id_only=1):
       """
@@ -393,6 +330,8 @@ une liste de mouvements..."""
       """
         This method is called whenever a packing list is being invoiced
       """
+      # We will make sure that everything is well generated into  the
+      # simulation, then we will be able to buid the invoice list.
       # we create an invoice for this delivery
       self.activate(priority=4).buildInvoiceList()
 
@@ -400,59 +339,158 @@ une liste de mouvements..."""
 
     security.declareProtected(Permissions.ModifyPortalContent, 'buildInvoiceList')
     def buildInvoiceList(self):
-      invoice = self.facture_vente.newContent(portal_type='Sale Invoice Transaction',
-                          source=self.getSource(),
-                          destination=self.getDestination(),
-                          source_section=self.getSourceSection(),
-                          destination_section=self.getDestinationSection(),
-                          incoterm = self.getIncoterm(),
-                          delivery_mode = self.getDeliveryMode(),
-                          description = 'Vente'
-                          )
-      invoice.setCausalityValue(self) # create causality relation
-
-      # Copy specific trade conditions (discount, payment)
-      order = self.getDefaultCausalityValue() # we only copy a single set of trade conditions
-      if order is not None :
-        to_copy=[]
-        to_copy=order.contentIds(filter={'portal_type':'Remise'})
-        if len(to_copy)>0 :
-          copy_data = order.manage_copyObjects(ids=to_copy)
-          new_id_list = invoice.manage_pasteObjects(copy_data)
-        # copy some properties from order
-        for key in ('payment_amount', 'payment_ratio', 'payment_term', 'payment_end_of_month', 'payment_additional_term', 'payment_mode', 'trade_date', 'price_currency', 'destination_administration', 'destination_decision', 'destination_payment', 'source_payment'):
-          invoice.setProperty(key, order.getProperty(key))
-
-      # Define VAT recoverability
-      if invoice.getDestinationSectionValue().getDefaultAddress() is not None :
-        if invoice.getDestinationSectionValue().getDefaultAddress().getRegion() in ('Europe/Nord/France',None,'') :
-          vat_ratio = 0.196
-          vat_recoverable = 1
-        else :
-          vat_ratio = 0
-          vat_recoverable = 0
-      else :
-        vat_ratio = 0
-        vat_recoverable = 0
-      # Set start_date
-      invoice_start_date = self.getTargetStartDate()
-      invoice.edit(value_added_tax_recoverable = vat_recoverable, value_added_tax_ratio = vat_ratio, start_date = invoice_start_date)
-      # Add Invoice lines for each resource/variation
-      movement_list = self.getMovementList()
-      movement_group = invoice.collectMovement(movement_list)
-      invoice_line_list = invoice.buildInvoiceLineList(movement_group)  # This method should be able to calculate price for each line
-
-      # Set local_roles
-      # what's the gestionaire of this order
-      user_name = ''
-      # are we on a sales order or puchase order ?
-      if order is not None :
-        if order.getPortalType() == 'Sales Order' :
-          user_name = order.getSourceAdministrationTitle().replace(' ','_')
-        elif order.getPortalType() == 'Purchase Order' :
-          user_name = order.getDestinationAdministrationPersonTitle().replace(' ','_')
-      # update local_roles
-      invoice.assign_gestionaire_designe_roles(user_name = user_name)
+      """
+      """
+      # Retrieve all invoices lines into the simulation
+      LOG('buildInvoiceList on',0,self.getPath())
+      simulation_invoice_line_list = []
+      LOG('buildInvoiceList self.objectIds()',0,self.objectIds())
+
+      #delivery_rule = self.getCausalityRelatedValueList()[0]
+      #simulation_invoice_line_list = delivery_rule.objectValues()
+      parent_simulation_line_list = []
+      for o in self.objectValues():
+        LOG('buildInvoiceList line.getDeliveryRelated',0,o.getDeliveryRelatedValueList())
+        parent_simulation_line_list += [x for x in o.getDeliveryRelatedValueList() \
+                                        if x.getPortalType()=='Simulation Movement']
+      simulation_line_list = []
+      LOG('buildInvoiceList parent_simulation_line_list',0,parent_simulation_line_list)
+      for o in parent_simulation_line_list:
+        LOG('buildInvoiceList rule_list',0,o.objectValues())
+        for rule in o.objectValues():
+          LOG('buildInvoiceList rule.objectValues()',0,rule.objectValues())
+          simulation_line_list += rule.objectValues()
+      #  for rule in o.getDeliveryRelatedValueList(portal_type='Simulation Movement'):
+      #    simulation_invoice_line_list += rule.objectValues()
+      LOG('buildInvoiceList simulation_invoice_line_list',0,simulation_invoice_line_list)
+      from Products.ERP5.MovementGroup import OrderMovementGroup
+      from Products.ERP5.MovementGroup import PathMovementGroup
+      from Products.ERP5.MovementGroup import DateMovementGroup
+      from Products.ERP5.MovementGroup import ResourceMovementGroup
+      from Products.ERP5.MovementGroup import VariantMovementGroup
+      #class_list = [OrderMovementGroup,PathMovementGroup,DateMovementGroup,ResourceMovementGroup,VariantMovementGroup]
+      class_list = [OrderMovementGroup,PathMovementGroup,DateMovementGroup,ResourceMovementGroup]
+      root_group = self.portal_simulation.collectMovement(simulation_invoice_line_list,class_list=class_list)
+      invoice_list = []
+
+      LOG('buildInvoiceList root_group',0,root_group)
+      if root_group is not None:
+        LOG('buildInvoiceList root_group.group_list',0,root_group.group_list)
+        for order_group in root_group.group_list:
+          LOG('buildInvoiceList order_group.order',0,order_group.order)
+          #if order_group.order is None: # How to check, order is actually the packing list line ???
+          if 1:
+            # Only build if there is not order yet
+            LOG('buildInvoiceList order_group.group_list',0,order_group.group_list)
+            for path_group in order_group.group_list :
+              invoice_module = self.accounting
+              invoice_type = 'Sale Invoice Transaction'
+              invoice_line_type = 'Invoice Line'
+
+              LOG('buildInvoiceList path_group.group_list',0,path_group.group_list)
+              for date_group in path_group.group_list :
+
+                invoice = invoice_module.newContent(portal_type = invoice_type)
+                invoice.edit( target_start_date = date_group.start_date,
+                              target_stop_date = date_group.stop_date,
+                              start_date = date_group.start_date,
+                              stop_date = date_group.stop_date,
+                              source = path_group.source,
+                              destination = path_group.destination,
+                              source_section = path_group.source_section,
+                              destination_section = path_group.destination_section,
+                              target_source = path_group.source,
+                              target_destination = path_group.destination,
+                              target_source_section = path_group.source_section,
+                              target_destination_section = path_group.destination_section)
+                invoice_list.append(invoice)
+                delivery_rule.setDeliveryValue(invoice)
+
+                for resource_group in date_group.group_list :
+
+                  LOG('resource_group.group_list',0,resource_group.group_list)
+                  # Create a new Sale Invoice Transaction Line for each resource
+                  resource = resource_group.resource
+                  simulation_line_list = resource_group.movement_list
+                  simulation_line = simulation_line_list[0]
+
+                  invoice_line = invoice.newContent(portal_type = invoice_line_type)
+                  invoice_line.edit( resource=resource)
+                  simulation_line.setDeliveryValue(invoice_line)
+                  resource_movement_list = resource_group.movement_list
+                  quantity = sum([x.getTargetQuantity() for x in resource_movement_list \
+                                 if x.getTargetQuantity() is not None])
+                  price = resource_movement_list[0].getPrice()
+                  invoice_line.edit(quantity=quantity,
+                                    price=price)
+                                    
+                  # the new delivery is added to the order_list
+
+
+                  #msdlfjkdslmjfsdmljf()
+                  #line_variation_category_list = []
+                  #line_variation_base_category_dict = {}
+
+                  # compute line_variation_base_category_list and
+                  # line_variation_category_list for new delivery_line
+#                  for variant_group in resource_group.group_list :
+#                    for variation_item in variant_group.category_list :
+#                      if not variation_item in line_variation_category_list :
+#                        line_variation_category_list.append(variation_item)
+#                        variation_base_category_items = variation_item.split('/')
+#                        if len(variation_base_category_items) > 0 :
+#                          line_variation_base_category_dict[variation_base_category_items[0]] = 1
+
+                  # update variation_base_category_list and line_variation_category_list for delivery_line
+                  #line_variation_base_category_list = line_variation_base_category_dict.keys()
+                  #delivery_line.setVariationBaseCategoryList(line_variation_base_category_list)
+                  #delivery_line.setVariationCategoryList(line_variation_category_list)
+
+                  # IMPORTANT : delivery cells are automatically created during setVariationCategoryList
+
+                  # update target_quantity for each delivery_cell
+#                  for variant_group in resource_group.group_list :
+#                    #LOG('Variant_group examin',0,str(variant_group.category_list))
+#                    object_to_update = None
+#                    # if there is no variation of the resource, update delivery_line with quantities and price
+#                    if len(variant_group.category_list) == 0 :
+#                      object_to_update = delivery_line
+#                    # else find which delivery_cell is represented by variant_group
+#                    else :
+#                      categories_identity = 0
+#                      #LOG('Before Check cell',0,str(delivery_cell_type))
+#                      #LOG('Before Check cell',0,str(delivery_line.contentValues()))
+#                      for delivery_cell in delivery_line.contentValues(filter={'portal_type':'Delivery Cell'}) :
+#                        #LOG('Check cell',0,str(delivery_cell))
+#                        #LOG('Check cell',0,str(variant_group.category_list))
+#                        #LOG('Check cell',0,str(delivery_cell.getVariationCategoryList()))
+#                        if len(variant_group.category_list) == len(delivery_cell.getVariationCategoryList()) :
+#                          #LOG('Parse category',0,str(delivery_cell.getVariationCategoryList()))
+#                          for category in delivery_cell.getVariationCategoryList() :
+#                            if not category in variant_group.category_list :
+#                              #LOG('Not found category',0,str(category))
+#                              break
+#                          else :
+#                            categories_identity = 1
+#
+#                        if categories_identity :
+#                          object_to_update = delivery_cell
+#                          break
+#
+#                    # compute target_quantity, quantity and price for delivery_cell or delivery_line and
+#                    # build relation between simulation_movement and delivery_cell or delivery_line
+#                    if object_to_update is not None :
+#                      cell_target_quantity = 0
+#                      for movement in variant_group.movement_list :
+#                        cell_target_quantity += movement.getConvertedTargetQuantity()
+#                      # We do not create a relation or modifu anything
+#                      # since planification of this movement will create new applied rule
+#                      object_to_update.edit(target_quantity = cell_target_quantity,
+#                                            quantity = cell_target_quantity,
+#                                            force_update = 1)
+
+      return invoice_list
+
 
     # Pricing methods
     def _getTotalPrice(self, context):
@@ -635,8 +673,13 @@ une liste de mouvements..."""
         Returns 1 if all movements have a delivery or order counterpart
         in the simulation
       """
+      LOG('Delivery.isSimulated getMovementList',0,self.getMovementList())
       for m in self.getMovementList():
+        LOG('Delivery.isSimulated m',0,m.getPhysicalPath())
+        LOG('Delivery.isSimulated m.isSimulated',0,m.isSimulated())
         if not m.isSimulated():
+          LOG('Delivery.isSimulated m.getQuantity',0,m.getQuantity())
+          LOG('Delivery.isSimulated m.getTargetQuantity',0,m.getTargetQuantity())
           if m.getQuantity() != 0.0 or m.getTargetQuantity() != 0:
             return 0
           # else Do we need to create a simulation movement ? XXX probably not
@@ -672,6 +715,11 @@ une liste de mouvements..."""
         Destination is divergent if simulated and target values differ
         or if multiple destinations are defined
       """
+      LOG('Delivery.isDestinationDivergent, self.getPath()',0,self.getPath())
+      LOG('Delivery.isDestinationDivergent, self.getDestination()',0,self.getDestination())
+      LOG('Delivery.isDestinationDivergent, self.getTargetDestination()',0,self.getTargetDestination())
+      LOG('Delivery.isDestinationDivergent, self.getDestinationList()',0,self.getDestinationList())
+      LOG('Delivery.isDestinationDivergent, self.getTargetDestinationList()',0,self.getTargetDestinationList())
       if self.getDestination() != self.getTargetDestination() \
           or len(self.getDestinationList()) > 1 \
           or len(self.getTargetDestinationList()) > 1:
@@ -704,6 +752,10 @@ une liste de mouvements..."""
     def isDateDivergent(self):
       """
       """
+      LOG("isDivergent getStartDate", 0, repr(self.getStartDate()))
+      LOG("isDivergent getTargetStartDate", 0, repr(self.getTargetStartDate()))
+      LOG("isDivergent getStopDate", 0, repr(self.getStopDate()))
+      LOG("isDivergent getTargetStopDate", 0, repr(self.getTargetStopDate()))
       from DateTime import DateTime
       if self.getStartDate() is None or self.getTargetStartDate() is None \
                or self.getStopDate() is None or self.getTargetStopDate() is None:
@@ -1216,7 +1268,10 @@ une liste de mouvements..."""
           for c in l.contentValues(filter={'portal_type':self.getPortalDeliveryMovementTypeList()}):
             #source_list.extend(c.getSimulationSourceList())
             delivery_cell_related_list = c.getDeliveryRelatedValueList()
+            delivery_cell_related_list = [x for x in delivery_cell_related_list if (x.getId()!='produced_resource')]
             source_list.extend(map(lambda x: x.getSource(),delivery_cell_related_list))
+            LOG('Delivery.updateFromSimulation, source_list:',0,source_list)
+            LOG('Delivery.updateFromSimulation, delivery_cell_related_list:',0,[x.getPhysicalPath() for x in delivery_cell_related_list])
             target_source_list.extend(map(lambda x: x.getTargetSource(),delivery_cell_related_list))
             #destination_list.extend(c.getDestinationSourceList())
             destination_list.extend(map(lambda x: x.getDestination(),delivery_cell_related_list))
@@ -1240,12 +1295,23 @@ une liste de mouvements..."""
             simulation_target_quantity = sum(map(lambda x: x.getTargetQuantity(),delivery_line_related_list))
             c._setTargetQuantity(simulation_target_quantity)
       # Update source list
-      self._setSourceSet(source_list) # Set should make sure each item is only once
-      self._setDestinationSet(destination_list)
+      LOG('Delivery.updateFromSimulation, source_list:',0,source_list)
+      LOG('Delivery.updateFromSimulation, destination_list:',0,destination_list)
+      LOG('Delivery.updateFromSimulation, target_source_list:',0,target_source_list)
+      LOG('Delivery.updateFromSimulation, target_destination_list:',0,target_destination_list)
+      if not None in source_list:
+        self._setSourceSet(source_list) # Set should make sure each item is only once
+      if not None in destination_list:
+        self._setDestinationSet(destination_list) 
       if update_target:
-        self._setTargetSourceSet(target_source_list) # Set should make sure each item is only once
-        self._setTargetDestinationSet(target_destination_list)
-
+        if not None in target_source_list:
+          LOG('Delivery.updateFromSimulation, update_target_source:',0,target_source_list)
+          self._setTargetSourceSet(target_source_list) # Set should make sure each item is only once
+        if not None in target_destination_list:
+          LOG('Delivery.updateFromSimulation, update_target_destination:',0,target_destination_list)
+          self._setTargetDestinationSet(target_destination_list) 
+      self.edit() # so that we may go to converged state
+      
     security.declareProtected(Permissions.ModifyPortalContent, 'propagateResourceToSimulation')
     def propagateResourceToSimulation(self):
       """
@@ -1300,3 +1366,55 @@ une liste de mouvements..."""
         LOG('propagateResourceToSimulation, list_to_merge:',0,list_to_merge)
         self.portal_simulation.mergeDeliveryList(list_to_merge)
 
+    security.declareProtected(Permissions.ModifyPortalContent, 'propagateArrowToSimulation')
+    def propagateArrowToSimulation(self):
+      """
+        Propagates any changes on arrow to the simulation 
+        
+        propagateArrowToSimulation has priority (ie. must be executed before) over updateFromSimulation        
+      """
+      LOG('propagateArrowToSimulation, ',0,'starting')
+      for l in self.contentValues(filter={'portal_type':delivery_movement_type_list}):
+        LOG('propagateArrowToSimulation, l.getPhysicalPath()',0,l.getPhysicalPath())
+        LOG('propagateArrowToSimulation, l.objectValues()',0,l.objectValues())
+        LOG('propagateArrowToSimulation, l.hasCellContent()',0,l.hasCellContent())
+        LOG('propagateArrowToSimulation, l.showDict()',0,l.showDict())
+        if l.hasCellContent():
+          for c in l.contentValues(filter={'portal_type':delivery_movement_type_list}):
+            LOG('propagateArrowToSimulation, c.getPhysicalPath()',0,c.getPhysicalPath())
+            for s in c.getDeliveryRelatedValueList():
+              LOG('propagateArrowToSimulation, s.getPhysicalPath()',0,s.getPhysicalPath())
+              LOG('propagateArrowToSimulation, c.getDestination()',0,c.getDestination())
+              LOG('propagateArrowToSimulation, s.getDestination()',0,s.getDestination())
+              if c.getTargetSource() != s.getSource() \
+                or c.getTargetDestination() != s.getDestination() \
+                or c.getTargetSourceSection() != s.getSourceSection() \
+                or c.getTargetDestinationSection() != s.getDestinationSection():
+                  s.setSource(c.getTargetSource())
+                  s.setDestination(c.getTargetDestination())
+                  s.setSourceSection(c.getTargetSourceSection())
+                  s.setDestinationSection(c.getTargetDestinationSection())
+                  s.activate().expand()
+        else:
+          for s in l.getDeliveryRelatedValueList():
+            if l.getTargetSource() != s.getSource() \
+              or l.getTargetDestination() != s.getDestination() \
+              or l.getTargetSourceSection() != s.getSourceSection() \
+              or l.getTargetDestinationSection() != s.getDestinationSection():
+                s.setSource(l.getTargetSource())
+                s.setDestination(l.getTargetDestination())
+                s.setSourceSection(l.getTargetSourceSection())
+                s.setDestinationSection(l.getTargetDestinationSection())
+                s.activate().expand()
+
+    security.declarePrivate( '_edit' )
+    def _edit(self, REQUEST=None, force_update = 0, **kw):
+      """
+      call propagateArrowToSimulation
+      """
+      XMLObject._edit(self,REQUEST=REQUEST,force_update=force_update,**kw)
+      #self.propagateArrowToSimulation()
+      # We must expand our applied rule only if not confirmed
+      #if self.getSimulationState() in planned_order_state:
+      #  self.updateAppliedRule() # This should be implemented with the interaction tool rather than with this hard coding
+