Commit 96e4c768 authored by Nicolas Wavrant's avatar Nicolas Wavrant

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

parent d570fb1d
from math import log
result = context.getPriceParameterDict(context=movement, **kw) result = context.getPriceParameterDict(context=movement, **kw)
# Calculate # 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) + # ((base_price + SUM(additional_price) +
# variable_value * SUM(variable_additional_price)) * # variable_value * SUM(variable_additional_price)) *
# (1 - MIN(1, MAX(SUM(discount_ratio) , exclusive_discount_ratio ))) + # (1 - MIN(1, MAX(SUM(discount_ratio) , exclusive_discount_ratio ))) +
...@@ -17,6 +22,23 @@ result = context.getPriceParameterDict(context=movement, **kw) ...@@ -17,6 +22,23 @@ result = context.getPriceParameterDict(context=movement, **kw)
# depends on discrete variations, but also on a continuous property # depends on discrete variations, but also on a continuous property
# of the object # 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
if result.get('base_unit_price', None) is None:
result["base_price"] = total_price / quantity
else:
result["base_price"] = round(total_price / quantity, int(round(- log(result['base_unit_price'], 10),0)))
base_price = result["base_price"] base_price = result["base_price"]
if base_price in (None, ""): if base_price in (None, ""):
# XXX Compatibility # XXX Compatibility
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
<item> <item>
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list/> <list>
<string>default</string>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -69,6 +71,17 @@ ...@@ -69,6 +71,17 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value>
<list>
<string>base_price</string>
<string>base_unit_price</string>
<string>slice_base_price</string>
<string>slice_quantity_range</string>
</list>
</value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_mapped_value_property_list</string> </value> <value> <string>my_mapped_value_property_list</string> </value>
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
<item> <item>
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list/> <list>
<string>default</string>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -69,6 +71,17 @@ ...@@ -69,6 +71,17 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value>
<list>
<string>base_price</string>
<string>base_unit_price</string>
<string>slice_base_price</string>
<string>slice_quantity_range</string>
</list>
</value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_mapped_value_property_list</string> </value> <value> <string>my_mapped_value_property_list</string> </value>
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
<item> <item>
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list/> <list>
<string>default</string>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -69,6 +71,17 @@ ...@@ -69,6 +71,17 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value>
<list>
<string>base_price</string>
<string>base_unit_price</string>
<string>slice_base_price</string>
<string>slice_quantity_range</string>
</list>
</value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_mapped_value_property_list</string> </value> <value> <string>my_mapped_value_property_list</string> </value>
......
...@@ -106,6 +106,7 @@ ...@@ -106,6 +106,7 @@
<string>my_price_currency</string> <string>my_price_currency</string>
<string>my_start_date_range_min</string> <string>my_start_date_range_min</string>
<string>my_start_date_range_max</string> <string>my_start_date_range_max</string>
<string>my_base_price_per_slice</string>
</list> </list>
</value> </value>
</item> </item>
......
...@@ -134,7 +134,9 @@ ...@@ -134,7 +134,9 @@
</item> </item>
<item> <item>
<key> <string>default</string> </key> <key> <string>default</string> </key>
<value> <string></string> </value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
...@@ -293,4 +295,17 @@ ...@@ -293,4 +295,17 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </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> </ZopeData>
<?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'] 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' base_id = 'path'
supply_line.updateQuantityPredicate(price_parameter) supply_line.updateQuantityPredicate(price_parameter)
supply_line.updateCellRange(base_id=base_id) supply_line.updateCellRange(base_id=base_id)
supply_line = state_change['object']
to_delete_cell_list = [
cell for cell in supply_line.getCellIdList(base_id='path')
if hasattr(supply_line, cell)
]
supply_line.manage_delObjects(ids=to_delete_cell_list)
if state_change.kwargs['workflow_method_args'][0]:
price_parameter = 'slice_base_price'
else:
price_parameter = 'base_price'
supply_line.updateQuantityPredicate(price_parameter)
supply_line.updateCellRange(base_id='path')
<?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): ...@@ -712,6 +712,8 @@ class Resource(XMLObject, XMLMatrix, VariatedMixin):
'non_discountable_additional_price': [], 'non_discountable_additional_price': [],
'priced_quantity': None, 'priced_quantity': None,
'base_unit_price': None, 'base_unit_price': None,
'slice_base_price': [],
'slice_quantity_range': [],
} }
if mapped_value is None: if mapped_value is None:
return price_parameter_dict return price_parameter_dict
......
...@@ -153,7 +153,7 @@ class SupplyLine(Path, Amount, XMLMatrix): ...@@ -153,7 +153,7 @@ class SupplyLine(Path, Amount, XMLMatrix):
Return predicate id related to a price parameter. Return predicate id related to a price parameter.
""" """
predicate_id_start_with = "quantity_range_" 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" % \ predicate_id_start_with = "%s_%s" % \
(price_parameter, predicate_id_start_with) (price_parameter, predicate_id_start_with)
# XXX Hardcoded portal type name # XXX Hardcoded portal type name
...@@ -183,12 +183,12 @@ class SupplyLine(Path, Amount, XMLMatrix): ...@@ -183,12 +183,12 @@ class SupplyLine(Path, Amount, XMLMatrix):
""" """
# We need to keep compatibility with generated accessor # We need to keep compatibility with generated accessor
price_parameter = kw.get('price_parameter', "base_price") 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" method_name = "_baseGetQuantityStepList"
else: else:
method_name = 'get%sList' % \ method_name = 'get%sList' % \
convertToUpperCase("%s_quantity_step" % price_parameter) convertToUpperCase("%s_quantity_step" % price_parameter)
return getattr(self, method_name)() return getattr(self, method_name)() or []
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
'updateQuantityPredicate') 'updateQuantityPredicate')
...@@ -208,7 +208,7 @@ class SupplyLine(Path, Amount, XMLMatrix): ...@@ -208,7 +208,7 @@ class SupplyLine(Path, Amount, XMLMatrix):
# With this script, we can change the title of the predicate # With this script, we can change the title of the predicate
script = getattr(self, 'SupplyLine_getTitle', None) script = getattr(self, 'SupplyLine_getTitle', None)
predicate_id_start_with = "quantity_range" 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" % \ predicate_id_start_with = "%s_%s" % \
(price_parameter, predicate_id_start_with) (price_parameter, predicate_id_start_with)
for i in range(0, len(quantity_step_list)-1): for i in range(0, len(quantity_step_list)-1):
...@@ -218,7 +218,11 @@ class SupplyLine(Path, Amount, XMLMatrix): ...@@ -218,7 +218,11 @@ class SupplyLine(Path, Amount, XMLMatrix):
p = self.newContent(id='%s_%s' % (predicate_id_start_with, str(i)), p = self.newContent(id='%s_%s' % (predicate_id_start_with, str(i)),
portal_type='Predicate', int_index=i+1) portal_type='Predicate', int_index=i+1)
p.setCriterionPropertyList(('quantity', )) 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: if script is not None:
title = script(min=min_quantity, max=max_quantity) title = script(min=min_quantity, max=max_quantity)
p.setTitle(title) 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