From 3857010183dc71fb8da69ca256413c86b15c87c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Thu, 26 Nov 2015 15:17:03 +0100
Subject: [PATCH] pdm/trade: make price from trade conditions only apply if the
 trade condition is used in this order

---
 .../erp5_pdm/InternalSupplyLine_view.xml      |   1 +
 .../my_product_line.xml                       | 115 ++++++++++++++++++
 .../erp5_pdm/PurchaseSupplyLine_view.xml      |   1 +
 .../my_product_line.xml                       | 115 ++++++++++++++++++
 .../erp5_pdm/SaleSupplyLine_view.xml          |   1 +
 .../SaleSupplyLine_view/my_product_line.xml   | 115 ++++++++++++++++++
 .../erp5_pdm/SupplyCell_asPredicate.xml       |  13 ++
 .../erp5_pdm/SupplyLine_asPredicate.xml       |  12 ++
 ...ovement_getPriceCalculationOperandDict.xml |   6 +
 product/ERP5/tests/testTradeCondition.py      |  18 +++
 10 files changed, 397 insertions(+)
 create mode 100644 bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/InternalSupplyLine_view/my_product_line.xml
 create mode 100644 bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/PurchaseSupplyLine_view/my_product_line.xml
 create mode 100644 bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SaleSupplyLine_view/my_product_line.xml

diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/InternalSupplyLine_view.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/InternalSupplyLine_view.xml
index 1d5113b3a4..718bc83d21 100644
--- a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/InternalSupplyLine_view.xml
+++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/InternalSupplyLine_view.xml
@@ -95,6 +95,7 @@
                       <list>
                         <string>my_destination_title</string>
                         <string>my_resource_title</string>
+                        <string>my_product_line</string>
                         <string>my_priced_quantity</string>
                         <string>my_base_unit_price</string>
                         <string>my_quantity_unit</string>
diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/InternalSupplyLine_view/my_product_line.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/InternalSupplyLine_view/my_product_line.xml
new file mode 100644
index 0000000000..d8c278399a
--- /dev/null
+++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/InternalSupplyLine_view/my_product_line.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>delegated_list</string> </key>
+            <value>
+              <list>
+                <string>editable</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>my_product_line</string> </value>
+        </item>
+        <item>
+            <key> <string>message_values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator_failed</string> </key>
+                    <value> <string>The input failed the external validator.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string>my_product_line</string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string>Base_viewPDMFieldLibrary</string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string>Click to edit the target</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="TALESMethod" module="Products.Formulator.TALESField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_text</string> </key>
+            <value> <string>not: context/hasResource</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/PurchaseSupplyLine_view.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/PurchaseSupplyLine_view.xml
index d94249070f..789ec0fbe5 100644
--- a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/PurchaseSupplyLine_view.xml
+++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/PurchaseSupplyLine_view.xml
@@ -84,6 +84,7 @@
                     <value>
                       <list>
                         <string>my_resource_title</string>
+                        <string>my_product_line</string>
                         <string>my_source_title</string>
                         <string>my_source_reference</string>
                         <string>my_priced_quantity</string>
diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/PurchaseSupplyLine_view/my_product_line.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/PurchaseSupplyLine_view/my_product_line.xml
new file mode 100644
index 0000000000..d8c278399a
--- /dev/null
+++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/PurchaseSupplyLine_view/my_product_line.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>delegated_list</string> </key>
+            <value>
+              <list>
+                <string>editable</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>my_product_line</string> </value>
+        </item>
+        <item>
+            <key> <string>message_values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator_failed</string> </key>
+                    <value> <string>The input failed the external validator.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string>my_product_line</string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string>Base_viewPDMFieldLibrary</string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string>Click to edit the target</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="TALESMethod" module="Products.Formulator.TALESField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_text</string> </key>
+            <value> <string>not: context/hasResource</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SaleSupplyLine_view.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SaleSupplyLine_view.xml
index e5f391d231..6a8a25d0b3 100644
--- a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SaleSupplyLine_view.xml
+++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SaleSupplyLine_view.xml
@@ -95,6 +95,7 @@
                       <list>
                         <string>my_destination_title</string>
                         <string>my_resource_title</string>
+                        <string>my_product_line</string>
                         <string>my_destination_reference</string>
                         <string>my_priced_quantity</string>
                         <string>your_quantity_unit</string>
diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SaleSupplyLine_view/my_product_line.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SaleSupplyLine_view/my_product_line.xml
new file mode 100644
index 0000000000..d8c278399a
--- /dev/null
+++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SaleSupplyLine_view/my_product_line.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>delegated_list</string> </key>
+            <value>
+              <list>
+                <string>editable</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>my_product_line</string> </value>
+        </item>
+        <item>
+            <key> <string>message_values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator_failed</string> </key>
+                    <value> <string>The input failed the external validator.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+                    </value>
+                </item>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <int>1</int> </value>
+                </item>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string>my_product_line</string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string>Base_viewPDMFieldLibrary</string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string>Click to edit the target</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="TALESMethod" module="Products.Formulator.TALESField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_text</string> </key>
+            <value> <string>not: context/hasResource</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SupplyCell_asPredicate.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SupplyCell_asPredicate.xml
index 84d3392630..6b7c35478a 100644
--- a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SupplyCell_asPredicate.xml
+++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SupplyCell_asPredicate.xml
@@ -66,6 +66,19 @@ if context.getSource():\n
 if context.getDestination():\n
   base_category_tuple += (\'destination\',)\n
 \n
+if context.getParentValue().getParentValue().getPortalType() in (\n
+    ## XXX There is no portal type group for trade conditions.\n
+    \'Sale Trade Condition\',\n
+    \'Purchase Trade Condition\',\n
+    \'Internal Trade Condition\'):\n
+  # Supply Lines from trade conditions are set as specialise to this trade condition,\n
+  # so that we can apply a predicate on movements later. Supply Lines from trade condition\n
+  # only apply on movements using these trade conditions.\n
+  category_list = context.getCategoryList() + [\'specialise/%s\' % context.getParentValue().getParentValue().getRelativeUrl()]\n
+  context = context.asContext(categories=category_list)\n
+  base_category_tuple += (\'specialise\', )\n
+\n
+\n
 #backwards compatibility\n
 mapped_value_property_list = context.getMappedValuePropertyList()\n
 if not \'priced_quantity\' in mapped_value_property_list:\n
diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SupplyLine_asPredicate.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SupplyLine_asPredicate.xml
index 49b60fc8fb..1e67230533 100644
--- a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SupplyLine_asPredicate.xml
+++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/SupplyLine_asPredicate.xml
@@ -68,6 +68,18 @@ if context.getSource():\n
 if context.getDestination():\n
   base_category_tuple += (\'destination\',)\n
 \n
+if context.getParentValue().getPortalType() in (\n
+    ## XXX There is no portal type group for trade conditions.\n
+    \'Sale Trade Condition\',\n
+    \'Purchase Trade Condition\',\n
+    \'Internal Trade Condition\'):\n
+  # Supply Lines from trade conditions are set as specialise to this trade condition,\n
+  # so that we can apply a predicate on movements later. Supply Lines from trade condition\n
+  # only apply on movements using these trade conditions.\n
+  category_list = context.getCategoryList() + [\'specialise/%s\' % context.getParentValue().getRelativeUrl()]\n
+  context = context.asContext(categories=category_list)\n
+  base_category_tuple += (\'specialise\', )\n
+\n
 #backwards compatibility\n
 mapped_value_property_list = context.getMappedValuePropertyList()\n
 if not \'priced_quantity\' in mapped_value_property_list:\n
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Movement_getPriceCalculationOperandDict.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Movement_getPriceCalculationOperandDict.xml
index 481e438179..1edd28f0ff 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Movement_getPriceCalculationOperandDict.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Movement_getPriceCalculationOperandDict.xml
@@ -143,6 +143,8 @@ except AttributeError:\n
   # Sometime, movements doesn\'t have an explanation.\n
   explanation = None\n
 \n
+specialise_set = set()\n
+\n
 if explanation is not None:\n
   explanation_type = explanation.getPortalType()\n
   high_priority_supply_line_list = []\n
@@ -157,6 +159,7 @@ if explanation is not None:\n
         high_priority_supply_line_list.extend(list(supply_cell_list))\n
       else:\n
         high_priority_supply_line_list.append(supply_line)\n
+      specialise_set.add(supply_line.getParentValue().getRelativeUrl())\n
 \n
   # XXX FIXME: Hardcoded values\n
   if "Internal" in explanation_type:\n
@@ -171,6 +174,9 @@ if explanation is not None:\n
 \n
 resource = context.getResourceValue()\n
 \n
+if specialise_set:\n
+  kw[\'categories\'] = kw.get(\'categories\', []) + [\'specialise/%s\' % x for x in specialise_set]\n
+\n
 if resource is not None:\n
   if isPricingOptimise():\n
     return getOptimisedPriceCalculationOperandDict(default=default, context=context, **kw)\n
diff --git a/product/ERP5/tests/testTradeCondition.py b/product/ERP5/tests/testTradeCondition.py
index aa263766db..07e1e967bb 100644
--- a/product/ERP5/tests/testTradeCondition.py
+++ b/product/ERP5/tests/testTradeCondition.py
@@ -479,6 +479,24 @@ class TestTradeConditionSupplyLine(TradeConditionTestCase):
     # not using the supply line inside trade condition
     self.assertEqual(1, line.getPrice())
 
+  def test_supply_line_in_other_trade_condition_does_not_apply(self):
+    """Supply lines from trade condition not related to an order does not apply.
+    """
+    supply_line = self.trade_condition.newContent(
+                                    portal_type=self.supply_line_type,
+                                    resource_value=self.resource,
+                                    base_price=2)
+    self.assertEqual(None, self.order.getSpecialiseValue())
+    self.order.setSourceSectionValue(self.vendor)
+    self.order.setDestinationSectionValue(self.client)
+
+    self.tic()
+
+    line = self.order.newContent(portal_type=self.order_line_type,
+                                 resource_value=self.resource,
+                                 quantity=1)
+    # not using the supply line inside trade condition
+    self.assertEqual(None, line.getPrice())
 
   # TODO: move to testSupplyLine ! (which does not exist yet)
   def test_supply_line_section(self):
-- 
2.30.9