diff --git a/product/ERP5/tests/testInvoice.py b/product/ERP5/tests/testInvoice.py
index 3e921a5965da3bb31bfa413ef5d3caac6320d2c9..5ce505123e60ef26eb524b78f3a2c2fb8cda9fd3 100755
--- a/product/ERP5/tests/testInvoice.py
+++ b/product/ERP5/tests/testInvoice.py
@@ -2,6 +2,7 @@
 #
 # Copyright (c) 2004 Nexedi SARL and Contributors. All Rights Reserved.
 #          Sebastien Robin <seb@nexedi.com>
+#          Jerome Perrin <jerome@nexedi.com>
 #
 # WARNING: This program as such is intended to be used by professional
 # programmers who take the whole responsability of assessing all potential
@@ -26,14 +27,14 @@
 #
 ##############################################################################
 
+"""
+  Tests invoice creation from simulation.
 
-
-#
-# Skeleton ZopeTestCase
-#
-
-from random import randint
-
+TODO:
+  * check empty related Delivery Rule
+  * check divergence 
+  
+"""
 import os, sys
 if __name__ == '__main__':
     execfile(os.path.join(sys.path[0], 'framework.py'))
@@ -42,420 +43,388 @@ if __name__ == '__main__':
 os.environ['EVENT_LOG_FILE'] = os.path.join(os.getcwd(), 'zLOG.log')
 os.environ['EVENT_LOG_SEVERITY'] = '-300'
 
-from Testing import ZopeTestCase
 from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
-from AccessControl.SecurityManagement import newSecurityManager, noSecurityManager
+from AccessControl.SecurityManagement import newSecurityManager
 from DateTime import DateTime
-from Acquisition import aq_base, aq_inner
 from zLOG import LOG
-from Products.ERP5Type.DateUtils import addToDate
+from testPackingList import TestPackingListMixin
 from Products.ERP5Type.tests.Sequence import Sequence, SequenceList
-import time
-import os
-from Products.ERP5Type import product_path
-from DateTime import DateTime
-
-class TestInvoice(ERP5TypeTestCase):
-  """
-  This is the list of test
 
-  test setNextStartDate : 
-  - every hour
-  - at 6, 10, 15, 21 every day
-  - every day at 10
-  - every 3 days at 14 and 15 and 17
-  - every monday and friday, at 6 and 15
-  - every 1st and 15th every month, at 12 and 14
-  - every 1st day of every 2 month, at 6
-  
-  WARNING:
-  
-  make sure Coramy Product is not installed (because it changes the meta_types
-  of many order/delivery types)
+class TestInvoice(TestPackingListMixin, ERP5TypeTestCase):
+  """Test invoice are created from orders then packing lists. """
   
-  """
+  # XXX
+  def playSequence(self, sequence_string) :
+    sequence_list = SequenceList()
+    sequence_list.addSequenceString(sequence_string)
+    sequence_list.play(self)
+ 
+  RUN_ALL_TESTS = 1
 
-  # Different variables used for this test
-  run_all_test = 0
-  source_company_id = 'Nexedi'
-  destination_company_id = 'MyOrg'
-  account1 = 'prestation_service'
-  account2 = 'creance_client'
-  account3 = 'tva_collectee_196'
-  account1_mirror = 'fourniture_service' # Not used
-  account2_mirror = 'dette_client'       # Not used
-  account3_mirror = 'tva_collectee_196'  # Not used
-  quantity1 = 3.0
-  price1 = 72.0
-  total_price1 = 216.0
+  sale_invoice_portal_type      = 'Sale Invoice Transaction'
+  sale_invoice_line_portal_type = 'Sale Invoice Line' 
+  sale_invoice_cell_portal_type = 'Invoice Cell'
+
+  default_region = "europe/west/france"
 
   def getTitle(self):
     return "Invoices"
-
-  def getBusinessTemplateList(self):
-    """
-    """
-    return ('erp5_accounting', 'erp5_trade', 'erp5_pdm')
-
-  def enableLightInstall(self):
-    """
-    You can override this. Return if we should do a light install (1) or not (0)
-    """
-    return 1
-
-  def enableActivityTool(self):
-    """
-    You can override this. Return if we should create (1) or not (0) an activity tool
-    """
-    return 1
-
-  def getActivityTool(self):
-    return getattr(self.getPortal(), 'portal_activities', None)
-
-  def getRuleTool(self):
-    return getattr(self.getPortal(), 'portal_rules', None)
-
-  def getWorkflowTool(self):
-    return getattr(self.getPortal(), 'portal_workflow', None)
-
-  def getSaleOrderModule(self):
-    return getattr(self.getPortal(),'sale_order',None)
-
-  def getSalePackingListModule(self):
-    return getattr(self.getPortal(),'sale_packing_list',None)
-
-  def getProductModule(self):
-    return getattr(self.getPortal(),'product',None)
-
-  def getAccountModule(self):
-    return getattr(self.getPortal(),'account',None)
-
-  def getAccountingModule(self):
-    return getattr(self.getPortal(),'accounting',None)
-
-  def getCurrencyModule(self):
-    return getattr(self.getPortal(), 'currency', None)
-
-  def login(self, quiet=0, run=run_all_test):
+  
+  def login(self, quiet=0, run=1):
     uf = self.getPortal().acl_users
-    uf._doAddUser('alex', '', ['Manager'], [])
+    # FIXME: unittest user should not have the Manager role
+    uf._doAddUser('alex', '', ['Manager', 'Assignee', 'Assignor',
+                               'Associate', 'Auditor', 'Author'], [])
     user = uf.getUserById('alex').__of__(uf)
     newSecurityManager(None, user)
+  
+  def createCategories(self):
+    """Create the categories for our test. """
+    TestPackingListMixin.createCategories(self)
+    # create categories
+    for cat_string in self.getNeededCategoryList() :
+      base_cat = cat_string.split("/")[0]
+      path = self.getPortal().portal_categories[base_cat]
+      for cat in cat_string.split("/")[1:] :
+        if not cat in path.objectIds() :
+          path = path.newContent(
+            portal_type = 'Category',
+            id = cat,
+            immediate_reindex = 1 )
+    # check categories have been created
+    for cat_string in self.getNeededCategoryList() :
+      self.assertNotEquals(None,
+                self.getCategoryTool().restrictedTraverse(cat_string),
+                cat_string)
+                
+  def getNeededCategoryList(self):
+    """return a list of categories that should be created."""
+    return ('region/%s' % self.default_region, )
+  
+  def getBusinessTemplateList(self):
+    """ """
+    return TestPackingListMixin.getBusinessTemplateList(self) + (
+              'erp5_accounting',)
 
-  def afterSetUp(self, quiet=1, run=1):
-    """
-    """
-    self.login()
-    # Must add some accounts, accounting transactions, products, etc.
-    account_module = self.getAccountModule()
-    self.accounting_module = self.getAccountingModule()
-    self.currency_module = self.getCurrencyModule()
-    self.organisation_module = self.getOrganisationModule()
-    product_module = self.getProductModule()
-    self.activity_tool = self.getActivityTool()
-    self.catalog_tool = self.getCatalogTool()
-    self.category_tool = self.getCategoryTool()
-    self.simulation_tool = self.getSimulationTool()
-    self.workflow_tool = self.getWorkflowTool()
-    self.portal = self.getPortal()
-    # flush activities
-    get_transaction().commit()
+  def stepTic(self, **kw):
     self.tic()
-    # When using light install, only base categories are created
-    if len(self.category_tool.region.contentValues()) == 0 :
-      self.category_tool.region.newContent(portal_type='Category', id='africa')
-      o = self.category_tool.region.newContent(portal_type='Category', id='europe')
-      o = o.newContent(portal_type='Category', id='west')
-      o.newContent(portal_type='Category', id='france')
 
-      self.category_tool.pcg.newContent(portal_type='Category', id='1')
-
-      self.category_tool.product_line.newContent(portal_type='Category', id='erp5')
-      o = self.category_tool.product_line.newContent(portal_type='Category', id='storever')
-      o.newContent(portal_type='Category', id='barebone')
-      o.newContent(portal_type='Category', id='notebook')
-      o.newContent(portal_type='Category', id='openbrick')
-    # If currency/EUR already exists, it means that the afterSetUp actions were already commited. Then, we just need to link to them.
-    old_euro = getattr( self.currency_module, 'EUR', None)
-    if old_euro is not None :
-      self.invoice_transaction_rule = getattr(self.getRuleTool(), 'default_invoice_transaction_rule')
-      self.predicate_product1 = getattr(self.invoice_transaction_rule, 'product_1')
-      self.predicate_region1 = getattr(self.invoice_transaction_rule, 'region_1')
-      return
-    # Create some currencies
-    euro = self.currency_module.newContent(id='EUR', title='Euro', portal_type='Currency')
-    # Create some accounts
-    account_module.newContent(portal_type='Account',id='prestation_service')
-    account_module.newContent(portal_type='Account',id='creance_client')
-    account_module.newContent(portal_type='Account',id='tva_collectee_196')
-    account_module.newContent(portal_type='Account',id='dette_fournisseur')
-    account_module.newContent(portal_type='Account',id='banques_etablissements_financiers')
-    account_module.newContent(portal_type='Account',id='account1')
-    account_module.newContent(portal_type='Account',id='account2')
-    account_module.newContent(portal_type='Account',id='account3')
-    account_module.newContent(portal_type='Account',id='account4')                          
-    # Create a product
-    product_module = self.getProductModule()
-    product = product_module.newContent(portal_type='Product',id='1', product_line='storever/notebook')
-    product.setPricedQuantity(1.0)
-    product.setBasePrice(self.price1)
-    # Create a destination with region
-    organisation_module = self.getOrganisationModule()
-    organisation = organisation_module.newContent(portal_type='Organisation',id=self.destination_company_id)
-    organisation.newContent(id='default_address', portal_type='Address', region='europe/west/france')
-    organisation = organisation_module.newContent(portal_type='Organisation',id=self.source_company_id)    
-    # Create some predicates
-    self.invoice_transaction_rule = self.getRuleTool().default_invoice_transaction_rule
-    self.invoice_transaction_rule.deleteContent(self.invoice_transaction_rule.contentIds()) # delete anything inside the rule first
-    self.predicate_product1 = self.invoice_transaction_rule.newContent(
-                    id='product_1',
-                    title='product_1',
-                    portal_type='Predicate Group',
-                    string_index='product',
-                    int_index='1', 
-                    membership_criterion_base_category_list=['product_line',], 
-                    membership_criterion_category_list=['product_line/storever/notebook'], 
-                    immediate_reindex=1)
-    self.predicate_region1 = self.invoice_transaction_rule.newContent(
-                    id='region_1',
-                    title='region_1', 
-                    portal_type='Predicate Group', 
-                    string_index='region', 
-                    int_index='1', 
-                    membership_criterion_base_category_list=['destination_region',], 
-                    membership_criterion_category_list=['destination_region/region/europe/west/france'], 
-                    immediate_reindex=1)
-    #self.invoice_transaction_rule.recursiveImmediateReindexObject()
-    # Update the matrix   
+  def stepCreateEntities(self, sequence, **kw) :
+    """Create a vendor and a client. """
+    self.stepCreateOrganisation1(sequence, **kw)
+    sequence.edit(client = sequence.get('organisation'))
+    self.stepCreateOrganisation2(sequence, **kw)
+    vendor = sequence.get('organisation')
+    vendor.setRegion(self.default_region)
+    self.assertNotEquals(vendor.getRegionValue(), None)
+    sequence.edit(vendor = vendor)
+  
+  def stepCreateCurrency(self, sequence, **kw) :
+    """Create a default currency. """
+    currency = self.getCurrencyModule().newContent(
+          portal_type = 'Currency',
+          id = "EUR" )
+    sequence.edit(currency = currency)
+  
+  def stepSetOrderPriceCurrency(self, sequence, **kw) :
+    """Set the price currency of the order. 
     
-    # flush activities
-    get_transaction().commit()
-    self.tic()
+    This step is not necessary. 
+    TODO : - include a test without this step.
+           - include a test with this step late.
+    """
+    currency = sequence.get('currency')
+    order = sequence.get('order')
+    order.setPriceCurrency(currency.getRelativeUrl())
+  
+  def stepCreateSaleInvoiceTransactionRule(self, sequence, **kw) :
+    """Create the rule for accounting. """
+    invoice_rule = self.getPortal().portal_rules.default_invoice_transaction_rule
+    invoice_rule.deleteContent([x.getId() for x in invoice_rule.objectValues()])
+    region_predicate = invoice_rule.newContent(portal_type = 'Predicate')
+    product_line_predicate = invoice_rule.newContent(portal_type = 'Predicate')
+    region_predicate.edit(
+      membership_criterion_base_category_list = ['destination_region'],
+      membership_criterion_category_list =
+                             ['destination_region/region/%s' % self.default_region ],
+      int_index = 1,
+      string_index = 'region'
+    )
+    product_line_predicate.edit(
+      membership_criterion_base_category_list = ['product_line'],
+      membership_criterion_category_list =
+                            ['product_line/apparel'],
+      int_index = 1,
+      string_index = 'product'
+    )
+    invoice_rule.updateMatrix()
+    # TODO create Accounts and cell ?
     
-    self.invoice_transaction_rule.updateMatrix()
-          
-    # add some values to the transaction lines in the accounting rule cell
-    cell_list = self.invoice_transaction_rule.contentValues(filter={'portal_type':'Accounting Rule Cell'})   
-    self.assertEqual(len(cell_list), 1) # Check that the rule is here
-    self.product1_region1_cell = getattr(self.invoice_transaction_rule, 'vat_per_region_0_0', None)
-    self.failUnless(self.product1_region1_cell != None)
-
-    self.product1_region1_line1 = getattr(self.product1_region1_cell, 'income', None)
-    self.failUnless(self.product1_region1_line1 != None)
-    self.product1_region1_line1.edit(title='income', source='account/prestation_service', destination='account/account1', quantity=1)
+  def modifyPackingListState(self, transition_name, sequence):
+    """ calls the workflow for the packing list """
+    packing_list = sequence.get('packing_list')
+    packing_list.portal_workflow.doActionFor(packing_list,
+          transition_name, wf_id='packing_list_workflow')
+  
+  def stepSetReadyPackingList(self, sequence=None, sequence_list=None, **kw):
+    """ set the Packing List as Ready. This must build the invoice. """
+    self.modifyPackingListState('set_ready_action', sequence=sequence)
+    packing_list = sequence.get('packing_list')
+    self.assertEquals(packing_list.getSimulationState(), 'ready')
 
-    self.product1_region1_line2 = getattr(self.product1_region1_cell, 'receivable', None)
-    self.failUnless(self.product1_region1_line2 != None)
-    self.product1_region1_line2.edit(title='receivable', source='account/prestation_service', destination='account/account2', quantity=0.5)
+  def stepStartPackingList(self, sequence=None, sequence_list=None, **kw):
+    self.modifyPackingListState('start_action', sequence=sequence)
+    packing_list = sequence.get('packing_list')
+    self.assertEquals(packing_list.getSimulationState(), 'started')
     
-    # flush activities
-    get_transaction().commit()
-    self.tic()
-
-  def stepTic(self, **kw):
-    self.tic()
-
-  def stepFirstCheck(self,sequence=None, sequence_list=None,**kw):
-    """
-    Do some basics checking
-    """
-    # Check the default delivery rule
-    portal_rules = self.getRuleTool()
-    self.failUnless('default_order_rule' in portal_rules.objectIds())
-    # Check defaults accounts
-    account_module = self.getAccountModule()
-    self.failUnless(self.account1 in account_module.objectIds())
-    self.failUnless(self.account2 in account_module.objectIds())
-    self.failUnless(self.account3 in account_module.objectIds())
-    # Check product 
-    product_module = self.getProductModule()
-    product = product_module['1']
-    sequence.edit(product=product)
-    self.assertEquals(product.getBasePrice(),self.price1)
+  def stepStopPackingList(self, sequence=None, sequence_list=None, **kw):
+    self.modifyPackingListState('stop_action', sequence=sequence)
+    packing_list = sequence.get('packing_list')
+    self.assertEquals(packing_list.getSimulationState(), 'stopped')
+    
+  def stepCancelPackingList(self, sequence=None, sequence_list=None, **kw):
+    self.modifyPackingListState('cancel_action', sequence=sequence)
+    packing_list = sequence.get('packing_list')
+    self.assertEquals(packing_list.getSimulationState(), 'cancelled')
 
-  def stepCreateSaleOrder(self,sequence=None, sequence_list=None,**kw):
-    """
+  def stepPackingListSimulation(self, sequence=None, sequence_list=None, **kw):
+    """ checks that simulation movements related to the packing list are OK """
+    packing_list = sequence.get('packing_list')
+    order = sequence.get('order')
+    order_root_applied_rule = order.getCausalityRelatedValueList(
+                                  portal_type = 'Applied Rule')[0]
+
+    # check simulation movements from this packing list
+    for movement in packing_list.getMovementList() :
+      simulation_movement_list = movement.getOrderRelatedValueList()
+      self.assertNotEquals(len(simulation_movement_list), 0)
+      total_quantity = 0
+      for simulation_movement in simulation_movement_list :
+        total_quantity += simulation_movement.getQuantity()
+        # check that those movements come from the same root applied
+        # rule than the order.
+        self.assertEquals( simulation_movement.getRootAppliedRule(),
+                           order_root_applied_rule)
+      self.assertEquals(total_quantity, movement.getQuantity())
+    
+  def stepCheckInvoiceBuilding(self, sequence=None, sequence_list=None, **kw):
+    """ checks that the invoice is built with the default_invoice_builder """
+    packing_list = sequence.get('packing_list')
+    related_applied_rule_list = packing_list.getCausalityRelatedValueList(
+                                   portal_type=self.applied_rule_portal_type)
+    related_invoice_list = packing_list.getCausalityRelatedValueList(
+                                   portal_type=self.sale_invoice_portal_type)
+
+    packing_list_building_state = 'started'
+    packing_list_state = packing_list.getSimulationState()
+    if packing_list_state != packing_list_building_state :
+      self.assertEquals(0, len(related_invoice_list))
+    else:
+      self.assertEquals(1, len(related_invoice_list))
+
+      invoice = related_invoice_list[0].getObject()
+      self.failUnless(invoice is not None)
+      # Invoices created by Delivery Builder are in planned state
+      self.assertEquals(invoice.getSimulationState(), 'planned')
+      
+      # Get the list of simulation movements of packing list ...
+      packing_list_simulation_movement_list = []
+      for packing_list_movement in packing_list.getMovementList():
+           packing_list_simulation_movement_list.extend(
+                packing_list_movement.getDeliveryRelatedValueList())
+      # ... invoice simulation movement are their childrens.
+      simulation_movement_list = []
+      for p_l_simulation_movement in packing_list_simulation_movement_list :
+        for applied_rule in p_l_simulation_movement.objectValues() :
+          simulation_movement_list.extend(applied_rule.objectValues())
+      
+      # First, test if each Simulation Movement is related to an
+      # Invoice Movement
+      invoice_relative_url = invoice.getRelativeUrl()
+      for simulation_movement in simulation_movement_list:
+        invoice_movement_list = simulation_movement.getDeliveryValueList()
+        self.assertEquals(len(invoice_movement_list), 1)
+        invoice_movement = invoice_movement_list[0]
+        self.failUnless(invoice_movement is not None)
+        self.assert_(invoice_movement.getRelativeUrl().\
+                              startswith(invoice_relative_url))
+
+      # Then, test if each Invoice movement is equals to the sum of somes
+      # Simulation Movemen
+      for invoice_movement in invoice.getMovementList(portal_type = [
+                          self.sale_invoice_cell_portal_type,
+                          self.sale_invoice_line_portal_type]) :
+        related_simulation_movement_list = invoice_movement.\
+                 getDeliveryRelatedValueList(portal_type='Simulation Movement')
+        quantity = 0
+        total_price = 0
+        invoice_movement_quantity = invoice_movement.getQuantity()
+        for related_simulation_movement in related_simulation_movement_list:
+          quantity += related_simulation_movement.getQuantity()
+          total_price += related_simulation_movement.getPrice() *\
+                         related_simulation_movement.getQuantity()
+          # Test resource
+          self.assertEquals(invoice_movement.getResource(), \
+                            related_simulation_movement.getResource())
+          # Test resource variation
+          self.assertEquals(invoice_movement.getVariationText(), \
+                            related_simulation_movement.getVariationText())
+          self.assertEquals(invoice_movement.getVariationCategoryList(), \
+                        related_simulation_movement.getVariationCategoryList())
+          # Test acquisition
+          self.checkAcquisition(invoice_movement,
+                                related_simulation_movement)
+          # Test delivery ratio
+          self.assertEquals(related_simulation_movement.getQuantity() /\
+                            invoice_movement_quantity, \
+                            related_simulation_movement.getDeliveryRatio())
+
+        self.assertEquals(quantity, invoice_movement.getQuantity())
+        # Test price
+        self.assertEquals(total_price / quantity, invoice_movement.getPrice())
+
+      sequence.edit(invoice = invoice)
+      
+      # Test causality
+      self.assertEquals(len(invoice.getCausalityValueList(
+                      portal_type = self.packing_list_portal_type)), 1)
+      self.assertEquals(invoice.getCausalityValue(), packing_list)
+      
+      # Finally, test getTotalQuantity and getTotalPrice on Invoice
+      self.assertEquals(packing_list.getTotalQuantity(),
+                        invoice.getTotalQuantity())
+      self.assertEquals(packing_list.getTotalPrice(),
+                        invoice.getTotalPrice())
+
+
+  def stepCreateSimpleSaleOrder(self, sequence, **kw):
+    """ create the Order for our test.
+      It contains one line :
+        resource : product_module/notebook
+        quantity : 10
+        price : 100
     """
+    source_section = sequence.get('source_section')
+    source = sequence.get('source')
+    destination_section = sequence.get('destination_section')
+    destination = sequence.get('destination')
+    product = sequence.get('product')
+    
     order_module = self.getSaleOrderModule()
     order = order_module.newContent(portal_type='Sale Order')
     order.setStartDate(DateTime('2004-11-20'))
     order.setStopDate(DateTime('2004-11-24'))
-    destination_organisation = self.getOrganisationModule()[self.destination_company_id]
-    order.setDestinationValue(destination_organisation)
-    source_organisation = self.getOrganisationModule()[self.source_company_id]
-    order.setSourceValue(source_organisation)
-    line1 = order.newContent(portal_type='Sale Order Line',id='1')
-    product = sequence.get('product')
-    line1.setResourceValue(product)
-    line1.setQuantity(self.quantity1)
-    line1.setPrice(self.price1)
-    sequence.edit(order=order)
-    self.assertEquals(line1.getTotalPrice(),self.total_price1)
-
-  def stepCreateOrderRule(self,sequence=None, sequence_list=None,**kw):
-    """
-    """
-    order = sequence.get('order')
-    order.plan() # Orders should be planned in order to be simulated
-    order._createOrderRule()
-
-  def stepCreateDeliveryRule(self,sequence=None, sequence_list=None,**kw):
-    """
-    Only if we want a packing list with no order
-    """
-    packing_list = sequence.get('packing_list')
-    packing_list._createDeliveryRule()
-
-  def stepCheckOrderRule(self,sequence=None, sequence_list=None,**kw):
+    order.setDestinationValue(destination)
+    order.setDestinationSectionValue(destination_section)
+    order.setSourceValue(source)
+    order.setSourceSectionValue(source_section)
+    order_line = order.newContent(portal_type = 'Sale Order Line', id = '1')
+    order_line.setResourceValue(product)
+    order_line.setQuantity(10)
+    order_line.setPrice(100)
+    sequence.edit(
+      order = order,
+      order_line = order_line,
+      order_line_list = [order_line])
+    self.assertEquals(order_line.getTotalPrice(), 10*100)
+
+  def stepCheckOrderRule(self, sequence=None, sequence_list=None, **kw):
     order = sequence.get('order')
     simulation_tool = self.getSimulationTool()
     # Check that there is an applied rule for our packing list
-    rule_list = [x for x in simulation_tool.objectValues() if x.getCausalityValue()==order]
-    self.assertEquals(len(rule_list),1)
-    order_rule = rule_list[0]
-    #order_rule.expand()
-    #ZopeTestCase._print('\norder_rule %s' % str(order_rule.getCausality()))
-    
-    sequence.edit(order_rule=order_rule)
+    rule_list = [x for x in simulation_tool.objectValues()
+                            if x.getCausalityValue()==order]
+    self.assertNotEquals(len(rule_list), 0)
+    sequence.edit(order_rule_list = rule_list)
+    # TODO
+    return 
+    """
     rule_line_list = order_rule.objectValues()
     order_line_list = order.objectValues()
-    self.assertEquals(len(order_line_list,),len(rule_line_list))
-    self.assertEquals(1,len(rule_line_list))
+    self.assertEquals(len(order_line_list), len(rule_line_list))
+    self.assertEquals(1, len(rule_line_list))
     rule_line = rule_line_list[0]
     sequence.edit(order_rule_line=rule_line)
     order_line = order_line_list[0]
-    self.assertEquals(rule_line.getQuantity(),self.quantity1)
-    self.assertEquals(rule_line.getPrice(),self.price1)
-    self.assertEquals(rule_line.getOrderValue(),order_line)
-    self.assertEquals(rule_line.getStartDate(),order_line.getStartDate())
-    self.assertEquals(rule_line.getStopDate(),order_line.getStopDate())
-    self.assertEquals(rule_line.getPortalType(),'Simulation Movement')
-    self.assertEquals(rule_line.getResourceValue(),order_line.getResourceValue())
-
-  def stepCheckInvoicingRule(self,sequence=None, sequence_list=None,**kw):
-    order_rule_line = sequence.get('order_rule_line')
-    invoicing_rule_list = order_rule_line.objectValues()
-    self.assertEquals(len(invoicing_rule_list),1)
-    invoicing_rule = invoicing_rule_list[0]
-    sequence.edit(invoicing_rule=invoicing_rule)
-    self.assertEquals(invoicing_rule.getSpecialiseId(),'default_invoicing_rule')
-    self.assertEquals(invoicing_rule.getPortalType(),'Applied Rule')
-    rule_line_list = invoicing_rule.objectValues()
-    self.assertEquals(len(rule_line_list),1)
-    rule_line = rule_line_list[0]
-    sequence.edit(invoicing_rule_line=rule_line)
-    product = sequence.get('product')
-    self.assertEquals(rule_line.getQuantity(),self.quantity1)
-    self.assertEquals(rule_line.getPrice(),self.price1)
-    self.assertEquals(rule_line.getPortalType(),'Simulation Movement')
-    self.assertEquals(rule_line.getResourceValue(), product)
+    self.assertEquals(rule_line.getQuantity(), 10)
+    self.assertEquals(rule_line.getPrice(), 100)
+    self.assertEquals(rule_line.getOrderValue(), order_line)
+    self.assertEquals(rule_line.getStartDate(), order_line.getStartDate())
+    self.assertEquals(rule_line.getStopDate(), order_line.getStopDate())
+    self.assertEquals(rule_line.getPortalType(), 'Simulation Movement')
+    self.assertEquals(rule_line.getResourceValue(),
+                      order_line.getResourceValue())
+    """
     
-
-  def stepCheckDeliveryRule(self,sequence=None, sequence_list=None,**kw):
+  def stepCheckInvoicingRule(self, sequence=None, sequence_list=None, **kw):
+    """ Checks that the invoicing rule is applied and its values are
+        correct. """
+    order_rule_list = sequence.get('order_rule_list')
+    for order_rule in order_rule_list :
+      for order_simulation_movement in order_rule.objectValues() :
+        invoicing_rule_list = order_simulation_movement.objectValues()
+        self.assertEquals(len(invoicing_rule_list), 1)
+        invoicing_rule = invoicing_rule_list[0]
+        sequence.edit(invoicing_rule = invoicing_rule)
+        self.assertEquals(invoicing_rule.getSpecialiseId(),
+                         'default_invoicing_rule')
+        self.assertEquals(invoicing_rule.getPortalType(),
+                         'Applied Rule')
+    
+        simulation_movement_list = invoicing_rule.objectValues()
+        self.assertNotEquals(len(simulation_movement_list), 0)
+        for simulation_movement in simulation_movement_list :
+          resource = sequence.get('resource')
+          self.assertEquals(simulation_movement.getPortalType(),
+                            'Simulation Movement')
+          self.assertEquals(simulation_movement.getResourceValue(),
+                            resource)
+          # TODO: What is the invoice dates supposed to be ?
+          # is this done through profiles ?
+          self.assertEquals(simulation_movement.getStartDate(),
+                     sequence.get('order').getStartDate())
+          self.assertEquals(simulation_movement.getStopDate(),
+                      sequence.get('order').getStopDate())
+          
+  def stepCheckDeliveryRuleForDeferred(
+                      self, sequence=None, sequence_list=None, **kw):
+    """ Checks that a delivery rule has been created when we took 'split
+        and defer' decision on the divergeant Packing List. """
+  
+  def stepCheckDeliveryRuleIsEmpty(
+                      self, sequence=None, sequence_list=None, **kw):
+    """ Checks that an empty delivery rule is created for the
+        convergeant Packing List"""
     packing_list = sequence.get('packing_list')
     self.failUnless(packing_list is not None)
     simulation_tool = self.getSimulationTool()
     # Check that there is an applied rule for our packing list
-    rule_list = [x for x in simulation_tool.objectValues() if x.getCausalityValue()==packing_list]
+    rule_list = [x for x in simulation_tool.objectValues()
+                          if x.getCausalityValue()==packing_list]
     self.assertEquals(len(rule_list),1)
     packing_list_rule = rule_list[0]
     sequence.edit(packing_list_rule=packing_list_rule)
     rule_line_list = packing_list_rule.objectValues()
     packing_list_line_list = packing_list.objectValues()
-    self.assertEquals(len(packing_list_line_list,),len(rule_line_list))
-    self.assertEquals(1,len(rule_line_list))
+    self.assertEquals(len(packing_list_line_list),
+                      len(rule_line_list))
+    self.assertEquals(1, len(rule_line_list))
     rule_line = rule_line_list[0]
     packing_list_line = packing_list_line_list[0]
-    self.assertEquals(rule_line.getQuantity(),self.quantity1)
-    self.assertEquals(rule_line.getPrice(),self.price1)
-    self.assertEquals(rule_line.getDeliveryValue(),packing_list_line)
-    self.assertEquals(rule_line.getStartDate(),packing_list_line.getStartDate())
-    self.assertEquals(rule_line.getStopDate(),packing_list_line.getStopDate())
-    self.assertEquals(rule_line.getPortalType(),'Simulation Movement')
-
-  def stepCheckInvoiceTransactionRule(self, sequence=None, sequence_list=None, **kw) :
-    invoicing_rule_line = sequence.get('invoicing_rule_line')
-    
-    
-    invoice_transaction_rule_list = invoicing_rule_line.objectValues()    
-    self.assertEquals(invoicing_rule_line.getDestinationRegion(),'region/europe/west/france')    
-    self.assertEquals(len(invoice_transaction_rule_list),1)
-    invoice_transaction_rule = invoice_transaction_rule_list[0]
-    sequence.edit(invoice_transaction_rule=invoice_transaction_rule)
-    self.assertEquals(invoice_transaction_rule.getSpecialiseId(),'default_invoice_transaction_rule')
-    self.assertEquals(invoice_transaction_rule.getPortalType(),'Applied Rule')
-    rule_line_list = invoice_transaction_rule.objectValues()
-    self.assertEquals(len(rule_line_list),3)
-    for rule_line in rule_line_list :
-      if rule_line.getId() == 'income' :
-        self.assertEquals(rule_line.getSourceValue(), self.getAccountModule()['prestation_service'])
-        self.assertEquals(rule_line.getDestinationValue(), self.getAccountModule()['account1'])
-        self.assertEquals(rule_line.getPortalType(),'Simulation Movement')
-        self.assertEquals(rule_line.getQuantity(), 3 * 72 * 1)
-      elif rule_line.getId() == 'receivable' :
-        self.assertEquals(rule_line.getSourceValue(), self.getAccountModule()['prestation_service'])
-        self.assertEquals(rule_line.getDestinationValue(), self.getAccountModule()['account2'])
-        self.assertEquals(rule_line.getPortalType(),'Simulation Movement')
-        self.assertEquals(rule_line.getQuantity(), 3 * 72 * 0.5)
-        sequence.edit(invoice_transaction_rule_line_revceivable=rule_line)
-      elif rule_line.getId() == 'collected_vat' :
-        self.assertEquals(rule_line.getSourceValue(), self.getAccountModule()['tva_collectee_196']) # this is defined in SaleInvoiceTransaction_init in ERP5 skins.
-      else :
-        raise self.failureException, 'Unknown movement : %s' % repr(rule_line)
-
-  def stepCheckPaymentRule(self, sequence=None, sequence_list=None, **kw) :
-    invoice_transaction_rule_line_revceivable = sequence.get('invoice_transaction_rule_line_revceivable')
-    payment_rule_list = invoice_transaction_rule_line_revceivable.objectValues()
-    self.assertEquals(len(payment_rule_list),1)
-    payment_rule = payment_rule_list[0]
-    sequence.edit(payment_rule=payment_rule)
-    self.assertEquals(payment_rule.getSpecialiseId(),'default_payment_rule')
-    self.assertEquals(payment_rule.getPortalType(),'Applied Rule')
-    rule_line_list = payment_rule.objectValues()
-    self.assertEquals(len(rule_line_list),2)
-    for rule_line in rule_line_list :
-      if rule_line.getId() == 'receivable' :
-        self.assertEquals(rule_line.getPortalType(),'Simulation Movement')
-        self.assertEquals(rule_line.getQuantity(), 0 - invoice_transaction_rule_line_revceivable.getQuantity())
-        sequence.edit(payment_rule_line_receivable=rule_line)
-      elif rule_line.getId() == 'bank' :
-        self.assertEquals(rule_line.getPortalType(),'Simulation Movement')
-        self.assertEquals(rule_line.getQuantity(), invoice_transaction_rule_line_revceivable.getQuantity())
-        sequence.edit(payment_rule_line_bank=rule_line)
-      else :
-        raise self.failureException, 'Unknown movement : %s' % repr(rule_line)
-
-  def stepBuildDeliveryList(self,sequence=None, sequence_list=None,**kw):
-    """
-    """
-    order = sequence.get('order')
-
-    # It should be in a script inside the workflow
-    order.buildDeliveryList()
-
-  def stepBuildInvoiceList(self,sequence=None, sequence_list=None,**kw):
-    """
-    """
-    packing_list = sequence.get('packing_list')
+    self.assertEquals(rule_line.getQuantity(), 10)
+    self.assertEquals(rule_line.getPrice(), 100)
+    self.assertEquals(rule_line.getDeliveryValue(),
+                      packing_list_line)
+    self.assertEquals(rule_line.getStartDate(),
+                      packing_list_line.getStartDate())
+    self.assertEquals(rule_line.getStopDate(),
+                      packing_list_line.getStopDate())
+    self.assertEquals(rule_line.getPortalType(),
+                      'Simulation Movement')
 
-    # It should be in a script inside the workflow
-    packing_list.buildInvoiceList()
-
-  def stepBuildInvoiceTransactionList(self, sequence=None, sequence_list=None, **kw) :
-    invoice = sequence.get('invoice')
-
-    # It should be in a script inside the workflow
-    invoice.buildInvoiceTransactionList()    
-
-  def stepBuildPaymentTransactionList(self, sequence=None, sequence_list=None, **kw) :
-    invoice = sequence.get('invoice')
-
-    # It should be in a script inside the workflow
-    invoice.buildPaymentTransactionList()
 
   def stepCheckPackingList(self,sequence=None, sequence_list=None,**kw):
-    """
-    """
+    """  """
     packing_list_module = self.getSalePackingListModule()
     order_rule = sequence.get('order_rule')
     order = sequence.get('order')
@@ -463,119 +432,158 @@ class TestInvoice(ERP5TypeTestCase):
     for o in packing_list_module.objectValues():
       if o.getCausalityValue() == order:
         sale_packing_list_list.append(o)
-    self.assertEquals(len(sale_packing_list_list),1)
+    self.assertEquals(len(sale_packing_list_list), 1)
     sale_packing_list = sale_packing_list_list[0]
     sale_packing_list_line_list = sale_packing_list.objectValues()
     self.assertEquals(len(sale_packing_list_line_list),1)
     sale_packing_list_line = sale_packing_list_line_list[0]
-    product = sequence.get('product')
-    self.assertEquals(sale_packing_list_line.getResourceValue(),product)
-    self.assertEquals(sale_packing_list_line.getPrice(),self.price1)
-    LOG('sale_packing_list_line.showDict()',0,sale_packing_list_line.showDict())
-    self.assertEquals(sale_packing_list_line.getQuantity(),self.quantity1)
-    self.assertEquals(sale_packing_list_line.getTotalPrice(),self.total_price1)
-    sequence.edit(packing_list=sale_packing_list)
-
-
-  def stepCheckInvoice(self,sequence=None, sequence_list=None,**kw):
-    """
-    """
+    product = sequence.get('resource')
+    self.assertEquals(sale_packing_list_line.getResourceValue(),
+                      product)
+    self.assertEquals(sale_packing_list_line.getPrice(),
+                      self.price1)
+    LOG('sale_packing_list_line.showDict()',0,
+          sale_packing_list_line.showDict())
+    self.assertEquals(sale_packing_list_line.getQuantity(),
+                      self.quantity1)
+    self.assertEquals(sale_packing_list_line.getTotalPrice(),
+                      self.total_price1)
+    sequence.edit(packing_list = sale_packing_list)
+
+  def stepCheckInvoice(self,sequence=None, sequence_list=None, **kw):
+    """ checks invoice properties are well set. """
+    # XXX need to clear the accounting module.
     accounting_module = self.getAccountingModule()
-    #invoicing_rule = sequence.get('invoicing_rule')
     sale_invoice_transaction_list = accounting_module.objectValues()
-    #for o in accounting_module.objectValues():
-      #if invoicing_rule.getDeliveryValue() == o:
-        #sale_invoice_transaction_list.append(o)
     self.assertEquals(len(sale_invoice_transaction_list),1)
+    packing_list = sequence.get("packing_list")
+    
     sale_invoice = sale_invoice_transaction_list[0]
     sequence.edit(invoice=sale_invoice)
-    sale_invoice_line_list = sale_invoice.contentValues(filter={'portal_type':'Invoice Line'})
-    LOG('IL', 0, repr([[i, i.getQuantity(), i.getPrice()] for i in sale_invoice_line_list]))
+    sale_invoice_line_list = sale_invoice.contentValues(
+                filter={'portal_type':'Invoice Line'})
     self.assertEquals(len(sale_invoice_line_list),1)
     sale_invoice_line = sale_invoice_line_list[0]
     sequence.edit(invoice_line=sale_invoice_line)
-    product = sequence.get('product')
-    self.assertEquals(sale_invoice_line.getResourceValue(),product)
-    self.assertEquals(sale_invoice_line.getPrice(),self.price1)
-    self.assertEquals(sale_invoice_line.getQuantity(),self.quantity1)
-    self.assertEquals(sale_invoice_line.getTotalPrice(),self.total_price1)
-    LOG('ILR', 0, sale_invoice_line.getDeliveryRelatedValueList())
-
-
-  def stepCheckInvoiceTransaction(self,sequence=None, sequence_list=None,**kw):
-    """
-    """
+    product = sequence.get('resource')
+    self.assertEquals(sale_invoice_line.getResourceValue(), product)
+    self.assertEquals(sale_invoice_line.getPrice(), self.price1)
+    self.assertEquals(sale_invoice_line.getQuantity(), self.quantity1)
+    self.assertEquals(sale_invoice_line.getTotalPrice(), self.total_price1)
+    self.assertEquals(sale_invoice.getCausalityValue(), packing_list)
+    
+  def stepRebuildAndCheckNothingIsCreated(self, sequence=None,
+                                           sequence_list=None, **kw):
+    """Rebuilds with sale_invoice_builder and checks nothing more is
+    created. """
+    return 'TODO' #XXX
     accounting_module = self.getAccountingModule()
     sale_invoice_transaction_list = accounting_module.objectValues()
-    self.assertEquals(len(sale_invoice_transaction_list),1)
-    sale_invoice = sale_invoice_transaction_list[0]
-    sale_invoice_line_list = sale_invoice.contentValues(filter={'portal_type':'Sale Invoice Transaction Line'})
-    LOG('SITL', 0, repr([[i, i.getQuantity(), i.getPrice()] for i in sale_invoice_line_list]))
-    self.assertEquals(len(sale_invoice_line_list),3)
-
-    for transaction_line in sale_invoice_line_list :
-      if transaction_line.getId() == 'income' :
-        self.assertEquals(transaction_line.getSourceValue(), self.getAccountModule()['prestation_service'])
-        self.assertEquals(transaction_line.getDestinationValue(), self.getAccountModule()['account1'])
-        self.assertEquals(transaction_line.getQuantity(), 3 * 72 * 1)
-      elif transaction_line.getId() == 'receivable' :
-        self.assertEquals(transaction_line.getSourceValue(), self.getAccountModule()['prestation_service'])
-        self.assertEquals(transaction_line.getDestinationValue(), self.getAccountModule()['account2'])
-        self.assertEquals(transaction_line.getQuantity(), 3 * 72 * 0.5)
-        sequence.edit(invoice_transaction_line_receivable=transaction_line)
-      elif transaction_line.getId() == 'collected_vat' :
-        simulation_movement = transaction_line.getDeliveryRelatedValueList()[0].getObject()
-        self.assertEquals(transaction_line.getSourceValue(), self.getAccountModule()['tva_collectee_196']) # this is defined in SaleInvoiceTransaction_init in ERP5 skins.
-      else :
-        raise self.failureException
-
-  def stepCheckPaymentTransaction(self, sequence=None, sequence_list=None, **kw) :
-    """
+    self.assertEquals(len(sale_invoice_transaction_list), 1)
+    #self.getPortal().
+    
+  # default sequence for one line of not varianted resource.
+  PACKING_LIST_DEFAULT_SEQUENCE = """
+      stepCreateSaleInvoiceTransactionRule
+      stepCreateEntities
+      stepCreateCurrency
+      stepCreateOrder
+      stepSetOrderProfile
+      stepSetOrderPriceCurrency
+      stepCreateNotVariatedResource
+      stepTic
+      stepCreateOrderLine
+      stepSetOrderLineResource
+      stepSetOrderLineDefaultValues
+      stepOrderOrder
+      stepTic
+      stepCheckDeliveryBuilding
+      stepConfirmOrder
+      stepTic
+      stepCheckOrderRule
+      stepCheckOrderSimulation
+      stepCheckDeliveryBuilding
+      stepAddPackingListContainer
+      stepAddPackingListContainerLine
+      stepSetContainerLineFullQuantity
+      stepTic
+      stepCheckPackingListIsPacked
     """
-    accounting_module = self.getAccountingModule()
-    payment_transaction_list = accounting_module.contentValues(filter={'portal_type':'Payment Transaction'})
-    self.assertEquals(len(payment_transaction_list),1)
-    payment_transaction = payment_transaction_list[0]
-    payment_transaction_line_list = payment_transaction.objectValues()
-    LOG('ATL', 0, repr([[i, i.getQuantity()] for i in payment_transaction_line_list]))
-    self.assertEquals(len(payment_transaction_line_list),3)
-
-    invoice_transaction_line_receivable = sequence.get('invoice_transaction_line_receivable')
-    for transaction_line in payment_transaction_line_list :
-      
-      if transaction_line.getId() == 'receivable' :
-        self.assertEquals(transaction_line.getSourceValue(), self.getAccountModule()['creance_client'])
-        self.assertEquals(transaction_line.getQuantity(), 0 - invoice_transaction_line_receivable.getQuantity())
-      elif transaction_line.getId() == 'bank' :
-        self.assertEquals(transaction_line.getSourceValue(), self.getAccountModule()['banques_etablissements_financiers'])
-        self.assertEquals(transaction_line.getQuantity(), invoice_transaction_line_receivable.getQuantity())
-      elif transaction_line.getId() == 'payable' :
-        self.assertEquals(transaction_line.getSourceValue(), self.getAccountModule()['dette_fournisseur']) # this is defined in SaleInvoiceTransaction_init in ERP5 skins.
-      else :
-        raise self.failureException
       
-      # Make sure payment and simulation are consistent
-      for simulation_movement in transaction_line.getDeliveryRelatedValueList():
-        self.assertEquals(simulation_movement.getSource(), transaction_line.getSource())            
-        self.assertEquals(simulation_movement.getDestination(), transaction_line.getDestination())            
-        self.assertEquals(simulation_movement.getSourceSection(), transaction_line.getSourceSection())            
-        self.assertEquals(simulation_movement.getDestinationSection(), transaction_line.getDestinationSection())            
-                
-  def testInvoice(self, quiet=0,run=1):
+  def test_SimpleInvoice(self, quiet=0, run=RUN_ALL_TESTS):
+    """Checks that a Simple Invoice is created from a Packing List"""
+    for base_sequence in (TestInvoice.PACKING_LIST_DEFAULT_SEQUENCE, ) :
+      self.playSequence(
+        base_sequence +
+      """
+        stepSetReadyPackingList
+        stepTic
+        stepStartPackingList
+        stepCheckInvoicingRule
+        stepTic
+        stepCheckInvoiceBuilding
+        stepRebuildAndCheckNothingIsCreated
+      """)
+
+  def DISABLEDtest_InvoiceEditPackingListLine(self, quiet=0, run=RUN_ALL_TESTS):
+    """Checks that editing a Packing List Line still creates a correct
+      Invoice"""
+    for base_sequence in (TestInvoice.PACKING_LIST_DEFAULT_SEQUENCE, ) :
+      self.playSequence(
+        base_sequence +
     """
-    We will play many sequences
+      stepEditPackingListLine
+      stepSetReadyPackingList
+      stepTic
+      stepStartPackingList
+      stepCheckInvoicingRule
+      stepTic
+      stepCheckInvoiceBuilding
+      stepRebuildAndCheckNothingIsCreated
+    """)
+
+  def DISABLEDtest_InvoiceDeletePackingListLine(self, quiet=0, run=RUN_ALL_TESTS):
+    """Checks that deleting a Packing List Line still creates a correct
+    Invoice"""
+    for base_sequence in (TestInvoice.PACKING_LIST_DEFAULT_SEQUENCE, ) :
+                # XXX use another sequence that creates 2 lines
+      self.playSequence(
+        base_sequence +
     """
-    sequence_list = SequenceList()
-    # Simple sequence 
-    # ... Fails
-    sequence_string = 'FirstCheck CreateSaleOrder CreateOrderRule Tic' \
-                    + ' CheckOrderRule BuildDeliveryList Tic' \
-                    + ' CheckPackingList CheckInvoicingRule BuildInvoiceList Tic' \
-                    + ' CheckInvoice CheckInvoiceTransactionRule BuildInvoiceTransactionList Tic ' \
-                    + ' CheckInvoiceTransaction CheckPaymentRule BuildPaymentTransactionList Tic' \
-                    + ' CheckPaymentTransaction'
-    sequence_list.addSequenceString(sequence_string)
-
-    sequence_list.play(self)
-
+      stepDeletePackingListLine
+      stepSetReadyPackingList
+      stepTic
+      stepStartPackingList
+      stepCheckInvoicingRule
+      stepTic
+      stepCheckInvoiceBuilding
+      stepRebuildAndCheckNothingIsCreated
+    """)
+
+  def DISABLEDtest_InvoiceAddPackingListLine(self, quiet=0, run=RUN_ALL_TESTS):
+    """Checks that adding a Packing List Line still creates a correct
+    Invoice"""
+    for base_sequence in (TestInvoice.PACKING_LIST_DEFAULT_SEQUENCE, ) :
+                # XXX use another sequence that creates 2 lines
+      self.playSequence(
+        base_sequence +
+    """
+      stepAddPackingListLine
+      stepSetReadyPackingList
+      stepTic
+      stepStartPackingList
+      stepCheckInvoicingRule
+      stepTic
+      stepCheckInvoiceBuilding
+      stepRebuildAndCheckNothingIsCreated
+    """)
+    
+if __name__ == '__main__':
+  framework()
+else:
+  import unittest
+  def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestInvoice))
+    return suite