Commit b0d269b1 by Sebastien Robin

simulation: fully review the way to merge deliveries and enable merge delivery action

Fully rewrite portal_simulation.mergeDeliveryList to use builders to reconstruct new
merged delivery.

Add parameter "merge_delivery" to builder. This parameter is used when
merge should be done in such a way that movement group at delivery
level are ignored
1 parent 2ee779a4
Showing 20 changed files with 395 additions and 325 deletions
......@@ -54,7 +54,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_mergeDeliveryList</string> </value>
<value> <string>DeliveryModule_mergeDeliveryList</string> </value>
</item>
<item>
<key> <string>title</string> </key>
......
......@@ -2,11 +2,15 @@
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ERP5 Form" module="erp5.portal_type"/>
<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>
......@@ -19,7 +23,24 @@
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary/>
<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>
......@@ -28,119 +49,43 @@
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string>Delivery_mergeDeliveryList</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<key> <string>_proxy_roles</string> </key>
<value>
<list/>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>enctype</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<list>
<string>left</string>
<string>right</string>
<string>center</string>
<string>bottom</string>
<string>hidden</string>
</list>
</value>
</item>
<item>
<key> <string>groups</string> </key>
<key> <string>guard</string> </key>
<value>
<dictionary>
<item>
<key> <string>bottom</string> </key>
<value>
<list>
<string>listbox</string>
</list>
</value>
</item>
<item>
<key> <string>center</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>hidden</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>left</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>right</string> </key>
<value>
<list/>
</value>
</item>
</dictionary>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_viewMergedDeliveryList</string> </value>
</item>
<item>
<key> <string>method</string> </key>
<value> <string>POST</string> </value>
</item>
<item>
<key> <string>name</string> </key>
<value> <string>Delivery_viewMergedDeliveryList</string> </value>
</item>
<item>
<key> <string>pt</string> </key>
<value> <string>form_dialog</string> </value>
</item>
<item>
<key> <string>row_length</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>stored_encoding</string> </key>
<value> <string>UTF-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Merge Deliveries</string> </value>
</item>
<item>
<key> <string>unicode_mode</string> </key>
<value> <int>0</int> </value>
<value> <string>Delivery_cleanDeliveryAfterMerge</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Guard" module="Products.DCWorkflow.Guard"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>update_action</string> </key>
<value> <string></string> </value>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
</dictionary>
</pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>merge_delivery_list</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Merge Internal Packing Lists</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DeliveryModule_mergeDeliveryList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>merge_delivery_list</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Merge Purchase Packing Lists</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DeliveryModule_mergeDeliveryList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_action</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_action</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>merge_delivery_list</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>1.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Merge Sale Packing Lists</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Expression" module="Products.CMFCore.Expression"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/DeliveryModule_mergeDeliveryList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</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>sort</string>
<string>title</string>
<string>lines</string>
<string>list_action</string>
<string>selection_name</string>
<string>columns</string>
<string>list_method</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox</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>
<item>
<key> <string>target</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>
<item>
<key> <string>list_method</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>id</string>
<string>ID</string>
</tuple>
<tuple>
<string>portal_type</string>
<string>Type</string>
</tuple>
<tuple>
<string>title</string>
<string>Title</string>
</tuple>
<tuple>
<string>relative_url</string>
<string>Path</string>
</tuple>
<tuple>
<string>description</string>
<string>Description</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>lines</string> </key>
<value> <int>30</int> </value>
</item>
<item>
<key> <string>list_action</string> </key>
<value> <string>Folder_viewContentList</string> </value>
</item>
<item>
<key> <string>selection_name</string> </key>
<value> <string>delivery_selection</string> </value>
</item>
<item>
<key> <string>sort</string> </key>
<value>
<list>
<tuple>
<string>relative_url</string>
<string>relative_url</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Merged Deliveries</string> </value>
</item>
</dictionary>
</value>
</item>
</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:None</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>here/REQUEST/form/selection_name</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
erp5_core (>= 5.4.3)
erp5_base
erp5_pdm
\ No newline at end of file
erp5_pdm
erp5_simulation
\ No newline at end of file
......@@ -35,6 +35,7 @@ Internal Packing List Line | quantity_view
Internal Packing List Line | view
Internal Packing List Line | view_price
Internal Packing List Module | delivery_line_report
Internal Packing List Module | merge_delivery_list
Internal Packing List Module | view
Internal Packing List Module | workflow_report
Internal Packing List | details
......@@ -105,6 +106,7 @@ Purchase Packing List Line | quantity_view
Purchase Packing List Line | view
Purchase Packing List Line | view_price
Purchase Packing List Module | delivery_line_report
Purchase Packing List Module | merge_delivery_list
Purchase Packing List Module | packing_list_export
Purchase Packing List Module | packing_list_report
Purchase Packing List Module | view
......@@ -231,6 +233,7 @@ Sale Packing List Line | profile_view
Sale Packing List Line | quantity_view
Sale Packing List Line | view
Sale Packing List Module | delivery_line_report
Sale Packing List Module | merge_delivery_list
Sale Packing List Module | packing_list_export
Sale Packing List Module | packing_list_report
Sale Packing List Module | shipment_report
......
......@@ -41,7 +41,7 @@ class CausalityAssignmentMovementGroup(MovementGroup):
def _getPropertyDict(self, movement, **kw):
return self._addCausalityToEdit(movement)
def _separate(self, movement_list):
def _separate(self, movement_list, **kw):
if not movement_list:
return []
property_dict = {}
......
......@@ -81,12 +81,19 @@ class MovementGroup(XMLObject):
# This method should be defined in sub classes.
raise NotImplementedError
def _separate(self, movement_list):
def _separate(self, movement_list, merge_delivery=False, **kw):
# By default, we separate movements by _getPropertyDict() values.
# You can override this method in each MovementGroup class.
tmp_dict = {}
first_property_dict = None
collect_order_group_id = self.getCollectOrderGroupId()
for movement in movement_list:
property_dict = self._getPropertyDict(movement)
# We are in the case of merging of deliveries, thus if the movement
# is configured to not split, just take properties of the first movement
if merge_delivery and collect_order_group_id == "delivery":
property_dict = {}
else:
property_dict = self._getPropertyDict(movement, **kw)
# XXX it can be wrong. we need a good way to get hash value, or
# we should compare for all pairs.
key = repr(property_dict)
......@@ -96,11 +103,11 @@ class MovementGroup(XMLObject):
tmp_dict[key] = [[movement], property_dict]
return tmp_dict.values()
def separate(self, movement_list):
def separate(self, movement_list, **kw):
# We sort group of simulation movements by their IDs.
# DO NOT OVERRIDE THIS METHOD. Override _separate() instead.
return sorted([[sorted(x[0], key=lambda x: x.getId()), x[1]] \
for x in self._separate(movement_list)],
for x in self._separate(movement_list, **kw)],
key=lambda x: x[0][0].getId())
def isBranch(self):
......
......@@ -51,7 +51,7 @@ class PropertyAssignmentMovementGroup(MovementGroup):
# We can always update.
return True, property_dict
def _separate(self, movement_list):
def _separate(self, movement_list, **kw):
if not movement_list:
return []
......
......@@ -44,7 +44,7 @@ class PropertyGroupingMovementGroup(MovementGroup):
return True, {}
return False, {}
def _separate(self, movement_list):
def _separate(self, movement_list, **kw):
if not movement_list:
return []
......
......@@ -61,7 +61,7 @@ class QuantitySignMovementGroup(MovementGroup):
property_dict['quantity_sign'] = cmp(quantity, 0)
return property_dict
def _separate(self, movement_list):
def _separate(self, movement_list, **kw):
if not movement_list:
return []
......
......@@ -57,5 +57,5 @@ class SplitMovementGroup(MovementGroup):
def test(self, document, property_dict, **kw):
return True, property_dict
def _separate(self, movement_list):
def _separate(self, movement_list, **kw):
return [[[movement], {}] for movement in movement_list]
......@@ -41,13 +41,15 @@ class MovementGroupNode:
# a separate method requests separating movements.
def __init__(self, movement_group_list=None, movement_list=None,
last_line_movement_group=None,
separate_method_name_list=[], movement_group=None):
separate_method_name_list=[], movement_group=None,
merge_delivery=None):
self._movement_list = []
self._group_list = []
self._movement_group = movement_group
self._movement_group_list = movement_group_list
self._last_line_movement_group = last_line_movement_group
self._separate_method_name_list = separate_method_name_list
self._merge_delivery = merge_delivery
if movement_list is not None :
self.append(movement_list)
......@@ -56,22 +58,24 @@ class MovementGroupNode:
movement_group=self._movement_group_list[0],
movement_group_list=self._movement_group_list[1:],
last_line_movement_group=self._last_line_movement_group,
separate_method_name_list=self._separate_method_name_list)
separate_method_name_list=self._separate_method_name_list,
merge_delivery=self._merge_delivery)
nested_instance.setGroupEdit(**property_dict)
split_movement_list = nested_instance.append(movement_list)
self._group_list.append(nested_instance)
return split_movement_list
def append(self, movement_list):
def append(self, movement_list, **kw):
all_split_movement_list = []
if len(self._movement_group_list):
for separate_movement_list, property_dict in \
self._movement_group_list[0].separate(movement_list):
self._movement_group_list[0].separate(movement_list,
merge_delivery=self._merge_delivery):
split_movement_list = self._appendGroup(separate_movement_list,
property_dict)
if len(split_movement_list):
if self._movement_group == self._last_line_movement_group:
self.append(split_movement_list)
self.append(split_movement_list, **kw)
else:
all_split_movement_list.extend(split_movement_list)
else:
......
......@@ -101,7 +101,8 @@ class BuilderMixin(XMLObject, Amount, Predicate):
security.declarePublic('build')
def build(self, applied_rule_uid=None, movement_relative_url_list=None,
delivery_relative_url_list=None, movement_list=None,