Commit d27a2fa0 authored by Julien Muchembled's avatar Julien Muchembled

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.
parent 8f4c1b5c
......@@ -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>
......
......@@ -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
# 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>
......
579
\ No newline at end of file
580
\ No newline at end of file
......@@ -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')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment