From fa0b9856914c6d720a6a3bb8859903c9bf352e17 Mon Sep 17 00:00:00 2001
From: Kazuhiko Shiozaki <kazuhiko@nexedi.com>
Date: Tue, 13 May 2014 14:12:39 +0200
Subject: [PATCH] applicable supply lines should be sorted by explanation's
 effective model list's order.

---
 ...ovement_getPriceCalculationOperandDict.xml | 54 ++++++-------
 product/ERP5/bootstrap/erp5_core/bt/revision  |  2 +-
 product/ERP5/tests/testTradeCondition.py      | 77 +++++++++++++++++++
 3 files changed, 103 insertions(+), 30 deletions(-)

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 e82ac13ce8..6a660b293e 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
@@ -64,9 +64,13 @@ def destinationSectionSortMethod(a, b):\n
 \n
 def getResourceInternalPriceSortMethod(high_priority_supply_line_list):\n
   def resourceInternalPriceSortMethod(a, b):\n
-    if a in high_priority_supply_line_list:\n
+    a_number = (a in high_priority_supply_line_list) and high_priority_supply_line_list.index(a)+1 or 0\n
+    b_number = (b in high_priority_supply_line_list) and high_priority_supply_line_list.index(b)+1 or 0\n
+    if a_number and b_number:\n
+      return a_number - b_number\n
+    elif a_number:\n
       return -1\n
-    elif b in high_priority_supply_line_list:\n
+    elif b_number:\n
       return 1\n
 \n
     if "Internal" in a.getPortalType():\n
@@ -84,9 +88,13 @@ def getResourceInternalPriceSortMethod(high_priority_supply_line_list):\n
 \n
 def getResourcePurchasePriceSortMethod(high_priority_supply_line_list):\n
   def resourcePurchasePriceSortMethod(a, b):\n
-    if a in high_priority_supply_line_list:\n
+    a_number = (a in high_priority_supply_line_list) and high_priority_supply_line_list.index(a)+1 or 0\n
+    b_number = (b in high_priority_supply_line_list) and high_priority_supply_line_list.index(b)+1 or 0\n
+    if a_number and b_number:\n
+      return a_number - b_number\n
+    elif a_number:\n
       return -1\n
-    elif b in high_priority_supply_line_list:\n
+    elif b_number:\n
       return 1\n
 \n
     if "Purchase" in a.getPortalType():\n
@@ -104,9 +112,13 @@ def getResourcePurchasePriceSortMethod(high_priority_supply_line_list):\n
 \n
 def getResourceSalePriceSortMethod(high_priority_supply_line_list):\n
   def resourceSalePriceSortMethod(a, b):\n
-    if a in high_priority_supply_line_list:\n
+    a_number = (a in high_priority_supply_line_list) and high_priority_supply_line_list.index(a)+1 or 0\n
+    b_number = (b in high_priority_supply_line_list) and high_priority_supply_line_list.index(b)+1 or 0\n
+    if a_number and b_number:\n
+      return a_number - b_number\n
+    elif a_number:\n
       return -1\n
-    elif b in high_priority_supply_line_list:\n
+    elif b_number:\n
       return 1\n
 \n
     if "Sale" in a.getPortalType():\n
@@ -122,18 +134,6 @@ def getResourceSalePriceSortMethod(high_priority_supply_line_list):\n
   return resourceSalePriceSortMethod\n
 \n
 \n
-def getRelatedTradeConditionList(trade_condition):\n
-  """Get all trade conditions related to an order.\n
-  trade_condition parameter can be a trade condition or an order/invoice\n
-  """\n
-  related_trade_condition_list = trade_condition.getSpecialiseValueList(\n
-        portal_type=(\'Sale Trade Condition\', \'Purchase Trade Condition\'))\n
-  for related_trade_condition in trade_condition.getSpecialiseValueList(\n
-        portal_type=(\'Sale Trade Condition\', \'Purchase Trade Condition\')):\n
-    related_trade_condition_list.extend(\n
-          getRelatedTradeConditionList(related_trade_condition))\n
-  return related_trade_condition_list\n
-\n
 def getOptimisedPriceCalculationOperandDict(default=None, context=None, **kw):\n
   """\n
    Price Method optimised by the preference \n
@@ -180,17 +180,13 @@ if explanation is not None:\n
                               context.getPortalOrderTypeList() + context.getPortalDeliveryTypeList():\n
     # if there are trade conditions containing supply lines related to that\n
     # order/invoice, we give high priority to those supply lines\n
-    for trade_condition in getRelatedTradeConditionList(explanation):\n
-      for supply_line in trade_condition.contentValues(\n
-                  portal_type=context.getPortalSupplyPathTypeList(),\n
-                  checked_permission=\'View\'):\n
-         supply_cell_list = supply_line.contentValues(\n
-                  portal_type=context.getPortalSupplyPathTypeList(),\n
-                  checked_permission=\'View\')\n
-         if supply_cell_list:\n
-            high_priority_supply_line_list.extend(list(supply_cell_list))\n
-         else:\n
-            high_priority_supply_line_list.append(supply_line)\n
+    for supply_line in explanation.asComposedDocument().objectValues(portal_type=context.getPortalSupplyPathTypeList()):\n
+      supply_cell_list = supply_line.objectValues(\n
+        portal_type=context.getPortalSupplyPathTypeList())\n
+      if supply_cell_list:\n
+        high_priority_supply_line_list.extend(list(supply_cell_list))\n
+      else:\n
+        high_priority_supply_line_list.append(supply_line)\n
 \n
   # XXX FIXME: Hardcoded values\n
   if "Internal" in explanation_type:\n
diff --git a/product/ERP5/bootstrap/erp5_core/bt/revision b/product/ERP5/bootstrap/erp5_core/bt/revision
index 12d8d66fd1..013b0a1fca 100644
--- a/product/ERP5/bootstrap/erp5_core/bt/revision
+++ b/product/ERP5/bootstrap/erp5_core/bt/revision
@@ -1 +1 @@
-41159
+41160
\ No newline at end of file
diff --git a/product/ERP5/tests/testTradeCondition.py b/product/ERP5/tests/testTradeCondition.py
index 4dd1001b0b..497de345ea 100644
--- a/product/ERP5/tests/testTradeCondition.py
+++ b/product/ERP5/tests/testTradeCondition.py
@@ -268,6 +268,10 @@ class TestTradeConditionSupplyLine(TradeConditionTestCase):
   def test_movement_price_assignment(self):
     # supply line from the trade condition apply to the movements in order
     # where this trade condition is used
+    #
+    # Order ---> TC (123)
+    #
+    # price should be 123
     supply_line = self.trade_condition.newContent(
                                     portal_type=self.supply_line_type,
                                     resource_value=self.resource,
@@ -281,6 +285,79 @@ class TestTradeConditionSupplyLine(TradeConditionTestCase):
                                  quantity=1)
     self.assertEqual(123, line.getPrice())
 
+    # supply line in the direct trade condition should have priority
+    # than its specialised trade condition
+    #
+    # Order ---> TC (125) ---> TC (123)
+    #
+    # price should be 125
+    trade_condition2 = self.trade_condition_module.newContent(
+      portal_type=self.trade_condition_type,
+      specialise_value=self.trade_condition)
+    trade_condition2.validate()
+    trade_condition2.newContent(
+      portal_type=self.supply_line_type,
+      resource_value=self.resource,
+      base_price=125)
+    self.order.setSpecialiseValue(trade_condition2)
+    self.tic()
+    line.setPrice(None)
+    self.assertEqual(125, line.getPrice())
+
+    # supply line in the first direct trade condition should have
+    # priority than the second trade condition
+    #
+    # Order -+-> TC (127)
+    #        +-> TC (125) ---> TC (123)
+    #
+    # price should be 127
+    #
+    # Order -+-> TC (125) ---> TC (123)
+    #        +-> TC (127)
+    #
+    # price should be 125
+    trade_condition3 = self.trade_condition_module.newContent(
+      portal_type=self.trade_condition_type)
+    trade_condition3.validate()
+    trade_condition3.newContent(
+      portal_type=self.supply_line_type,
+      resource_value=self.resource,
+      base_price=127)
+    self.order.setSpecialiseValueList((trade_condition3, trade_condition2))
+    self.tic()
+    line.setPrice(None)
+    self.assertEqual(127, line.getPrice())
+    self.order.setSpecialiseValueList((trade_condition2, trade_condition3))
+    self.tic()
+    line.setPrice(None)
+    self.assertEqual(125, line.getPrice())
+
+    # supply line in the second direct trade condition should have
+    # priority than the first trade condition's specialised trade
+    # condition
+    #
+    # Order -+-> TC (---) ---> TC (123)
+    #        +-> TC (127)
+    #
+    # price should be 127
+    #
+    # Order -+-> TC (127)
+    #        +-> TC (---) ---> TC (123)
+    #
+    # price should be 127
+    trade_condition4 = self.trade_condition_module.newContent(
+      portal_type=self.trade_condition_type,
+      specialise_value=self.trade_condition)
+    trade_condition4.validate()
+    self.order.setSpecialiseValueList((trade_condition4, trade_condition3))
+    self.tic()
+    line.setPrice(None)
+    self.assertEqual(127, line.getPrice())
+    self.order.setSpecialiseValueList((trade_condition3, trade_condition4))
+    self.tic()
+    line.setPrice(None)
+    self.assertEqual(127, line.getPrice())
+
   def test_supply_line_priority(self):
     # supply lines from related trade condition should have priority over
     # supply lines from supply modules
-- 
2.30.9