From 5d10854e41a9c99717fe412255ab3ebb7cae3026 Mon Sep 17 00:00:00 2001
From: Jean-Paul Smets <jp@nexedi.com>
Date: Fri, 23 Jan 2004 16:09:06 +0000
Subject: [PATCH] new

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@298 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 .../PortalSimulation_fixDeliveryRule.py       |  37 ++
 .../PortalSimulation_updateAssetPrice.py      |  33 ++
 .../coramy_mrp/ZeroStock_buildOrderList.py    |  51 +++
 .../skins/coramy_pdm/tissu_list_export.py     |  31 ++
 .../coramy_trade/ContainerLine_zGetTotal.zsql |  21 ++
 .../coramy_trade/Container_oneClicInput.py    | 121 +++++++
 .../Container_oneClicInputForm.form           | 195 +++++++++++
 .../Container_printExtandLabel.py             | 167 +++++++++
 .../coramy_trade/Container_printLabel.py      |  16 +
 .../coramy_trade/Container_sendExtandEdi.py   |  93 +++++
 .../Delivery_zGetNeededCellList.zsql          |  30 ++
 .../coramy_trade/InvoiceLine_priceView.form   | 301 ++++++++++++++++
 .../InvoiceLine_quantityView.form             | 278 +++++++++++++++
 .../skins/coramy_trade/InvoiceLine_view.form  | 331 ++++++++++++++++++
 .../PackingList_getDistinctContainerList.py   |  44 +++
 .../skins/coramy_trade/PlanTransportExtand.py | 111 ++++++
 .../SaleInvoice_updateTransaction.py          |  65 ++++
 .../SalesPackingList_printForm.form           |  41 +++
 ...sales_packing_list_container_list_print.pt | 210 +++++++++++
 19 files changed, 2176 insertions(+)
 create mode 100755 product/Coramy/skins/coramy_mrp/PortalSimulation_fixDeliveryRule.py
 create mode 100755 product/Coramy/skins/coramy_mrp/PortalSimulation_updateAssetPrice.py
 create mode 100755 product/Coramy/skins/coramy_mrp/ZeroStock_buildOrderList.py
 create mode 100755 product/Coramy/skins/coramy_pdm/tissu_list_export.py
 create mode 100755 product/Coramy/skins/coramy_trade/ContainerLine_zGetTotal.zsql
 create mode 100755 product/Coramy/skins/coramy_trade/Container_oneClicInput.py
 create mode 100755 product/Coramy/skins/coramy_trade/Container_oneClicInputForm.form
 create mode 100755 product/Coramy/skins/coramy_trade/Container_printExtandLabel.py
 create mode 100755 product/Coramy/skins/coramy_trade/Container_printLabel.py
 create mode 100755 product/Coramy/skins/coramy_trade/Container_sendExtandEdi.py
 create mode 100755 product/Coramy/skins/coramy_trade/Delivery_zGetNeededCellList.zsql
 create mode 100755 product/Coramy/skins/coramy_trade/InvoiceLine_priceView.form
 create mode 100755 product/Coramy/skins/coramy_trade/InvoiceLine_quantityView.form
 create mode 100755 product/Coramy/skins/coramy_trade/InvoiceLine_view.form
 create mode 100755 product/Coramy/skins/coramy_trade/PackingList_getDistinctContainerList.py
 create mode 100755 product/Coramy/skins/coramy_trade/PlanTransportExtand.py
 create mode 100755 product/Coramy/skins/coramy_trade/SaleInvoice_updateTransaction.py
 create mode 100755 product/Coramy/skins/coramy_trade/SalesPackingList_printForm.form
 create mode 100755 product/Coramy/skins/coramy_trade/sales_packing_list_container_list_print.pt

diff --git a/product/Coramy/skins/coramy_mrp/PortalSimulation_fixDeliveryRule.py b/product/Coramy/skins/coramy_mrp/PortalSimulation_fixDeliveryRule.py
new file mode 100755
index 0000000000..dd061c0e25
--- /dev/null
+++ b/product/Coramy/skins/coramy_mrp/PortalSimulation_fixDeliveryRule.py
@@ -0,0 +1,37 @@
+## Script (Python) "PortalSimulation_fixDeliveryRule"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+delivery_id = {}
+delivery_list = []
+
+for m in context.objectValues():
+  id = '_'.join(m.getId().split('_')[0:4])
+  if m.getDelivery() is not None:
+    delivery = m.getDeliveryValue()
+    delivery_id[id] = m.getDelivery()    
+  else:
+    delivery_list.append(m)
+  m.setOrder(delivery_id[id])
+  print "%s %s %s" % (id, m.getRelativeUrl(), delivery_id[id])
+
+
+# Build deliveries
+movement_group = context.portal_simulation.collectMovement(delivery_list)
+delivery_list = context.portal_simulation.buildDeliveryList(movement_group)
+
+# Change workflow state
+for new_delivery in delivery_list :
+   # Copy local roles
+   for k, v in delivery.get_local_roles():
+     new_delivery.manage_addLocalRoles(k,v)
+   # update the state of the created deliveries to 'confirmed'
+   #new_delivery.confirm()
+   print "Created delivery %s" % new_delivery.getId()
+
+return printed
diff --git a/product/Coramy/skins/coramy_mrp/PortalSimulation_updateAssetPrice.py b/product/Coramy/skins/coramy_mrp/PortalSimulation_updateAssetPrice.py
new file mode 100755
index 0000000000..778e7288c0
--- /dev/null
+++ b/product/Coramy/skins/coramy_mrp/PortalSimulation_updateAssetPrice.py
@@ -0,0 +1,33 @@
+## Script (Python) "PortalSimulation_updateAssetPrice"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+mlist = context.Resource_zGetMovementHistoryList(resource = ["modele/417P401"],
+		variation_text = """coloris/modele/417P401/1_espace_stuc
+taille/enfant/10 ans""",
+		section_category = "group/Coramy",
+		node_category= "site/Stock_PF",
+                strict_membership = 0,
+                simulation_state = ('delivered', 'started', 'stopped', 'invoiced'))
+
+print map(lambda x:x.relative_url, mlist)
+print "next" 
+
+result = context.portal_simulation.updateAssetPrice(
+		"modele/417P401",
+		"""coloris/modele/417P401/1_espace_stuc
+taille/enfant/10 ans""",
+		"group/Coramy",
+		"site/Stock_PF"
+
+	)
+
+for i in result:
+  print ' '.join(map(lambda x:str(x), i))
+
+return printed
diff --git a/product/Coramy/skins/coramy_mrp/ZeroStock_buildOrderList.py b/product/Coramy/skins/coramy_mrp/ZeroStock_buildOrderList.py
new file mode 100755
index 0000000000..27ed12f097
--- /dev/null
+++ b/product/Coramy/skins/coramy_mrp/ZeroStock_buildOrderList.py
@@ -0,0 +1,51 @@
+## Script (Python) "ZeroStock_buildOrderList"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+if 1:
+  # Delete all proposed orders
+  for o in context.portal_catalog(simulation_state="auto_planned", parent_uid=[context.ordre_fabrication.getUid()]) :
+    realo = o.getObject()
+    realo.aq_parent.deleteContent(realo.getId())
+
+  # Empty Zero Stock
+  context.portal_simulation.zero_stock.deleteContent(context.portal_simulation.zero_stock.contentIds())
+
+  # Expand Zero Stock as many times as needed (1 or 2 for the Coramy case)
+  # for i in range(0,1):
+  context.portal_simulation.zero_stock.expand()
+
+# Collect movements in Zero Stock applied rule
+zs_movement_list = context.portal_simulation.zero_stock.contentValues()
+
+# keep only movements with a Modele resource
+movement_list = []
+for movement in zs_movement_list[0:100] :
+  resource_value = movement.getResourceValue()
+  if resource_value is not None:
+    #if resource_value.getPortalType() == 'Modele' :
+    movement_list.append(movement)
+
+# Parse movements into a root group
+root_group = context.portal_simulation.collectMovement(movement_list)
+order_list = context.portal_simulation.buildOrderList(root_group)
+
+# update produced orders
+for order in order_list:
+  order.autoPlan()
+  order.purchase_order_apply_condition()
+
+# reEmpty Zero Stock because we don't want to see the zero_stock quantities in the columns future_stock
+context.portal_simulation.zero_stock.deleteContent(context.portal_simulation.zero_stock.contentIds())
+
+request = context.REQUEST
+redirect_url = '%s/view?%s' % ( context.absolute_url()
+                                , 'portal_status_message=%s+propositions+OF+créés.' % len(order_list)
+                                )
+
+request[ 'RESPONSE' ].redirect( redirect_url )
diff --git a/product/Coramy/skins/coramy_pdm/tissu_list_export.py b/product/Coramy/skins/coramy_pdm/tissu_list_export.py
new file mode 100755
index 0000000000..3180ddeb42
--- /dev/null
+++ b/product/Coramy/skins/coramy_pdm/tissu_list_export.py
@@ -0,0 +1,31 @@
+## Script (Python) "tissu_list_export"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+selection = context.portal_selections.getSelectionFor('tissu_selection',REQUEST=context.REQUEST)
+tissu_list = selection(context=context)
+request = context.REQUEST
+tab = '\t'
+cr = '\n'
+
+export ="Référence"+tab+"Fournisseur"+tab+"Réf. Fournisseur"+tab+"Collection"+tab+"Description"+cr
+for tissu_item in tissu_list:
+  tissu=tissu_item.getObject()
+  if tissu <> None :
+    ligne_tissu = ''
+    ligne_tissu += str(tissu.getId())+tab
+    ligne_tissu += str(tissu.getDefaultSourceTitle())+tab
+    ligne_tissu += str(tissu.getSourceReference())+tab
+    ligne_tissu += str(tissu.getCollection())+tab
+    ligne_tissu += str(tissu.getDescription())+tab
+
+    export += ligne_tissu+cr
+
+request.RESPONSE.setHeader('Content-Type','application/text')
+
+return export
diff --git a/product/Coramy/skins/coramy_trade/ContainerLine_zGetTotal.zsql b/product/Coramy/skins/coramy_trade/ContainerLine_zGetTotal.zsql
new file mode 100755
index 0000000000..6df107da08
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/ContainerLine_zGetTotal.zsql
@@ -0,0 +1,21 @@
+<dtml-comment>
+title:
+connection_id:MySQL
+max_rows:1000
+max_cache:100
+cache_time:0
+class_name:
+class_file:
+</dtml-comment>
+<params>uid</params>
+SELECT 
+	SUM(quantity) AS total_quantity, 
+	SUM(total_price) AS total_price, 
+	SUM(target_quantity) AS target_total_quantity, 
+	SUM(target_total_price) AS target_total_price, 
+	AVG(price) AS average_price
+FROM catalog, movement
+WHERE 
+	catalog.parent_uid = <dtml-sqlvar uid type="int">
+AND	
+	catalog.uid = movement.uid
diff --git a/product/Coramy/skins/coramy_trade/Container_oneClicInput.py b/product/Coramy/skins/coramy_trade/Container_oneClicInput.py
new file mode 100755
index 0000000000..3e2f11cb78
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/Container_oneClicInput.py
@@ -0,0 +1,121 @@
+## Script (Python) "Container_oneClicInput"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=form_id='',selection_index=None,selection_name='',dialog_category='object_exchange',container_type='',gross_weight=0,listbox=None,cancel_url='',next_container_int_index=1
+##title=
+##
+# first we build a dict of desired container lines
+# key of dict : id of resource
+# item of dict : tuples (resource_value, variation_category_list, quantity)
+delivery = context
+next_container_number = next_container_int_index
+
+#desired_lines = {}
+desired_containers = {}
+for relative_url, listitem in listbox.items() :
+  container_index = listitem['container_index']
+  if not container_index in desired_containers.keys() :
+    desired_containers[container_index] = {}
+  other_quantity = listitem['container_quantity']
+  listitem_value = context.restrictedTraverse(relative_url)
+  if listitem_value is not None :
+    if other_quantity :
+      container_quantity = other_quantity
+    else :
+      container_quantity = listitem_value.getQuantity()
+    my_resource = listitem_value.getResourceValue()
+    if my_resource is not None :
+      if my_resource.getRelativeUrl() in desired_containers[container_index].keys() :
+        desired_containers[container_index][my_resource.getRelativeUrl()].append((listitem_value.getVariationCategoryList(), container_quantity))
+      else :
+        desired_containers[container_index][my_resource.getRelativeUrl()] = [(listitem_value.getVariationCategoryList(), container_quantity)]
+
+# we build as many containers as needed
+container_key_list = desired_containers.keys()
+container_key_list.sort()
+for key in container_key_list :
+  desired_lines = desired_containers[key]
+  new_container_id = 'c'+str(next_container_number)
+  # we use container_type to know which are the resource (and variation) of the container
+  container_type_item_list = container_type.split('/')
+  container_resource_url = '/'.join(container_type_item_list[0:2])
+  cointainer_resource_variation = 'variante/'+container_type
+  context.portal_types.constructContent(type_name = 'Container',
+                                        container = delivery,
+                                        int_index = next_container_number,
+                                        serial_number = "%06d%04d" % (int(delivery.getId()),next_container_number),
+                                        resource = container_resource_url,
+                                        variation_base_category_list = ['variante'],
+                                        variation_category_list = [cointainer_resource_variation],
+                                        gross_weight = gross_weight,
+                                        id = new_container_id,
+                                        )
+  next_container_number += 1
+  container = delivery[new_container_id]
+  container.flushActivity(invoke=1)
+
+  # print container label
+  container.Container_printLabel()
+
+  # now build container_lines
+  for key in desired_lines.keys() :
+    new_container_line_id = str(container.generateNewId())
+
+    # compute variation_base_category_list and variation_category_list for this line
+    line_variation_base_category_dict = {}
+    line_variation_category_list = []
+
+    for my_tuple in desired_lines[key] :
+
+      for variation_item in my_tuple[0] :
+        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
+
+      line_variation_base_category_list = line_variation_base_category_dict.keys()
+
+    # construct new content (container_line)
+    my_resource_url = key
+    context.portal_types.constructContent(type_name = 'Container Line',
+                                        container = container,
+                                        id = new_container_line_id,
+                                        resource = my_resource_url,
+                                        variation_base_category_list = line_variation_base_category_list,
+                                        variation_category_list = line_variation_category_list
+                                        )
+    container_line = container[new_container_line_id]
+
+    # set target_quantities in container_lines
+    container_cell_list = container_line.contentValues()
+    for my_tuple in desired_lines[key] :
+      quantity_updated = 0
+      for container_cell in container_cell_list :
+        if container_cell.test(context.asContext(categories=my_tuple[0])) :
+          container_cell.setTargetQuantity(my_tuple[1])
+          container_cell.flushActivity(invoke=1)
+          quantity_updated = 1
+          break
+      # if no cell according to variation_category_list was found
+      # or no variation at all, we update the container_line
+      if not quantity_updated :
+        container_line.setTargetQuantity(my_tuple[1])
+        container_line.flushActivity(invoke=1)
+
+  # update target_quantities on delivery_lines or cells
+  container.edit()
+
+redirect_url = '%s/%s?selection_name=%s&dialog_category=%s&form_id=%s&cancel_url=%s&%s' % ( context.absolute_url()
+                            , 'Container_fastInputForm'
+                            , selection_name
+                            , dialog_category
+                            , form_id
+                            , cancel_url
+                            , 'portal_status_message=%s+colis+créé(s)' % len(container_key_list)
+                            )
+
+context.REQUEST[ 'RESPONSE' ].redirect( redirect_url )
diff --git a/product/Coramy/skins/coramy_trade/Container_oneClicInputForm.form b/product/Coramy/skins/coramy_trade/Container_oneClicInputForm.form
new file mode 100755
index 0000000000..9db969fee4
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/Container_oneClicInputForm.form
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<form>
+  <title>Saisie immédiate</title>
+  <name>Container_oneClicInputForm</name>
+  <action>Container_oneClicInput</action>
+  <enctype>multipart/form-data</enctype>
+  <method>POST</method>
+  <pt>form_dialog</pt>
+
+  <groups>
+    <group>
+      <title>left</title>
+      <fields>
+
+      <field><id>my_container_type</id> <type>ListField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <first_item type="int">0</first_item>
+          <hidden type="int">0</hidden>
+          <items type="list">[('carton A', 'composant/CAame/A'), ('carton B', 'composant/CAame/B'), ('carton C', 'composant/CAame/C'), ('carton D1', 'composant/CAame/D1'), ('carton D2', 'composant/CAame/D2'), ('carton D3', 'composant/CAame/D3')]</items>
+          <required type="int">1</required>
+          <size type="int">1</size>
+          <title>Type de colis</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="unknown_selection">You selected an item that was not in the list.</message>
+        </messages>
+      </field>
+      <field><id>my_gross_weight</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default>0.0</default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">1</required>
+          <title>Poids brut (kg)</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>right</title>
+      <fields>
+
+      <field><id>my_next_container_int_index</id> <type>IntegerField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default>1</default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <end></end>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">1</required>
+          <start></start>
+          <title>Prochain numéro</title>
+        </values>
+        <tales>
+          <default>python:len(here.contentValues(filter={'portal_type':'Container'}))+1</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_integer">You did not enter an integer.</message>
+          <message name="integer_out_of_range">The integer you entered was out of range.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>center</title>
+      <fields>
+
+      </fields>
+    </group>
+    <group>
+      <title>bottom</title>
+      <fields>
+
+      <field><id>listbox</id> <type>ListBox</type>
+        <values>
+          <all_columns type="list">[]</all_columns>
+          <all_editable_columns type="list">[]</all_editable_columns>
+          <alternate_name></alternate_name>
+          <columns type="list">[('resource_title', 'Produit'), ('variation_text', 'Variantes'), ('Amount_getTailleClient', 'Taille client'), ('quantity', 'Quantit\xe9e demand\xe9e'), ('DeliveryCell_getContainedTargetQuantity', 'Quantit\xe9e colis\xe9e'), ('container_quantity', 'Autre quantit\xe9'), ('container_index', 'Ordre colis'), ('quantity_unit', 'Unit\xe9')]</columns>
+          <css_class></css_class>
+          <default></default>
+          <default_params type="list">[]</default_params>
+          <description></description>
+          <domain_root_list type="list">[]</domain_root_list>
+          <domain_tree type="int">0</domain_tree>
+          <editable_columns type="list">[('container_quantity', 'container_quantity'), ('container_index', 'container_index')]</editable_columns>
+          <external_validator></external_validator>
+          <global_attributes type="list">[]</global_attributes>
+          <hidden type="int">0</hidden>
+          <lines type="int">100</lines>
+          <list_action>folder_contents</list_action>
+          <list_method type="method">Delivery_zGetNeededCellList</list_method>
+          <meta_types type="list">[]</meta_types>
+          <portal_types type="list">[]</portal_types>
+          <report_root_list type="list">[]</report_root_list>
+          <report_tree type="int">0</report_tree>
+          <search type="int">0</search>
+          <search_columns type="list">[]</search_columns>
+          <select type="int">0</select>
+          <selection_name>delivery_cells_selection</selection_name>
+          <sort type="list">[('variation_text', 'variation_text')]</sort>
+          <stat_method></stat_method>
+          <title>Contenu du colis</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>hidden</title>
+      <fields>
+
+      <field><id>listbox_container_quantity</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">0</required>
+          <title>Autre quantité</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      <field><id>listbox_container_index</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default>1</default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">5</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">0</required>
+          <title>Ordre colis</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+  </groups>
+</form>
\ No newline at end of file
diff --git a/product/Coramy/skins/coramy_trade/Container_printExtandLabel.py b/product/Coramy/skins/coramy_trade/Container_printExtandLabel.py
new file mode 100755
index 0000000000..c1031316f4
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/Container_printExtandLabel.py
@@ -0,0 +1,167 @@
+## Script (Python) "Container_printExtandLabel"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+from Products.Coramy.MetoAPI import selectMeter, startFormat, setDecoration, setPrintSpeed, setPaperSpeed, setPixel, setTemparature, setNumber, endFormat, printText, printLine, printFrame, setAsdFont
+
+
+def chaine(num, div):
+    case = {
+       10 : 1,
+       100 : 2,
+       1000: 3,
+       10000: 4,
+       100000: 5,
+       1000000: 6
+
+    }       
+    longueur = case[div]
+    #longueur = div / 10
+    tmp = str( int(num) % div)
+
+    result = ''
+    for i in range(0,longueur):
+        result += '0'
+
+    result = result[:-len(tmp)] + tmp
+    return result
+
+
+
+raw_string = ''
+container = context
+
+
+# selecting printer (user dependent)
+local_user = container.portal_membership.getAuthenticatedMember().getUserName()
+if local_user == 'Nicole_Denis' :
+  printer_name = 'Meto_XS40_2'
+elif local_user == 'Christelle_Megret' :
+  printer_name = 'Meto_XS40_3'
+elif local_user == 'Jocelyne_Olejarz' :
+  printer_name = 'Meto_XS40_4'
+elif local_user == 'Nathalie_Wadoux' :
+  printer_name = 'Meto_XS40_5'
+else :
+  printer_name = 'Meto_XS40_2'
+
+delivery = container.aq_parent
+
+# Destination
+client_title = delivery.getDestinationValue(portal_type=['Organisation']).getTitle()
+client_address_items = delivery.getDestinationValue(portal_type=['Organisation']).getDefaultAddress().asText(country='France').split('\n')
+client_address_1 = client_address_items[0]
+if len(client_address_items) > 2 :
+  client_address_2 = client_address_items[1]
+else :
+  client_address_2 = ''
+client_city = client_address_items[len(client_address_items)-1]
+client_zip_code = delivery.getDestinationValue(portal_type=['Organisation']).getDefaultAddress().getZipCode()
+
+# Expediteur
+source_section = delivery.getSourceSectionTitle()
+list = delivery.portal_catalog(Title=source_section, portal_type = 'Organisation')
+if len(list) > 0:
+    expe = list[0].getObject()
+
+    expe_title = expe.getTitle()
+    expe_address_items = expe.getDefaultAddress().asText(country='France').split('\n')
+    expe_address = expe_address_items[0]
+    expe_city = expe_address_items[len(expe_address_items)-1]
+    
+
+# Printing protocol starts here
+# first set some parameters
+raw_string += selectMeter()
+raw_string += setAsdFont()
+#raw_string += setDecoration(1)
+raw_string += startFormat()
+raw_string += setPrintSpeed()
+raw_string += setPaperSpeed()
+raw_string += setTemparature()
+
+
+# then design the label
+# adress
+raw_string += printFrame(1, 29, 41, 35, 99, 5, 5, 10)
+# ref colis
+raw_string += printFrame(1, 29, 8, 35, 33, 5, 5, 10)
+# code produit extand
+raw_string += printFrame(1, 3, 94, 26, 46, 5, 5, 10)
+raw_string += printLine(1, 3, 64, 15, 30, 10)
+# dpt
+raw_string += printFrame(1, 18, 64, 11, 30, 5, 5, 10)
+# expediteur
+raw_string += printFrame(1, 3, 8, 26, 56, 5, 5, 10)
+
+
+# calcul modulo
+#recepisse = str(int(atof(delivery.getId())) % 1000000) + str( container.getIntIndex() % 100  )
+recepisse = chaine( delivery.getId() , 1000000) + chaine( container.getIntIndex() , 100 )
+
+
+case_society = {
+    'BLS':'5433',
+    'Houvenaegel':'1194',
+    'Coramy':'0193' 
+}
+code_client = case_society[ source_section ]
+
+code = '12119591'+code_client+'4012'+recepisse + chaine( container.getGrossWeight() * 10 , 1000  ) + '00' + client_zip_code[:2]
+totpair = int(code[0])
+totimpair = 0
+
+for i in range(15):
+    totimpair += int(code[(2*i)+1])
+    totpair += int(code[(2*i)+2]) 
+
+cal1 = str((totpair * 3) + totimpair)
+digit = str ( 10 - int( cal1[ len(cal1) - 1 ]  ) )
+
+if digit == '10':
+    digit = '0'
+
+code_barre = code+digit
+
+
+
+# code barre
+raw_string += printText(2, "d", 0, 0, 300, 70, 139, code_barre, 10)
+raw_string += printText(2, "9", 0, 0, 300, 65, 111, code_barre, 10)
+
+
+# expediteur
+raw_string += printText(2, "9", 0, 0, 2, 22, 62, "Expediteur", 10)
+raw_string += printText(2, "9", 0, 0, 2, 15, 62, expe_title , 10)
+raw_string += printText(2, "9", 0, 0, 1, 10, 62, expe_address , 10)
+raw_string += printText(2, "9", 0, 0, 1, 4, 62, expe_city , 10)
+
+# destinataire
+raw_string += printText(2, "9", 0, 0, 2, 56, 139, client_title  , 10)
+raw_string += printText(2, "9", 0, 0, 2, 46, 139, client_address_1   , 10)
+raw_string += printText(2, "9", 0, 0, 2, 41, 139, client_address_2  , 10)
+raw_string += printText(2, "9", 0, 0, 3, 31, 139, client_city  , 10)
+
+# colis
+raw_string += printText(2, "9", 0, 0, 1, 58, 38, "Cde "+ delivery.getId() , 10)
+raw_string += printText(2, "9", 0, 0, 1, 41, 38, "Poids "+ str( container.getGrossWeight()) + " Kg", 10)
+raw_string += printText(2, "9", 0, 0, 1, 49, 38, "Colis "+ str(container.getIntIndex()), 10)
+raw_string += printText(2, "9", 0, 0, 1, 32, 38, "Ref. "+ recepisse, 10)
+raw_string += printText(2, "9", 0, 0, 4, 18, 134, "EXTAND", 10)
+raw_string += printText(2, "9", 0, 0, 6, 3, 130, "B12", 10)
+raw_string += printText(2, "9", 0, 0, 5, 17, 86, client_zip_code[:2] , 10)
+
+raw_string += printText(2, "9", 0, 0, 6, 2, 87, context.PlanTransportExtand(client_zip_code[:2])[1] , 10)
+
+# set the quentity to print
+raw_string += setNumber()
+raw_string += endFormat()
+
+# send data to printer
+#return chaine(94.2,10000)
+context.sendRawToCups(printer_name, raw_string)
diff --git a/product/Coramy/skins/coramy_trade/Container_printLabel.py b/product/Coramy/skins/coramy_trade/Container_printLabel.py
new file mode 100755
index 0000000000..dd463cd9eb
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/Container_printLabel.py
@@ -0,0 +1,16 @@
+## Script (Python) "Container_printLabel"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+# print container label
+container = context
+
+if container.aq_parent.getDeliveryMode() == 'Transporteur/Extand' :
+  container.Container_printExtandLabel()
+else :
+  container.Container_printMetoLabel()
diff --git a/product/Coramy/skins/coramy_trade/Container_sendExtandEdi.py b/product/Coramy/skins/coramy_trade/Container_sendExtandEdi.py
new file mode 100755
index 0000000000..5e87bd7e8b
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/Container_sendExtandEdi.py
@@ -0,0 +1,93 @@
+## Script (Python) "Container_sendExtandEdi"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+from DateTime import DateTime
+from string import zfill,ljust
+
+request = context.REQUEST
+msg = ''
+
+
+def decoupe(s,width):
+    from string import ljust
+    import string
+    if len(s) > width:
+        result = s[-width:]
+    else:
+        #result = string.ljust(s,width)
+        result = (' ' * (width-len(s))) + s
+        #return ' '+s
+    return result
+
+def chaine(num, width):
+    s = str(int(num))
+    if len(s) > width:
+        result = s[-width:]
+    else:
+        result = zfill(s,width)
+    return result
+
+
+object_list = context.object_action_list(selection_name='sales_packing_list_selection')
+for delivery in object_list:
+
+    if delivery.getDeliveryMode() == 'Transporteur/Extand':
+
+        # Destination
+        client_title = delivery.getDestinationValue(portal_type=['Organisation']).getTitle()
+        client_address_items = delivery.getDestinationValue(portal_type=['Organisation']).getDefaultAddress().asText(country='France').split('\n')
+        client_address_1 = client_address_items[0]
+        if len(client_address_items) > 2 :
+            client_address_2 = client_address_items[1]
+        else :
+            client_address_2 = ''
+        if len(client_address_items) > 3 :
+            client_address_3 = client_address_items[2]
+        else :
+            client_address_3 = ''
+
+        #client_city = client_address_items[len(client_address_items)-1]
+        client_city = delivery.getDestinationValue(portal_type=['Organisation']).getDefaultAddress().getCity()
+
+        client_zip_code = delivery.getDestinationValue(portal_type=['Organisation']).getDefaultAddress().getZipCode()
+
+        client_tel = delivery.getDestinationValue(portal_type=['Organisation']).getDefaultTelephone().asText().split('\n')[0]
+
+
+     
+
+        plat = context.PlanTransportExtand(client_zip_code[:2])[0] 
+
+
+        container_list = delivery.contentValues(filter={'portal_type':'Container'})
+        for container in container_list:
+
+            #recepisse = "%08d%02d" % (delivery.getId() ,container.getIntIndex())
+            recepisse = chaine( delivery.getId(), 8 )+chaine(str(container.getIntIndex()) , 2)
+
+            case_society = {
+                'BLS':'5433',
+                'Houvenaegel':'1194',
+                'Coramy':'0193' 
+            }
+            source_section = delivery.getSourceSectionTitle()
+            code_client = case_society[ source_section ]
+     
+            msg += "301959"+code_client+recepisse+"0100"+client_zip_code[:2]+chaine(container.getGrossWeight() * 10 , 3)        
+
+            msg += DateTime().strftime("%Y%m%d")
+          
+            num_com_client = delivery.getCausalityValue(portal_type=['Sales Order']).getDestinationReference()
+            msg += plat+"001000"+decoupe( num_com_client ,80)+decoupe(client_title ,32)+decoupe(client_address_1,32)
+            msg += decoupe(client_address_2,32)+decoupe(client_address_3,32)+decoupe(client_zip_code,10)
+            msg += decoupe(client_city,32)+decoupe(client_tel,16)+'\r\n'
+            
+
+request.RESPONSE.setHeader('Content-Type','application/text')
+return msg
diff --git a/product/Coramy/skins/coramy_trade/Delivery_zGetNeededCellList.zsql b/product/Coramy/skins/coramy_trade/Delivery_zGetNeededCellList.zsql
new file mode 100755
index 0000000000..9e589f6a9f
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/Delivery_zGetNeededCellList.zsql
@@ -0,0 +1,30 @@
+<dtml-comment>
+title:
+connection_id:MySQL
+max_rows:1000
+max_cache:100
+cache_time:0
+class_name:ZSQLBrain
+class_file:zsqlbrain.py
+</dtml-comment>
+<params>uid
+sort_on</params>
+SELECT
+	cell.uid, cell.Id, cell.path, cell.Description, movement.variation_text
+FROM
+        catalog as cell, movement
+WHERE
+	movement.delivery_uid = <dtml-sqlvar uid type="int">
+AND
+	movement.uid = cell.uid
+AND
+	movement.is_accountable = 1
+AND
+	movement.quantity <> 0
+AND
+	cell.portal_type <> "Simulation Movement"
+AND
+	cell.portal_type <> "Container"
+<dtml-if sort_on>ORDER BY
+	<dtml-var sort_on>
+</dtml-if>
\ No newline at end of file
diff --git a/product/Coramy/skins/coramy_trade/InvoiceLine_priceView.form b/product/Coramy/skins/coramy_trade/InvoiceLine_priceView.form
new file mode 100755
index 0000000000..3b0ff782a8
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/InvoiceLine_priceView.form
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<form>
+  <title>Ligne de livraison</title>
+  <name>packing_list_line_quantity_view</name>
+  <action>base_edit</action>
+  <enctype>multipart/form-data</enctype>
+  <method>POST</method>
+  <pt>form_view</pt>
+
+  <groups>
+    <group>
+      <title>Default</title>
+      <fields>
+
+      <field><id>my_id</id> <type>StringField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <max_length></max_length>
+          <required type="int">1</required>
+          <title>Ligne n°</title>
+          <truncate type="int">0</truncate>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_long">Too much input was given.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>right</title>
+      <fields>
+
+      </fields>
+    </group>
+    <group>
+      <title>center</title>
+      <fields>
+
+      </fields>
+    </group>
+    <group>
+      <title>bottom</title>
+      <fields>
+
+      <field><id>matrixbox</id> <type>MatrixBox</type>
+        <values>
+          <all_editable_attributes type="list">[('ttarget_quantity', 'target_quantity'), ('quantity', 'quantity'), ('price', 'price'), ('predicate_value', 'predicate_value'), ('variation_category_list', 'variation_category_list')]</all_editable_attributes>
+          <alternate_name></alternate_name>
+          <cell_base_id>movement</cell_base_id>
+          <cell_range type="list">[]</cell_range>
+          <columns type="list">[('None', 'None')]</columns>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <editable_attributes type="list">[('target_quantity', 'target_quantity'), ('quantity', 'quantity'), ('price', 'price'), ('predicate_value', 'predicate_value'), ('variation_category_list', 'variation_category_list')]</editable_attributes>
+          <external_validator></external_validator>
+          <getter_method></getter_method>
+          <global_attributes type="list">[('domain_base_category_list', 'domain_base_category_list'), ('mapped_value_property_list', 'mapped_value_property_list'), ('predicate_operator', 'predicate_operator')]</global_attributes>
+          <hidden type="int">0</hidden>
+          <lines type="list">[('None', 'None')]</lines>
+          <setter_method></setter_method>
+          <tabs type="list">[('None', 'None')]</tabs>
+          <title>matrixbox</title>
+          <update_cell_range type="int">1</update_cell_range>
+        </values>
+        <tales>
+          <columns>python:here.order_line_matrix_item_list(base_category_list = ('taille',), base=1)</columns>
+          <lines>python:here.order_line_matrix_item_list(base_category_list = ('coloris','variante'), base=1)</lines>
+          <tabs>python:here.order_line_matrix_item_list(base_category_list = ('taille','coloris','variante'), base=1, include=0)</tabs>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+        </messages>
+      </field>
+      <field><id>domain_base_category_list</id> <type>LinesField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">[]</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">5</height>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>Valid Domain</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+          <default>here/getVariationBaseCategoryList</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      <field><id>predicate_operator</id> <type>StringField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default>SUPERSET_OF</default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">20</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <required type="int">0</required>
+          <title>Operator</title>
+          <truncate type="int">0</truncate>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_long">Too much input was given.</message>
+        </messages>
+      </field>
+      <field><id>mapped_value_property_list</id> <type>LinesField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">['target_quantity', 'quantity', 'price']</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">5</height>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>Modified categories</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>hidden</title>
+      <fields>
+
+      <field><id>matrixbox_predicate_value</id> <type>LinesField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">[]</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">5</height>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>matrixbox_predicate_value</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+          <default>python:cell_index</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      <field><id>matrixbox_variation_category_list</id> <type>LinesField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">[]</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">5</height>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>matrixbox_predicate_value</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+          <default>python:cell_index</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      <field><id>matrixbox_price</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">0</required>
+          <title>matrixbox_price</title>
+        </values>
+        <tales>
+          <default>python:cell.getProperty('price')</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      <field><id>matrixbox_quantity</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">1</hidden>
+          <required type="int">0</required>
+          <title>matrixbox_quantity</title>
+        </values>
+        <tales>
+          <default>python:cell.getProperty('quantity')</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      <field><id>matrixbox_target_quantity</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">1</hidden>
+          <required type="int">0</required>
+          <title>matrixbox_target_quantity</title>
+        </values>
+        <tales>
+          <default>python:cell.getProperty('target_quantity')</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+  </groups>
+</form>
\ No newline at end of file
diff --git a/product/Coramy/skins/coramy_trade/InvoiceLine_quantityView.form b/product/Coramy/skins/coramy_trade/InvoiceLine_quantityView.form
new file mode 100755
index 0000000000..8b911fd2fa
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/InvoiceLine_quantityView.form
@@ -0,0 +1,278 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<form>
+  <title>Ligne de livraison</title>
+  <name>packing_list_line_quantity_view</name>
+  <action>base_edit</action>
+  <enctype>multipart/form-data</enctype>
+  <method>POST</method>
+  <pt>form_view</pt>
+
+  <groups>
+    <group>
+      <title>Default</title>
+      <fields>
+
+      <field><id>my_id</id> <type>StringField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <max_length></max_length>
+          <required type="int">1</required>
+          <title>Ligne n°</title>
+          <truncate type="int">0</truncate>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_long">Too much input was given.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>right</title>
+      <fields>
+
+      </fields>
+    </group>
+    <group>
+      <title>center</title>
+      <fields>
+
+      </fields>
+    </group>
+    <group>
+      <title>bottom</title>
+      <fields>
+
+      <field><id>matrixbox</id> <type>MatrixBox</type>
+        <values>
+          <all_editable_attributes type="list">[('quantity', 'quantity'), ('price', 'price'), ('predicate_value', 'predicate_value'), ('variation_category_list', 'variation_category_list')]</all_editable_attributes>
+          <alternate_name></alternate_name>
+          <cell_base_id>movement</cell_base_id>
+          <cell_range type="list">[]</cell_range>
+          <columns type="list">[('None', 'None')]</columns>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <editable_attributes type="list">[('quantity', 'quantity'), ('price', 'price'), ('predicate_value', 'predicate_value'), ('variation_category_list', 'variation_category_list')]</editable_attributes>
+          <external_validator></external_validator>
+          <getter_method></getter_method>
+          <global_attributes type="list">[('domain_base_category_list', 'domain_base_category_list'), ('mapped_value_property_list', 'mapped_value_property_list'), ('predicate_operator', 'predicate_operator')]</global_attributes>
+          <hidden type="int">0</hidden>
+          <lines type="list">[('None', 'None')]</lines>
+          <setter_method></setter_method>
+          <tabs type="list">[('None', 'None')]</tabs>
+          <title>matrixbox</title>
+          <update_cell_range type="int">1</update_cell_range>
+        </values>
+        <tales>
+          <columns>python:here.order_line_matrix_item_list(base_category_list = ('taille',), base=1)</columns>
+          <lines>python:here.order_line_matrix_item_list(base_category_list = ('coloris','variante'), base=1)</lines>
+          <tabs>python:here.order_line_matrix_item_list(base_category_list = ('taille','coloris','variante'), base=1, include=0)</tabs>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+        </messages>
+      </field>
+      <field><id>domain_base_category_list</id> <type>LinesField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">[]</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">5</height>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>Valid Domain</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+          <default>here/getVariationBaseCategoryList</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      <field><id>predicate_operator</id> <type>StringField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default>SUPERSET_OF</default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">20</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <required type="int">0</required>
+          <title>Operator</title>
+          <truncate type="int">0</truncate>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_long">Too much input was given.</message>
+        </messages>
+      </field>
+      <field><id>mapped_value_property_list</id> <type>LinesField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">['target_quantity', 'quantity', 'price']</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">5</height>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>Modified categories</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>hidden</title>
+      <fields>
+
+      <field><id>matrixbox_predicate_value</id> <type>LinesField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">[]</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">5</height>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>matrixbox_predicate_value</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+          <default>python:cell_index</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      <field><id>matrixbox_variation_category_list</id> <type>LinesField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">[]</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">5</height>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>matrixbox_predicate_value</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+          <default>python:cell_index</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      <field><id>matrixbox_price</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">1</hidden>
+          <required type="int">0</required>
+          <title>matrixbox_price</title>
+        </values>
+        <tales>
+          <default>python:cell.getProperty('price')</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      <field><id>matrixbox_quantity</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">0</required>
+          <title>matrixbox_quantity</title>
+        </values>
+        <tales>
+          <default>python:cell.getProperty('quantity')</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+  </groups>
+</form>
\ No newline at end of file
diff --git a/product/Coramy/skins/coramy_trade/InvoiceLine_view.form b/product/Coramy/skins/coramy_trade/InvoiceLine_view.form
new file mode 100755
index 0000000000..8e5d735898
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/InvoiceLine_view.form
@@ -0,0 +1,331 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<form>
+  <title>Ligne de livraison</title>
+  <name>sales_packing_list_line_view</name>
+  <action>base_edit</action>
+  <enctype>multipart/form-data</enctype>
+  <method>POST</method>
+  <pt>form_view</pt>
+
+  <groups>
+    <group>
+      <title>left</title>
+      <fields>
+
+      <field><id>my_id</id> <type>StringField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">5</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <max_length></max_length>
+          <required type="int">1</required>
+          <title>Ligne n°</title>
+          <truncate type="int">0</truncate>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_long">Too much input was given.</message>
+        </messages>
+      </field>
+      <field><id>my_description</id> <type>TextAreaField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <height type="int">2</height>
+          <hidden type="int">0</hidden>
+          <max_length></max_length>
+          <max_linelength></max_linelength>
+          <max_lines></max_lines>
+          <required type="int">0</required>
+          <title>Description</title>
+          <width type="int">40</width>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_many_lines">You entered too many lines.</message>
+          <message name="line_too_long">A line was too long.</message>
+          <message name="too_long">You entered too many characters.</message>
+        </messages>
+      </field>
+      <field><id>my_resource_relative_url</id> <type>RelationStringField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <base_category>resource</base_category>
+          <catalog_index>relative_url</catalog_index>
+          <css_class></css_class>
+          <default></default>
+          <default_module>modele</default_module>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">40</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <jump_method>base_jump_relation</jump_method>
+          <max_length></max_length>
+          <portal_type type="list">[('Composant', 'Composant'), ('Tissu', 'Tissu'), ('Modele', 'Modele'), ('Forme', 'Forme'), ('Vetement', 'Vetement'), ('Category', 'Category'), ('Gamme', 'Gamme')]</portal_type>
+          <required type="int">0</required>
+          <title>Produit</title>
+          <truncate type="int">0</truncate>
+          <update_method>base_update_relation</update_method>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_long">Too much input was given.</message>
+        </messages>
+      </field>
+      <field><id>my_variation_base_category_list</id> <type>MultiListField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">[]</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <items type="list">[]</items>
+          <required type="int">0</required>
+          <size type="int">3</size>
+          <title>Axes variation</title>
+        </values>
+        <tales>
+          <items>here/getVariationRangeBaseCategoryList</items>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="unknown_selection">You selected an item that was not in the list.</message>
+        </messages>
+      </field>
+      <field><id>my_variation_category_list</id> <type>MultiListField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default type="list">[]</default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <items type="list">[]</items>
+          <required type="int">0</required>
+          <size type="int">8</size>
+          <title>Variantes</title>
+        </values>
+        <tales>
+          <items>here/getVariationRangeCategoryItemList</items>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="unknown_selection">You selected an item that was not in the list.</message>
+        </messages>
+      </field>
+      <field><id>my_quantity</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">0</required>
+          <title>Quantité par défaut</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>right</title>
+      <fields>
+
+      <field><id>my_quantity_unit</id> <type>ListField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <first_item type="int">0</first_item>
+          <hidden type="int">0</hidden>
+          <items type="list">[]</items>
+          <required type="int">0</required>
+          <size type="int">1</size>
+          <title>Unité</title>
+        </values>
+        <tales>
+          <items>here/getQuantityUnitRangeItemList</items>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="unknown_selection">You selected an item that was not in the list.</message>
+        </messages>
+      </field>
+      <field><id>my_price</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">0</required>
+          <title>Prix par défaut</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      <field><id>spacer</id> <type>StringField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">20</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">1</hidden>
+          <max_length></max_length>
+          <required type="int">0</required>
+          <title> </title>
+          <truncate type="int">0</truncate>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="too_long">Too much input was given.</message>
+        </messages>
+      </field>
+      <field><id>my_total_quantity</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">10</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">1</hidden>
+          <required type="int">0</required>
+          <title>Quantité facturée</title>
+        </values>
+        <tales>
+          <title>python:'Quantité facturée : %.2f' % here.getTotalQuantity()</title>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      <field><id>my_value_added_tax_ratio</id> <type>FloatField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <display_maxwidth></display_maxwidth>
+          <display_width type="int">20</display_width>
+          <external_validator></external_validator>
+          <extra></extra>
+          <hidden type="int">0</hidden>
+          <required type="int">0</required>
+          <title>Taux de TVA</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="not_float">You did not enter a floating point number.</message>
+        </messages>
+      </field>
+      <field><id>my_value_added_tax_recoverable</id> <type>ListField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <external_validator></external_validator>
+          <extra></extra>
+          <first_item type="int">0</first_item>
+          <hidden type="int">0</hidden>
+          <items type="list">[('Non', '0'), ('Oui', '1')]</items>
+          <required type="int">0</required>
+          <size type="int">1</size>
+          <title>Soumis à la TVA</title>
+        </values>
+        <tales>
+          <default>python:str(here.getValueAddedTaxRecoverable())</default>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="unknown_selection">You selected an item that was not in the list.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+    <group>
+      <title>center</title>
+      <fields>
+
+      </fields>
+    </group>
+    <group>
+      <title>bottom</title>
+      <fields>
+
+      </fields>
+    </group>
+    <group>
+      <title>hidden</title>
+      <fields>
+
+      </fields>
+    </group>
+  </groups>
+</form>
\ No newline at end of file
diff --git a/product/Coramy/skins/coramy_trade/PackingList_getDistinctContainerList.py b/product/Coramy/skins/coramy_trade/PackingList_getDistinctContainerList.py
new file mode 100755
index 0000000000..6307c8a530
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/PackingList_getDistinctContainerList.py
@@ -0,0 +1,44 @@
+## Script (Python) "PackingList_getDistinctContainerList"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+# this method return a list of distinct containers
+# it returns a sorted list of tuples (object container, range)
+# the range is a tuple (first number of this container, last number of this container)
+
+delivery = context
+
+container_list = delivery.contentValues(filter={'portal_type' : 'Container'})
+
+ordered_container_list = context.sort_object_list(unordered_list=container_list, sort_order = (('int_index', 'ASC'),) )
+
+final_container_list = []
+if len(container_list) > 0 :
+  container_ref = container_list[0].getContainerText()
+  container_object = container_list[0]
+  first_container = 1
+  last_container = 1
+else :
+  container_ref = ''
+  container_object = None
+  first_container = 0
+  last_container = 0
+
+for container in ordered_container_list :
+  if container.getContainerText() != container_ref :
+    # append tuple in final_container_list
+    final_container_list.append((container_object,(first_container,last_container)))
+    # reset variables
+    container_object = container
+    first_container = container.getIntIndex()
+  last_container = container.getIntIndex()
+
+# append final container in final_container_list 
+final_container_list.append((container_object,(first_container,last_container)))
+
+return final_container_list
diff --git a/product/Coramy/skins/coramy_trade/PlanTransportExtand.py b/product/Coramy/skins/coramy_trade/PlanTransportExtand.py
new file mode 100755
index 0000000000..3ac78722cc
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/PlanTransportExtand.py
@@ -0,0 +1,111 @@
+## Script (Python) "PlanTransportExtand"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=departement=''
+##title=
+##
+plan_transport = {
+'01':('901','01'),
+'02':('951','51'),
+'03':('963','63'),
+'04':('984','84'),
+'05':('938','38'),
+'06':('906','06'),
+'07':('926','26'),
+'08':('951','51'),
+'09':('932','32'),
+'10':('910','10'),
+'11':('932','32'),
+'12':('982','82'),
+'13':('913','13'),
+'14':('914','14'),
+'15':('963','63'),
+'16':('916','16'),
+'17':('979','79'),
+'18':('945','45'),
+'19':('987','87'),
+'20':('920','20'),
+'21':('921','21'),
+'22':('935','35'),
+'23':('987','87'),
+'24':('987','87'),
+'25':('925','25'),
+'26':('926','26'),
+'27':('976','76'),
+'28':('978','78'),
+'29':('929','29'),
+'30':('984','84'),
+'31':('931','31'),
+'32':('932','32'),
+'55':('954','54'),
+'56':('956','56'),
+'57':('957','57'),
+'58':('921','21'),
+'59':('959','59'),
+'60':('960','60'),
+'61':('972','72'),
+'62':('962','62'),
+'63':('963','63'),
+'64':('964','64'),
+'65':('964','64'),
+'66':('966','66'),
+'67':('967','67'),
+'68':('968','68'),
+'69':('969','69'),
+'70':('925','25'),
+'71':('921','21'),
+'72':('972','72'),
+'73':('974','74'),
+'74':('974','74'),
+'75':('975','75'),
+'76':('976','76'),
+'77':('977','77'),
+'78':('978','78'),
+'79':('979','79'),
+'80':('960','60'),
+'81':('982','82'),
+'82':('982','82'),
+'83':('983','83'),
+'84':('984','84'),
+'85':('944','44'),
+'86':('937','37'),
+'33':('933','33'),
+'34':('934','34'),
+'35':('935','35'),
+'36':('937','37'),
+'37':('937','37'),
+'38':('938','38'),
+'39':('921','21'),
+'40':('964','64'),
+'41':('945','45'),
+'42':('942','42'),
+'43':('942','42'),
+'44':('944','44'),
+'45':('945','45'),
+'46':('982','82'),
+'47':('933','33'),
+'48':('966','66'),
+'49':('949','49'),
+'50':('914','14'),
+'51':('951','51'),
+'52':('910','10'),
+'53':('972','72'),
+'54':('954','54'),
+'87':('987','87'),
+'88':('954','54'),
+'89':('910','10'),
+'90':('925','25'),
+'91':('994','94'),
+'92':('995','95'),
+'93':('992','92'),
+'94':('994','94'),
+'95':('995','95'),
+'98':('906','06'),
+}
+if departement == '' :
+  return None
+else :
+  return plan_transport[departement]
diff --git a/product/Coramy/skins/coramy_trade/SaleInvoice_updateTransaction.py b/product/Coramy/skins/coramy_trade/SaleInvoice_updateTransaction.py
new file mode 100755
index 0000000000..802f02ce88
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/SaleInvoice_updateTransaction.py
@@ -0,0 +1,65 @@
+## Script (Python) "SaleInvoice_updateTransaction"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+# Create invoice lines
+global total_price 
+global total_vat 
+global total_discount 
+total_price = 0.0
+total_vat = 0.0
+total_discount = 0.0
+invoice = context
+
+def updateTotal(l):
+  global total_price 
+  global total_vat 
+  global total_discount 
+  if l.getPrice() in ('', None):
+    return 'Price is not defined for %s %s' % (l.getResource(), l.getVariationText())
+  elif l.getQuantity():
+    price = l.getPrice() * l.getQuantity()
+    total_price += price
+    if l.getValueAddedTaxRatio() and l.getValueAddedTaxRecoverable():
+      total_vat += price * l.getValueAddedTaxRatio()
+  return None  
+
+for l in context.contentValues(filter={'portal_type':"Invoice Line"}):
+  if l.hasCellContent():
+    for c in l.contentValues(filter={'portal_type':"Invoice Cell"}):
+      error_message = updateTotal(c)
+      if error_message is not None:
+        return error_message 
+  else:
+    error_message = updateTotal(l)
+    if error_message is not None:
+      return error_message 
+
+# Generate accounting lines
+# Income Line
+if not invoice.hasObject('income'):
+  income = invoice.newContent(portal_type="Sale Invoice Transaction Line", id='income')                          
+else:
+  income = context.income 
+income.edit(source='account/vente', destination='account/achat',
+                           source_credit=total_price)
+# Payable Line
+if not invoice.hasObject('payable'):
+  payable = invoice.newContent(portal_type="Sale Invoice Transaction Line", id='payable')                          
+else:
+  payable = context.payable 
+payable.edit(source='account/creance_client', destination='dette_fournisseur',
+                           source_debit=total_price + total_vat)
+
+# VAT Line
+if not invoice.hasObject('vat'):
+  vat = invoice.newContent(portal_type="Sale Invoice Transaction Line", id='vat')                          
+else:
+  vat = context.vat
+vat.edit(source='account/tva_collectee_196', destination='account/tva_recuperable_196',
+                           source_credit=total_vat)
diff --git a/product/Coramy/skins/coramy_trade/SalesPackingList_printForm.form b/product/Coramy/skins/coramy_trade/SalesPackingList_printForm.form
new file mode 100755
index 0000000000..750cb3d581
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/SalesPackingList_printForm.form
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<form>
+  <title>Imprimer</title>
+  <name>SalesPackingList_printForm</name>
+  <action>sales_packing_list_secure_print</action>
+  <enctype>multipart/form-data</enctype>
+  <method>POST</method>
+  <pt>form_dialog</pt>
+
+  <groups>
+    <group>
+      <title>left</title>
+      <fields>
+
+      <field><id>my_packing_list_page_template</id> <type>RadioField</type>
+        <values>
+          <alternate_name></alternate_name>
+          <css_class></css_class>
+          <default></default>
+          <description></description>
+          <external_validator></external_validator>
+          <first_item type="int">1</first_item>
+          <hidden type="int">0</hidden>
+          <items type="list">[('Bordereau de livraison', 'sales_packing_list_print'), ('Liste de colisage', 'sales_packing_list_container_list_print')]</items>
+          <orientation>vertical</orientation>
+          <required type="int">1</required>
+          <title>Impression demandée</title>
+        </values>
+        <tales>
+        </tales>
+        <messages>
+          <message name="external_validator_failed">The input failed the external validator.</message>
+          <message name="required_not_found">Input is required but no input given.</message>
+          <message name="unknown_selection">You selected an item that was not in the list.</message>
+        </messages>
+      </field>
+      </fields>
+    </group>
+  </groups>
+</form>
\ No newline at end of file
diff --git a/product/Coramy/skins/coramy_trade/sales_packing_list_container_list_print.pt b/product/Coramy/skins/coramy_trade/sales_packing_list_container_list_print.pt
new file mode 100755
index 0000000000..94df8e2255
--- /dev/null
+++ b/product/Coramy/skins/coramy_trade/sales_packing_list_container_list_print.pt
@@ -0,0 +1,210 @@
+<HTML>
+  <HEAD>
+    <meta http-equiv="content-type" content="text/html;charset=ISO-8859-1">
+    <title tal:content="here/getTitle">Coramy</title>
+    <link rel=stylesheet type="text/css" href="modele_catalog_c">
+  </HEAD>
+  <BODY bgcolor="#ffffff" tal:define="delivery_list python:here.object_action_list(selection_name='sales_packing_list_selection',max_nb=10);
+                                       page_number python:[0]">
+    <TABLE tal:repeat="delivery delivery_list" width="660" height="955"  cellpadding="0" cellspacing="0" tal:attributes="class python:here.PT_pageBreak(page_number)">
+      <TABLE border="0" width="660" height="900"  cellpadding="0" cellspacing="0"
+              tal:define="order python:delivery.getCausalityValue(portal_type=['Sales Order']);
+                          destination python:delivery.getDestinationValue(portal_type=['Organisation']);
+                          distinct_container_list python:delivery.PackingList_getDistinctContainerList();
+                          totalizer python:[0,0,0,0]"><!-- Tableau general -->
+        <TR>
+          <TD>
+            <TABLE border="0" width="100%" height="100%">
+              <TR>
+                <TD class="Titre" tal:content="python:delivery.getSourceSectionTitle()">Coramy</TD>
+                <TD align="center">
+                  <span class="Titre2">Liste de colisage<span tal:content="python:' n° '+delivery.getId()"/></span><br>
+                  Lieferschein Nr / Delivery note N°
+                </TD>
+                <TD align="right">
+                  <span tal:content="python:'Gravelines, le '+str(here.DateTime_getFormattedDate())"/>
+                </TD>
+              </TR>
+            </TABLE>
+          </TD>
+        </TR>
+        <TR height="18%"><!-- Infos -->
+          <TD><br>
+            <TABLE border="0" width="100%" height="100%">
+              <TR>
+                <TD nowrap align="center" class="Bordereau">Commande N°<br>Auftrag Nr / Order N°<br><span class="Normal" tal:content="python:order.getDestinationReference()" /></TD>
+                <TD nowrap align="center" class="Bordereau" >Poids brut (Kg)<br>Brutto-gewicht / Gross weight <br><span class="Normal" tal:content="python:delivery.PackingList_getTotalGrossWeight()" /></TD>
+                <TD nowrap rowspan="3">
+                  <SPAN tal:condition="python:destination<>None">
+                  <b><SPAN tal:content="python:modules['string'].capwords(destination.getTitle())"/></b>
+                  <br><SPAN tal:condition="python:destination.getPortalType()<>'Category'">
+                      <SPAN tal:define="address_items python:modules['string'].
+                              split(destination.getDefaultAddress().asText(country='France'),'\n')">
+                        <SPAN tal:repeat="item address_items">
+                          <SPAN tal:content="item"/><br>
+                        </SPAN>
+                      </SPAN>
+                    </SPAN>
+                  </SPAN>
+                </TD>
+                <TD nowrap align="center" rowspan="2" class="Bordereau">Port<br>Porto / Freight<br><span class="Normal" tal:content="python:delivery.getIncoterm()" /></TD>
+              </TR>
+              <TR>
+                <TD nowrap align="center" class="Bordereau">Confirmation N°<br>Bestätigung Nr <br><span class="Normal" tal:content="python:order.getId()" /></TD>
+                <TD nowrap align="center" class="Bordereau">Nombre de colis<br>Kolli Anzahl / Nb of parcels <br><span class="Normal" tal:content="python:len(delivery.contentValues(filter={'portal_type':'Container'}))" /></TD>
+              </TR>
+              <TR>
+                <TD nowrap align="center" class="Bordereau"> Date d'expédition<br>Versand Tag / Sending Date <br><span class="Normal" tal:content="python:str(here.DateTime_getFormattedDate(delivery.getTargetStartDate()))" /></TD>
+                <TD nowrap align="center" class="Bordereau" >Nombre d'articles<br>Artikel Anzahl / Nb of items<br><span class="Normal" tal:content="python:delivery.getTargetTotalQuantity()" /></TD>
+                <TD nowrap align="center" class="Bordereau" >Transporteur <br> Carrier / Spediteur<br><span class="Normal" tal:content="python:delivery.getDeliveryMode()" /></TD>
+              </TR>
+            </TABLE>
+          </TD>
+        </TR>
+
+
+        <SPAN tal:repeat="container_template distinct_container_list">
+          <SPAN tal:define="toto python:here.PT_reset_total_list(totalizer,[1])"/>
+          <SPAN tal:repeat="delivery_line python:container_template[0].contentValues(filter={'portal_type':
+                          'Container Line'})">
+            <TR><!-- Matrice de ligne de livraison -->
+              <TD>
+
+                  <TABLE border="1" width="100%"
+                          tal:define="correspondance_tailles python:delivery_line.getResourceValue().getSpecialiseValue(portal_type=['Correspondance Tailles']);
+                                      coloris_list python:delivery_line.Variated_getColorisList();
+                                      taille_qty python:len(delivery_line.Variated_getTailleList(correspondance_tailles)[0]);
+                                      morphologie_list python:delivery_line.getMorphologieList()
+                                      ">
+                    <TR>
+                      <TD align="left"
+                       tal:condition="python:container_template[1][0]==container_template[1][1]">
+                        <b tal:content="python:'Colis %s'%container_template[1][0]"/>
+                      </TD>
+                      <TD align="left"
+                       tal:condition="python:container_template[1][0]<>container_template[1][1]">
+                        <b tal:content="python:'Colis %s à %s'%(container_template[1][0],container_template[1][1])"/>
+                      </TD>
+                      <TD tal:attributes="colspan python:taille_qty+1" align="center">Quantités réparties par tailles</TD>
+                    </TR>
+
+                    <SPAN tal:condition="python:len(morphologie_list)==0"
+                          tal:define="taille_list python:delivery_line.Variated_getTailleList(correspondance_tailles)"><!-- S'Il N'Y A PAS DE VARIANTES MORPHOLOGIQUES -->
+                        <TR tal:condition="python:1">
+                          <TD nowrap><SPAN tal:content="python:'Modèle : %s' %delivery_line.getResourceValue().getId()"/></TD>
+                          <TD rowspan="2" align="center" tal:repeat="index python:range(taille_qty)"
+                            tal:content="python:taille_list[1][index]">36</TD><!-- BOUCLE SUR LE NB DE TAILLES -->
+                          <TD align="center" rowspan="2" nowrap>Total</TD>
+                        </TR>
+                        <TR>
+
+                          <TD>
+                            <SPAN tal:condition="python:delivery_line.getResourceValue().getPortalType()=='Modele'" width="30%" tal:content="python:delivery_line.getResourceValue().getComposition()"/>
+                            <SPAN tal:condition="python:delivery_line.getResourceValue().getPortalType()=='Assortiment'" width="30%" tal:content="python:delivery_line.getResourceValue().getDescription()"/>
+                          </TD>
+                        </TR>
+
+                        <SPAN tal:condition="python:len(coloris_list[0])>0">
+                        <TR tal:repeat="index python:range(len(coloris_list[0]))"><!-- BOUCLE SUR LES COLORIS -->
+                          <TD align="left" tal:content="python:'coloris '+coloris_list[1][index]"></TD>
+                          <SPAN tal:define="toto python:delivery_line.PT_reset_total_list(totalizer,[2,3])"/>
+                          <SPAN tal:repeat="target_quantity python:delivery_line.DeliveryLine_getTargetQuantityList(taille_list[2],coloris_list[2][index])">
+                            <TD align = right tal:content="python: '%.0f' %target_quantity"/>
+                            <SPAN tal:define="toto python:delivery_line.PT_update_total_list(totalizer,[0,1,2,3],target_quantity)"/>
+                          </SPAN>
+                          <TD align="right" tal:content="python: '%.0f' %totalizer[3]"/>
+                        </TR>
+                        </SPAN>
+
+                        <SPAN tal:condition="python:len(coloris_list[0])==0">
+                        <TR><!-- PAS DE COLORIS -->
+                          <TD align="left"></TD>
+                          <SPAN tal:define="toto python:delivery_line.PT_reset_total_list(totalizer,[2,3])"/>
+                          <SPAN tal:repeat="target_quantity python:delivery_line.DeliveryLine_getTargetQuantityList(taille_list[2])">
+                            <TD align = right tal:content="python: '%.0f' %target_quantity"/>
+                            <SPAN tal:define="toto python:delivery_line.PT_update_total_list(totalizer,[0,1,2,3],target_quantity)"/>
+                          </SPAN>
+                          <SPAN tal:condition="python:taille_qty==0"
+                                tal:define="toto python:delivery_line.PT_update_total_list(totalizer,[0,1,2,3],delivery_line.getTargetQuantity())"/>
+                          <TD align="right" tal:content="python: '%.0f' %totalizer[3]"/>
+                        </TR>
+                        </SPAN>
+
+                      <TR>
+                        <TD align = "right" tal:attributes="colspan python:taille_qty+1">Total colis
+                        </TD>
+                        <TD align="right" tal:content="python: '%.0f' %totalizer[1]">
+                        </TD>
+                      </TR>
+                    </SPAN>
+
+                    <SPAN tal:condition="python:len(morphologie_list)>0"><!-- S'Il Y A DES VARIANTES MORPHOLOGIQUES -->
+                      <SPAN tal:repeat="morphologie morphologie_list">
+                      <SPAN tal:define="taille_list python:delivery_line.Variated_getTailleList(correspondance_tailles,morphologie);
+                                        toto python:delivery_line.PT_reset_total_list(totalizer,[3])"><!-- BOUCLE SUR LES VARIANTES MORPHOLOGIQUES -->
+                        <TR tal:condition="python:1">
+                          <TD nowrap><SPAN tal:content="python:'Modèle : %s' % '/'.join(morphologie.split('/')[1:])"/></TD>
+                          <TD rowspan="2" align="center" tal:repeat="index python:range(taille_qty)"
+                            tal:content="python:taille_list[1][index]">36</TD><!-- BOUCLE SUR LE NB DE TAILLES -->
+                          <TD align="center" rowspan="2" nowrap>Total</TD>
+                        </TR>
+                        <TR>
+
+                          <TD>
+                            <SPAN tal:condition="python:delivery_line.getResourceValue().getPortalType()=='Modele'" width="30%" tal:content="python:delivery_line.getResourceValue().getComposition()"/>
+                            <SPAN tal:condition="python:delivery_line.getResourceValue().getPortalType()=='Assortiment'" width="30%" tal:content="python:delivery_line.getResourceValue().getDescription()"/>
+                          </TD>
+                        </TR>
+
+                        <TR tal:repeat="index python:range(len(coloris_list[0]))"><!-- BOUCLE SUR LES COLORIS -->
+                          <TD align="left" tal:content="python:'coloris '+coloris_list[1][index]"></TD>
+                          <SPAN tal:define="toto python:delivery_line.PT_reset_total_list(totalizer,[3])"/>
+                          <SPAN tal:repeat="target_quantity python:delivery_line.DeliveryLine_getTargetQuantityList(taille_list[2],coloris_list[2][index],morphologie)">
+                            <TD align = right tal:content="python: '%.0f' %target_quantity"/>
+                            <SPAN tal:define="toto python:delivery_line.PT_update_total_list(totalizer,[0,1,2,3],target_quantity)"/>
+                          </SPAN>
+                          <TD align="right" tal:content="python: '%.0f' %totalizer[3]"/>
+                        </TR>
+                      </SPAN>
+                      <TR>
+                        <TD align = "right" tal:attributes="colspan python:taille_qty+1">Total colis
+                        </TD>
+                        <TD align="right" tal:content="python: '%.0f' %totalizer[1]">
+                        </TD>
+                      </TR>
+                      </SPAN>
+
+                    </SPAN>
+
+                  </TABLE>
+              </TD>
+            </TR>
+
+            <TR tal:define="commentaires_list python:modules['string'].split('','\n')"><!-- Notes -->
+              <TD valign="top">
+                <span tal:repeat="commentaires_item commentaires_list">
+                <span tal:content="python:commentaires_item"/></span>
+              </TD>
+            </TR>
+
+          </SPAN>
+        </SPAN>
+
+        <TR>
+          <TD height="40%"/>
+        </TR>
+        <TR>
+          <TD tal:condition="python:delivery.getSourceSectionTitle()=='BLS'" align="center">BLS - 5 bis, rue Denis Cordonnier - 59820 Gravelines (FRANCE)<br>Tél. : + 33 (0) 3 28 51 86 26 -  Fax : + 33 (0) 3 28 23 34 96
+            <p class="Copy">S.A.R.L. au capital de 10.000 € - T.V.A. FR 51 442 959 243 - R.C. Dunkerque 442 959 243 - SIRET 442 959 243 00019</p>
+          </TD>
+          <TD tal:condition="python:delivery.getSourceSectionTitle()=='Houvenaegel'" align="center">Houvenaegel Création - 5 bis, rue Denis Cordonnier - 59820 Gravelines (FRANCE)<br>Tél. : + 33 (0) 3 28 51 91 55 -  Fax : + 33 (0) 3 28 23 34 96
+            <p class="Copy">S.A.R.L. au capital de 7.622,45 € - T.V.A. FR 07 422 769 810 - R.C. Dunkerque 422 769 810 - SIRET 422 769 810 00025</p>
+          </TD>
+          <TD tal:condition="python:delivery.getSourceSectionTitle()=='Coramy'" align="center">Coramy - 5 bis, rue Denis Cordonnier - 59820 Gravelines (FRANCE)<br>Tél. : + 33 (0) 3 28 51 91 51 -  Fax : + 33 (0) 3 28 23 34 96
+            <p class="Copy">S.A.S. au capital de 435.200 € - T.V.A. FR 67 611 750 274 - R.C. Dunkerque 611 750 274 - SIRET 611 750 274 00023  - CNUF 15971</p>
+          </TD>
+        </TR>
+      </TABLE>
+    </TABLE>
+  </BODY>
+</HTML>
-- 
2.30.9