Commit 11f096ae authored by Nicolas Wavrant's avatar Nicolas Wavrant

erp5_pdm: support calculation of base_price applying to all items of a same slice

parent 2c6669c5
from math import log
result = context.getPriceParameterDict(context=movement, **kw)
# Calculate
# If slice_base_price:
# base_price = SUM(number_of_items_in_slice * slice_base_price) for each slice
# Then
# ((base_price + SUM(additional_price) +
# variable_value * SUM(variable_additional_price)) *
# (1 - MIN(1, MAX(SUM(discount_ratio) , exclusive_discount_ratio ))) +
......@@ -17,6 +22,20 @@ result = context.getPriceParameterDict(context=movement, **kw)
# depends on discrete variations, but also on a continuous property
# of the object
if result["slice_base_price"]:
total_price = 0.
quantity = movement.getQuantity()
sliced_base_price_list = zip(result["slice_base_price"], result["slice_quantity_range"])
for slice_price, slice_range in sliced_base_price_list:
slice_min, slice_max = slice_range
if slice_max is None:
slice_max = quantity + 1
if slice_min is None:
slice_min = 1
priced_quantity = min(slice_max - 1, quantity) - (slice_min - 1)
total_price += priced_quantity * slice_price
result["base_price"] = round(total_price / quantity, int(round(- log(result['base_unit_price'], 10),0)))
base_price = result["base_price"]
if base_price in (None, ""):
# XXX Compatibility
......
......@@ -106,6 +106,7 @@
<string>my_price_currency</string>
<string>my_start_date_range_min</string>
<string>my_start_date_range_max</string>
<string>my_base_price_per_slice</string>
</list>
</value>
</item>
......
......@@ -134,7 +134,9 @@
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>description</string> </key>
......@@ -293,4 +295,17 @@
</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>python: [\'base_price\', \'base_unit_price\', \'slice_base_price\', \'slice_quantity_range\']</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -184,6 +184,10 @@
<key> <string>update_cell_range</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>url_cells</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
......@@ -328,6 +332,12 @@
<key> <string>update_cell_range</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>url_cells</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
</value>
</item>
......
<?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>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_base_price_per_slice</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>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</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>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_checkbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Base Price Applies to Items in Slice</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<list>
<string>SupplyLine_updateBasePricePerSlice</string>
</list>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SupplyLine_changeBasePricePerSlice</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>_setBasePricePerSlice</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type_group_filter</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
supply_line = state_change['object']
price_parameter = 'base_price'
if supply_line.isBasePricePerSlice():
price_parameter = 'slice_base_price'
else:
price_parameter = 'base_price'
base_id = 'path'
supply_line.updateQuantityPredicate(price_parameter)
supply_line.updateCellRange(base_id=base_id)
supply_line = state_change['object']
base_id = 'path'
supply_line.updateCellSliceParameterList(base_id=base_id)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>SupplyLine_updateBasePricePerSlice</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -712,6 +712,8 @@ class Resource(XMLObject, XMLMatrix, VariatedMixin):
'non_discountable_additional_price': [],
'priced_quantity': None,
'base_unit_price': None,
'slice_base_price': [],
'slice_quantity_range': [],
}
if mapped_value is None:
return price_parameter_dict
......
......@@ -141,7 +141,32 @@ class SupplyLine(Path, Amount, XMLMatrix):
This method creates a new cell
"""
kwd.setdefault('base_id', 'path')
return XMLMatrix.newCell(self, *kw, **kwd)
cell = XMLMatrix.newCell(self, *kw, **kwd)
if kwd['base_id'] == 'path' and self.isBasePricePerSlice():
index = self.index[kwd['base_id']][0][kw[0]]
quantity_step_list = [None] + self.getQuantityStepList() + [None]
min_quantity = quantity_step_list[index]
max_quantity = quantity_step_list[index+1]
cell.setSliceQuantityRange((min_quantity, max_quantity))
return cell
security.declareProtected(Permissions.ModifyPortalContent, 'newCell')
def updateCellSliceParameterList(self, base_id):
quantity_step_list = [None] + self.getQuantityStepList(base_id) + [None]
for cell in self.getCellValueList():
if not self.isBasePricePerSlice():
cell.setSliceQuantityRange(None)
cell.setSliceBasePrice(None)
else:
try:
index = quantity_step_list.index(cell._range_criterion['quantity'][0])
except KeyError:
# _range_criterion is set to {} if criterion is None
index = 0
min_quantity = quantity_step_list[index]
max_quantity = quantity_step_list[index+1]
cell.setSliceQuantityRange((min_quantity, max_quantity))
cell.setSliceBasePrice(cell.getBasePrice())
############################################################
# Quantity predicate API
......@@ -153,7 +178,7 @@ class SupplyLine(Path, Amount, XMLMatrix):
Return predicate id related to a price parameter.
"""
predicate_id_start_with = "quantity_range_"
if price_parameter != "base_price":
if price_parameter not in ("base_price", "slice_base_price"):
predicate_id_start_with = "%s_%s" % \
(price_parameter, predicate_id_start_with)
# XXX Hardcoded portal type name
......@@ -183,7 +208,7 @@ class SupplyLine(Path, Amount, XMLMatrix):
"""
# We need to keep compatibility with generated accessor
price_parameter = kw.get('price_parameter', "base_price")
if price_parameter == "base_price":
if price_parameter in ("base_price", "slice_base_price"):
method_name = "_baseGetQuantityStepList"
else:
method_name = 'get%sList' % \
......@@ -208,7 +233,7 @@ class SupplyLine(Path, Amount, XMLMatrix):
# With this script, we can change the title of the predicate
script = getattr(self, 'SupplyLine_getTitle', None)
predicate_id_start_with = "quantity_range"
if price_parameter != "base_price":
if price_parameter not in ("base_price", "slice_base_price"):
predicate_id_start_with = "%s_%s" % \
(price_parameter, predicate_id_start_with)
for i in range(0, len(quantity_step_list)-1):
......@@ -218,7 +243,11 @@ class SupplyLine(Path, Amount, XMLMatrix):
p = self.newContent(id='%s_%s' % (predicate_id_start_with, str(i)),
portal_type='Predicate', int_index=i+1)
p.setCriterionPropertyList(('quantity', ))
p.setCriterion('quantity', min=min_quantity, max=max_quantity)
p.setCriterion(
'quantity',
min=min_quantity,
max=(None if price_parameter == 'slice_base_price' else max_quantity)
)
if script is not None:
title = script(min=min_quantity, max=max_quantity)
p.setTitle(title)
......
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