From d27a2fa0fbaf5354ae5b9fe9dc4e46cf43f95ac8 Mon Sep 17 00:00:00 2001 From: Julien Muchembled <jm@nexedi.com> Date: Mon, 7 Apr 2014 17:04:52 +0200 Subject: [PATCH] Price calculation: in default script, return all operands and fix variable additional part variable_additional_price was not multiplied by the result of getPricingVariable as it was done in previous implementation. In order that the caller has more information about how the price was computed, Resource_getPriceCalculationOperandDict now returns the result of getPriceParameterDict with following changed: - list values involved in priced calculation are replaced by their sums - 'price' key is added to holds the computed price Also removing fallback code from Resource class, since it's been a long time that erp5_pdm provides Resource_getPriceCalculationOperandDict Resource_getPrice script is kept in case some unrelated code still uses it. --- .../erp5_pdm/Resource_getPrice.xml | 61 +----------- ...esource_getPriceCalculationOperandDict.xml | 68 +++++++------- bt5/erp5_pdm/bt/revision | 2 +- product/ERP5/Document/Resource.py | 92 +------------------ 4 files changed, 42 insertions(+), 181 deletions(-) diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/Resource_getPrice.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/Resource_getPrice.xml index 9e067de426..b581ad34c2 100644 --- a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/Resource_getPrice.xml +++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/Resource_getPrice.xml @@ -50,69 +50,12 @@ </item> <item> <key> <string>_body</string> </key> - <value> <string>price_parameter_dict = context.getPriceParameterDict(context=movement, REQUEST=REQUEST, **kw)\n -\n -# Calculate the unit price\n -unit_base_price = None\n -# Calculate\n -# ((base_price + SUM(additional_price) +\n -# variable_value * SUM(variable_additional_price)) *\n -# (1 - MIN(1, MAX(SUM(discount_ratio) , exclusive_discount_ratio ))) +\n -# SUM(non_discountable_additional_price)) *\n -# (1 + SUM(surcharge_ratio))\n -# Or, as (nearly) one single line :\n -# ((bp + S(ap) + v * S(vap))\n -# * (1 - m(1, M(S(dr), edr)))\n -# + S(ndap))\n -# * (1 + S(sr))\n -# Variable value is dynamically configurable through a python script.\n -# It can be anything, depending on business requirements.\n -# It can be seen as a way to define a pricing model that not only\n -# depends on discrete variations, but also on a continuous property\n -# of the object\n -\n -base_price = price_parameter_dict[\'base_price\']\n -if base_price in (None, \'\'):\n - # XXX Compatibility\n - # base_price must not be defined on resource\n - base_price = context.getBasePrice()\n -\n -if base_price not in (None, \'\'):\n - unit_base_price = base_price\n -\n - # Sum additional price\n - unit_base_price += sum(price_parameter_dict[\'additional_price\'])\n -\n - # Sum variable additional price\n - variable_value = 1.0\n - unit_base_price += sum(price_parameter_dict[\'variable_additional_price\']) * variable_value\n -\n - # Discount\n - sum_discount_ratio = sum(price_parameter_dict[\'discount_ratio\'])\n - exclusive_discount_ratio = price_parameter_dict[\'exclusive_discount_ratio\'] or 0\n - d_ratio = max(0, sum_discount_ratio, exclusive_discount_ratio)\n - if d_ratio != 0:\n - unit_base_price *= 1 - min(1, d_ratio)\n -\n - # Sum non discountable additional price\n - unit_base_price += sum(price_parameter_dict[\'non_discountable_additional_price\'])\n -\n - # Surcharge ratio\n - sum_surcharge_ratio = sum(price_parameter_dict[\'surcharge_ratio\']) + 1\n - unit_base_price *= sum_surcharge_ratio\n -\n - # Divide by the priced quantity\n - priced_quantity = price_parameter_dict[\'priced_quantity\']\n - if priced_quantity not in (None, 0):\n - unit_base_price /= priced_quantity\n -\n -# Return result\n -return unit_base_price\n + <value> <string>return context.Resource_getPriceCalculationOperandDict(*args, **kw)["price"]\n </string> </value> </item> <item> <key> <string>_params</string> </key> - <value> <string>default=None, movement=None, REQUEST=None, **kw</string> </value> + <value> <string>*args, **kw</string> </value> </item> <item> <key> <string>id</string> </key> diff --git a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/Resource_getPriceCalculationOperandDict.xml b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/Resource_getPriceCalculationOperandDict.xml index 0f3831564a..6585ea0fce 100644 --- a/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/Resource_getPriceCalculationOperandDict.xml +++ b/bt5/erp5_pdm/SkinTemplateItem/portal_skins/erp5_pdm/Resource_getPriceCalculationOperandDict.xml @@ -50,10 +50,10 @@ </item> <item> <key> <string>_body</string> </key> - <value> <string>price_parameter_dict = context.getPriceParameterDict(context=movement, REQUEST=REQUEST, **kw)\n + <value> <string encoding="cdata"><![CDATA[ + +result = context.getPriceParameterDict(context=movement, **kw)\n \n -# Calculate the unit price\n -unit_base_price = None\n # Calculate\n # ((base_price + SUM(additional_price) +\n # variable_value * SUM(variable_additional_price)) *\n @@ -71,50 +71,54 @@ unit_base_price = None\n # depends on discrete variations, but also on a continuous property\n # of the object\n \n -base_price = price_parameter_dict[\'base_price\']\n -if base_price in (None, \'\'):\n +base_price = result["base_price"]\n +if base_price in (None, ""):\n # XXX Compatibility\n # base_price must not be defined on resource\n base_price = context.getBasePrice()\n + if base_price in (None, ""):\n + return {"price": default,\n + "base_unit_price": result.get(\'base_unit_price\')}\n \n -if base_price not in (None, \'\'):\n - unit_base_price = base_price\n +for x in ("additional_price",\n + "variable_additional_price",\n + "discount_ratio",\n + "non_discountable_additional_price",\n + "surcharge_ratio"):\n + result[x] = sum(result[x])\n \n +unit_base_price = (base_price\n # Sum additional price\n - unit_base_price += sum(price_parameter_dict[\'additional_price\'])\n -\n + + result["additional_price"]\n # Sum variable additional price\n - variable_value = 1.0\n - unit_base_price += sum(price_parameter_dict[\'variable_additional_price\']) * variable_value\n + + result["variable_additional_price"] \\\n + * context.getPricingVariable(context=movement))\n \n - # Discount\n - sum_discount_ratio = sum(price_parameter_dict[\'discount_ratio\'])\n - exclusive_discount_ratio = price_parameter_dict[\'exclusive_discount_ratio\'] or 0\n - d_ratio = max(0, sum_discount_ratio, exclusive_discount_ratio)\n - if d_ratio != 0:\n - unit_base_price *= 1 - min(1, d_ratio)\n +# Discount\n +d_ratio = max(result["discount_ratio"], result[\'exclusive_discount_ratio\'] or 0)\n +if d_ratio > 0:\n + unit_base_price *= max(0, 1 - d_ratio)\n \n - # Sum non discountable additional price\n - unit_base_price += sum(price_parameter_dict[\'non_discountable_additional_price\'])\n +# Sum non discountable additional price\n +unit_base_price += result[\'non_discountable_additional_price\']\n \n - # Surcharge ratio\n - sum_surcharge_ratio = sum(price_parameter_dict[\'surcharge_ratio\']) + 1\n - unit_base_price *= sum_surcharge_ratio\n +# Surcharge ratio\n +unit_base_price *= 1 + result["surcharge_ratio"]\n \n - # Divide by the priced quantity\n - priced_quantity = price_parameter_dict[\'priced_quantity\']\n - if priced_quantity not in (None, 0):\n - unit_base_price /= priced_quantity\n +# Divide by the priced quantity\n +priced_quantity = result[\'priced_quantity\']\n +if priced_quantity:\n + unit_base_price /= priced_quantity\n \n -# Return result\n -if unit_base_price is None:\n - unit_base_price = default\n -return dict(price=unit_base_price, base_unit_price=price_parameter_dict.get(\'base_unit_price\'))\n -</string> </value> +result["price"] = unit_base_price\n +return result\n + + +]]></string> </value> </item> <item> <key> <string>_params</string> </key> - <value> <string>default=None, movement=None, REQUEST=None, **kw</string> </value> + <value> <string>default=None, movement=None, **kw</string> </value> </item> <item> <key> <string>id</string> </key> diff --git a/bt5/erp5_pdm/bt/revision b/bt5/erp5_pdm/bt/revision index 72b67e0ede..55b22b1aa9 100644 --- a/bt5/erp5_pdm/bt/revision +++ b/bt5/erp5_pdm/bt/revision @@ -1 +1 @@ -579 \ No newline at end of file +580 \ No newline at end of file diff --git a/product/ERP5/Document/Resource.py b/product/ERP5/Document/Resource.py index babb12acd2..f29cbdc2a3 100644 --- a/product/ERP5/Document/Resource.py +++ b/product/ERP5/Document/Resource.py @@ -743,95 +743,9 @@ class Resource(XMLObject, XMLMatrix, VariatedMixin): Consult the doc string in Movement.getPriceCalculationOperandDict for more details. """ - # First, try to use a new type-based method for the calculation. - # Note that this is based on self (i.e. a resource) instead of context - # (i.e. a movement). - method = self._getTypeBasedMethod('getPriceCalculationOperandDict') - if method is not None: - return unrestricted_apply(method, kw=dict( - default=default, movement=context, REQUEST=REQUEST, **kw)) - - # Next, try an old type-based method which returns only a final result. - method = self._getTypeBasedMethod('getPrice') - if method is not None: - price = method(default=default, movement=context, REQUEST=REQUEST, **kw) - if price is not None: - return {'price': price} - return default - - # This below is used only if any type-based method is not - # available at all. We should provide the default implementation - # in a Business Template as Resource_getPrice, thus this will not - # be used in the future. Kept only for backward compatibility in - # case where the user still uses an older Business Template. - - price_parameter_dict = self.getPriceParameterDict( - context=context, REQUEST=REQUEST, **kw) - # Calculate the unit price - unit_base_price = None - # Calculate -# ((base_price + SUM(additional_price) + -# variable_value * SUM(variable_additional_price)) * -# (1 - MIN(1, MAX(SUM(discount_ratio) , exclusive_discount_ratio ))) + -# SUM(non_discountable_additional_price)) * -# (1 + SUM(surcharge_ratio)) - # Or, as (nearly) one single line : -# ((bp + S(ap) + v * S(vap)) -# * (1 - m(1, M(S(dr), edr))) -# + S(ndap)) -# * (1 + S(sr)) - # Variable value is dynamically configurable through a python script. - # It can be anything, depending on business requirements. - # It can be seen as a way to define a pricing model that not only - # depends on discrete variations, but also on a continuous property - # of the object - - base_price = price_parameter_dict['base_price'] - if base_price in [None, '']: - # XXX Compatibility - # base_price must not be defined on resource - base_price = self.getBasePrice() - if base_price not in [None, '']: - unit_base_price = base_price - # Sum additional price - for additional_price in price_parameter_dict['additional_price']: - unit_base_price += additional_price - # Sum variable additional price - variable_value = self.getPricingVariable(context=context) - for variable_additional_price in \ - price_parameter_dict['variable_additional_price']: - unit_base_price += variable_additional_price * variable_value - # Discount - sum_discount_ratio = 0 - for discount_ratio in price_parameter_dict['discount_ratio']: - sum_discount_ratio += discount_ratio - exclusive_discount_ratio = \ - price_parameter_dict['exclusive_discount_ratio'] - d_ratio = 0 - d_ratio = max(d_ratio, sum_discount_ratio) - if exclusive_discount_ratio not in [None, '']: - d_ratio = max(d_ratio, exclusive_discount_ratio) - if d_ratio != 0: - d_ratio = 1 - min(1, d_ratio) - unit_base_price = unit_base_price * d_ratio - # Sum non discountable additional price - for non_discountable_additional_price in\ - price_parameter_dict['non_discountable_additional_price']: - unit_base_price += non_discountable_additional_price - # Surcharge ratio - sum_surcharge_ratio = 1 - for surcharge_ratio in price_parameter_dict['surcharge_ratio']: - sum_surcharge_ratio += surcharge_ratio - unit_base_price = unit_base_price * sum_surcharge_ratio - # Divide by the priced quantity if not (None, 0) - if unit_base_price is not None\ - and price_parameter_dict['priced_quantity']: - priced_quantity = price_parameter_dict['priced_quantity'] - unit_base_price = unit_base_price / priced_quantity - # Return result - if unit_base_price is not None: - return {'price': unit_base_price} - return default + kw.update(default=default, movement=context, REQUEST=REQUEST) + return unrestricted_apply( + self._getTypeBasedMethod('getPriceCalculationOperandDict'), kw=kw) security.declareProtected(Permissions.AccessContentsInformation, 'getPrice') -- 2.30.9