From 5a3a189d43c759cb89d7899c77f9ae486e726070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com> Date: Mon, 30 Nov 2015 09:18:38 +0100 Subject: [PATCH] pdm/trade: make price from trade conditions only apply if the trade condition is used in this order (cherry picked from commit 0ad99c2db048991e250121f08380c56c3289e43f) Conflicts: product/ERP5/tests/testTradeCondition.py --- .../erp5_pdm/SupplyCell_asPredicate.xml | 13 +++++ .../erp5_pdm/SupplyLine_asPredicate.xml | 12 +++++ ...ovement_getPriceCalculationOperandDict.xml | 6 +++ product/ERP5/tests/testTradeCondition.py | 52 +++++++++++++++++++ 4 files changed, 83 insertions(+) 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 2f585cd869..76edd1a1ab 100644 --- a/product/ERP5/tests/testTradeCondition.py +++ b/product/ERP5/tests/testTradeCondition.py @@ -467,6 +467,58 @@ class TestTradeConditionSupplyLine(TradeConditionTestCase): # not using the supply line inside trade condition self.assertEqual(1, line.getPrice()) + def test_supply_line_in_invalidated_trade_condition_with_reference_does_not_apply(self): + # edge case derived from + # test_supply_line_in_invalidated_trade_condition_does_not_apply, if a + # trade condition have a reference and is invalidated, composition + # mechanism will lookup another applicable trade condition, which can fail, + # but this should not affect getPrice + other_supply = self.portal.getDefaultModule(self.supply_type + ).newContent(portal_type=self.supply_type, + resource_value=self.resource, + source_section_value=self.vendor, + destination_section_value=self.client) + other_supply.validate() + other_supply_line = other_supply.newContent( + portal_type=self.supply_line_type, + base_price=1) + self.trade_condition.setReference(self.id()) + supply_line = self.trade_condition.newContent( + portal_type=self.supply_line_type, + resource_value=self.resource, + base_price=2) + self.order.setSpecialiseValue(self.trade_condition) + self.order.setSourceSectionValue(self.vendor) + self.order.setDestinationSectionValue(self.client) + + self.trade_condition.invalidate() + 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(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): # if a supply lines defines a section, it has priority over supply lines -- GitLab