Commit ec87d8a7 authored by Sebastien Robin's avatar Sebastien Robin Committed by Xiaowu Zhang

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
parent 74cbad5a
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Delivery_mergeDeliveryList</string> </value> <value> <string>DeliveryModule_mergeDeliveryList</string> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
......
<?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></string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>id</string> </key>
<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>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</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 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="ERP5 Form" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<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/>
</value>
</item>
</dictionary>
</state>
</object>
</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>
<value> <string></string> </value>
</item>
<item>
<key> <string>edit_order</string> </key>
<value>
<list/>
</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>
<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>
</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>
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string></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_core (>= 5.4.3)
erp5_base erp5_base
erp5_pdm erp5_pdm
\ No newline at end of file erp5_simulation
\ No newline at end of file
...@@ -35,6 +35,7 @@ Internal Packing List Line | quantity_view ...@@ -35,6 +35,7 @@ Internal Packing List Line | quantity_view
Internal Packing List Line | view Internal Packing List Line | view
Internal Packing List Line | view_price Internal Packing List Line | view_price
Internal Packing List Module | delivery_line_report Internal Packing List Module | delivery_line_report
Internal Packing List Module | merge_delivery_list
Internal Packing List Module | view Internal Packing List Module | view
Internal Packing List Module | workflow_report Internal Packing List Module | workflow_report
Internal Packing List | details Internal Packing List | details
...@@ -106,6 +107,7 @@ Purchase Packing List Line | quantity_view ...@@ -106,6 +107,7 @@ Purchase Packing List Line | quantity_view
Purchase Packing List Line | view Purchase Packing List Line | view
Purchase Packing List Line | view_price Purchase Packing List Line | view_price
Purchase Packing List Module | delivery_line_report 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_export
Purchase Packing List Module | packing_list_report Purchase Packing List Module | packing_list_report
Purchase Packing List Module | view Purchase Packing List Module | view
...@@ -232,6 +234,7 @@ Sale Packing List Line | profile_view ...@@ -232,6 +234,7 @@ Sale Packing List Line | profile_view
Sale Packing List Line | quantity_view Sale Packing List Line | quantity_view
Sale Packing List Line | view Sale Packing List Line | view
Sale Packing List Module | delivery_line_report 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_export
Sale Packing List Module | packing_list_report Sale Packing List Module | packing_list_report
Sale Packing List Module | shipment_report Sale Packing List Module | shipment_report
......
...@@ -41,7 +41,7 @@ class CausalityAssignmentMovementGroup(MovementGroup): ...@@ -41,7 +41,7 @@ class CausalityAssignmentMovementGroup(MovementGroup):
def _getPropertyDict(self, movement, **kw): def _getPropertyDict(self, movement, **kw):
return self._addCausalityToEdit(movement) return self._addCausalityToEdit(movement)
def _separate(self, movement_list): def _separate(self, movement_list, **kw):
if not movement_list: if not movement_list:
return [] return []
property_dict = {} property_dict = {}
......
...@@ -81,12 +81,19 @@ class MovementGroup(XMLObject): ...@@ -81,12 +81,19 @@ class MovementGroup(XMLObject):
# This method should be defined in sub classes. # This method should be defined in sub classes.
raise NotImplementedError raise NotImplementedError
def _separate(self, movement_list): def _separate(self, movement_list, merge_delivery=False, **kw):
# By default, we separate movements by _getPropertyDict() values. # By default, we separate movements by _getPropertyDict() values.
# You can override this method in each MovementGroup class. # You can override this method in each MovementGroup class.
tmp_dict = {} tmp_dict = {}
first_property_dict = None
collect_order_group_id = self.getCollectOrderGroupId()
for movement in movement_list: 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 # XXX it can be wrong. we need a good way to get hash value, or
# we should compare for all pairs. # we should compare for all pairs.
key = repr(property_dict) key = repr(property_dict)
...@@ -96,11 +103,11 @@ class MovementGroup(XMLObject): ...@@ -96,11 +103,11 @@ class MovementGroup(XMLObject):
tmp_dict[key] = [[movement], property_dict] tmp_dict[key] = [[movement], property_dict]
return tmp_dict.values() return tmp_dict.values()
def separate(self, movement_list): def separate(self, movement_list, **kw):
# We sort group of simulation movements by their IDs. # We sort group of simulation movements by their IDs.
# DO NOT OVERRIDE THIS METHOD. Override _separate() instead. # DO NOT OVERRIDE THIS METHOD. Override _separate() instead.
return sorted([[sorted(x[0], key=lambda x: x.getId()), x[1]] \ 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()) key=lambda x: x[0][0].getId())
def isBranch(self): def isBranch(self):
......
...@@ -51,7 +51,7 @@ class PropertyAssignmentMovementGroup(MovementGroup): ...@@ -51,7 +51,7 @@ class PropertyAssignmentMovementGroup(MovementGroup):
# We can always update. # We can always update.
return True, property_dict return True, property_dict
def _separate(self, movement_list): def _separate(self, movement_list, **kw):
if not movement_list: if not movement_list:
return [] return []
......
...@@ -44,7 +44,7 @@ class PropertyGroupingMovementGroup(MovementGroup): ...@@ -44,7 +44,7 @@ class PropertyGroupingMovementGroup(MovementGroup):
return True, {} return True, {}
return False, {} return False, {}
def _separate(self, movement_list): def _separate(self, movement_list, **kw):
if not movement_list: if not movement_list:
return [] return []
......
...@@ -61,7 +61,7 @@ class QuantitySignMovementGroup(MovementGroup): ...@@ -61,7 +61,7 @@ class QuantitySignMovementGroup(MovementGroup):
property_dict['quantity_sign'] = cmp(quantity, 0) property_dict['quantity_sign'] = cmp(quantity, 0)
return property_dict return property_dict
def _separate(self, movement_list): def _separate(self, movement_list, **kw):
if not movement_list: if not movement_list:
return [] return []
......
...@@ -57,5 +57,5 @@ class SplitMovementGroup(MovementGroup): ...@@ -57,5 +57,5 @@ class SplitMovementGroup(MovementGroup):
def test(self, document, property_dict, **kw): def test(self, document, property_dict, **kw):
return True, property_dict return True, property_dict
def _separate(self, movement_list): def _separate(self, movement_list, **kw):
return [[[movement], {}] for movement in movement_list] return [[[movement], {}] for movement in movement_list]
...@@ -41,13 +41,15 @@ class MovementGroupNode: ...@@ -41,13 +41,15 @@ class MovementGroupNode:
# a separate method requests separating movements. # a separate method requests separating movements.
def __init__(self, movement_group_list=None, movement_list=None, def __init__(self, movement_group_list=None, movement_list=None,
last_line_movement_group=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._movement_list = []
self._group_list = [] self._group_list = []
self._movement_group = movement_group self._movement_group = movement_group
self._movement_group_list = movement_group_list self._movement_group_list = movement_group_list
self._last_line_movement_group = last_line_movement_group self._last_line_movement_group = last_line_movement_group
self._separate_method_name_list = separate_method_name_list self._separate_method_name_list = separate_method_name_list
self._merge_delivery = merge_delivery
if movement_list is not None : if movement_list is not None :
self.append(movement_list) self.append(movement_list)
...@@ -56,22 +58,24 @@ class MovementGroupNode: ...@@ -56,22 +58,24 @@ class MovementGroupNode:
movement_group=self._movement_group_list[0], movement_group=self._movement_group_list[0],
movement_group_list=self._movement_group_list[1:], movement_group_list=self._movement_group_list[1:],
last_line_movement_group=self._last_line_movement_group, 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) nested_instance.setGroupEdit(**property_dict)
split_movement_list = nested_instance.append(movement_list) split_movement_list = nested_instance.append(movement_list)
self._group_list.append(nested_instance) self._group_list.append(nested_instance)
return split_movement_list return split_movement_list
def append(self, movement_list): def append(self, movement_list, **kw):
all_split_movement_list = [] all_split_movement_list = []
if len(self._movement_group_list): if len(self._movement_group_list):
for separate_movement_list, property_dict in \ 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, split_movement_list = self._appendGroup(separate_movement_list,
property_dict) property_dict)
if len(split_movement_list): if len(split_movement_list):
if self._movement_group == self._last_line_movement_group: if self._movement_group == self._last_line_movement_group:
self.append(split_movement_list) self.append(split_movement_list, **kw)
else: else:
all_split_movement_list.extend(split_movement_list) all_split_movement_list.extend(split_movement_list)
else: else:
......
This diff is collapsed.
...@@ -104,7 +104,8 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -104,7 +104,8 @@ class BuilderMixin(XMLObject, Amount, Predicate):
security.declarePublic('build') security.declarePublic('build')
def build(self, applied_rule_uid=None, movement_relative_url_list=None, def build(self, applied_rule_uid=None, movement_relative_url_list=None,
delivery_relative_url_list=None, movement_list=None, delivery_relative_url_list=None, movement_list=None,
explanation=None, business_link=None, activate_kw=None, **kw): explanation=None, business_link=None, activate_kw=None,
merge_delivery=None, **kw):
""" """
Build deliveries from a list of movements Build deliveries from a list of movements
...@@ -139,13 +140,13 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -139,13 +140,13 @@ class BuilderMixin(XMLObject, Amount, Predicate):
if not movement_list: if not movement_list:
return [] return []
# Collect # Collect
root_group_node = self.collectMovement(movement_list) root_group_node = self.collectMovement(movement_list, merge_delivery=merge_delivery)
# Build # Build
delivery_list = self.buildDeliveryList( delivery_list = self.buildDeliveryList(
root_group_node, root_group_node,
delivery_relative_url_list=delivery_relative_url_list, delivery_relative_url_list=delivery_relative_url_list,
movement_list=movement_list, activate_kw=activate_kw, movement_list=movement_list, activate_kw=activate_kw,
**kw) merge_delivery=merge_delivery, **kw)
# Call a script after building # Call a script after building
self.callAfterBuildingScript(delivery_list, movement_list, **kw) self.callAfterBuildingScript(delivery_list, movement_list, **kw)
return delivery_list return delivery_list
...@@ -545,7 +546,7 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -545,7 +546,7 @@ class BuilderMixin(XMLObject, Amount, Predicate):
searchMovementList = UnrestrictedMethod(_searchMovementList) searchMovementList = UnrestrictedMethod(_searchMovementList)
security.declarePrivate('collectMovement') security.declarePrivate('collectMovement')
def collectMovement(self, movement_list): def collectMovement(self, movement_list, merge_delivery=False):
""" """
group movements in the way we want. Thanks to this method, we are able group movements in the way we want. Thanks to this method, we are able
to retrieve movement classed by order, resource, criterion,.... to retrieve movement classed by order, resource, criterion,....
...@@ -562,7 +563,8 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -562,7 +563,8 @@ class BuilderMixin(XMLObject, Amount, Predicate):
root_group_node = MovementGroupNode( root_group_node = MovementGroupNode(
separate_method_name_list=separate_method_name_list, separate_method_name_list=separate_method_name_list,
movement_group_list=movement_group_list, movement_group_list=movement_group_list,
last_line_movement_group=last_line_movement_group) last_line_movement_group=last_line_movement_group,
merge_delivery=merge_delivery)
root_group_node.append(movement_list) root_group_node.append(movement_list)
return root_group_node return root_group_node
...@@ -644,14 +646,16 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -644,14 +646,16 @@ class BuilderMixin(XMLObject, Amount, Predicate):
if update: if update:
delivery_to_update_list = [portal.restrictedTraverse(relative_url) for \ delivery_to_update_list = [portal.restrictedTraverse(relative_url) for \
relative_url in delivery_relative_url_list] relative_url in delivery_relative_url_list]
# Deliveries we are trying to update # Only use select method when the list of delivery is not already provided
delivery_select_method_id = self.getDeliverySelectMethodId() if len(delivery_to_update_list) == 0:
if delivery_select_method_id not in ["", None]: # Deliveries we are trying to update
to_update_delivery_sql_list = getattr(self, delivery_select_method_id) \ delivery_select_method_id = self.getDeliverySelectMethodId()
(movement_list=movement_list) if delivery_select_method_id not in ["", None]:
delivery_to_update_list.extend([sql_delivery.getObject() \ to_update_delivery_sql_list = getattr(self, delivery_select_method_id) \
for sql_delivery \ (movement_list=movement_list)
in to_update_delivery_sql_list]) delivery_to_update_list.extend([sql_delivery.getObject() \
for sql_delivery \
in to_update_delivery_sql_list])
else: else:
delivery_to_update_list = [] delivery_to_update_list = []
# We do not want to update the same object more than twice in one # We do not want to update the same object more than twice in one
...@@ -682,7 +686,8 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -682,7 +686,8 @@ class BuilderMixin(XMLObject, Amount, Predicate):
collect_order_list, movement_group_node_list=None, collect_order_list, movement_group_node_list=None,
delivery_to_update_list=None, delivery_to_update_list=None,
divergence_list=None, divergence_list=None,
activate_kw=None, force_update=0, **kw): activate_kw=None, force_update=0,
merge_delivery=None, **kw):
""" """
Build delivery from a list of movement Build delivery from a list of movement
""" """
...@@ -708,7 +713,8 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -708,7 +713,8 @@ class BuilderMixin(XMLObject, Amount, Predicate):
delivery_to_update_list=delivery_to_update_list, delivery_to_update_list=delivery_to_update_list,
divergence_list=divergence_list, divergence_list=divergence_list,
activate_kw=activate_kw, activate_kw=activate_kw,
force_update=force_update) force_update=force_update,
merge_delivery=merge_delivery)
delivery_list.extend(new_delivery_list) delivery_list.extend(new_delivery_list)
force_update = 0 force_update = 0
else: else:
...@@ -718,9 +724,14 @@ class BuilderMixin(XMLObject, Amount, Predicate): ...@@ -718,9 +724,14 @@ class BuilderMixin(XMLObject, Amount, Predicate):
x for x in delivery_to_update_list \ x for x in delivery_to_update_list \
if x.getPortalType() == self.getDeliveryPortalType() and \ if x.getPortalType() == self.getDeliveryPortalType() and \
not self._isUpdated(x, 'delivery')] not self._isUpdated(x, 'delivery')]
delivery, property_dict = self._findUpdatableObject( if merge_delivery:
delivery_to_update_list, movement_group_node_list, # We must have only one delivery to update in the case of merge
divergence_list) delivery, = delivery_to_update_list
property_dict = {}
else:
delivery, property_dict = self._findUpdatableObject(
delivery_to_update_list, movement_group_node_list,
divergence_list)
# if all deliveries are rejected in case of update, we update the # if all deliveries are rejected in case of update, we update the
# first one. # first one.
......
...@@ -1010,6 +1010,48 @@ class TestPackingListMixin(TestOrderMixin): ...@@ -1010,6 +1010,48 @@ class TestPackingListMixin(TestOrderMixin):
after_tag=after_tag, after_tag=after_tag,
).build(explanation_uid=packing_list.getCausalityValue().getUid()) ).build(explanation_uid=packing_list.getCausalityValue().getUid())
def stepMergeSplittedPackingList(self, sequence=None):
"""
Invoke the merge of the two sales packing list and check the merged packing list
Then also try to create a packing list not coming from order, and then
tro to merge it with the merged packing list
"""
# Merge the two existing packing list
packing_list1 = sequence.get('packing_list')
packing_list2 = sequence.get('new_packing_list')
self.portal.portal_simulation.mergeDeliveryList([packing_list1, packing_list2])
self.tic()
self.assertEqual('confirmed', packing_list1.getSimulationState())
self.assertEqual('cancelled', packing_list2.getSimulationState())
line, = packing_list1.objectValues(
portal_type= self.packing_list_line_portal_type)
self.assertEqual(self.default_quantity,line.getQuantity())
self.assertTrue(packing_list1.getStartDate() is not None)
self.assertTrue(packing_list1.getStopDate() is not None)
# Now clone the merged packing list, so that we will have :
# - one packing list coming from order (merged_packing_list)
# - one not coming from order (the cloned one)
cloned_packing_list = packing_list1.Base_createCloneDocument(batch_mode=True)
cloned_packing_list.setStartDate(cloned_packing_list.getStartDate() + 1)
cloned_packing_list.setStopDate(cloned_packing_list.getStopDate() + 1)
cloned_line, = cloned_packing_list.objectValues()
cloned_line.setQuantity(self.default_quantity+1)
self.portal.portal_workflow.doActionFor(cloned_packing_list, "confirm_action")
self.tic()
self.portal.portal_simulation.mergeDeliveryList([packing_list1, cloned_packing_list])
self.tic()
self.assertEqual('confirmed', packing_list1.getSimulationState())
self.assertEqual('cancelled', cloned_packing_list.getSimulationState())
resource = sequence.get('resource').getRelativeUrl()
def checkLineSet(delivery, expected_set):
line_list = delivery.getMovementList()
self.assertEqual(len(line_list), len(expected_set))
found_set = set([(x.getResource(), x.getQuantity(), x.getPrice()) for x in line_list])
expected_set = set([(resource, self.default_quantity, 555),
(resource, self.default_quantity+1, 555)])
checkLineSet(packing_list1, expected_set)
class TestPackingList(TestPackingListMixin, ERP5TypeTestCase) : class TestPackingList(TestPackingListMixin, ERP5TypeTestCase) :
run_all_test = 1 run_all_test = 1
...@@ -1020,6 +1062,8 @@ class TestPackingList(TestPackingListMixin, ERP5TypeTestCase) : ...@@ -1020,6 +1062,8 @@ class TestPackingList(TestPackingListMixin, ERP5TypeTestCase) :
Change the quantity on an delivery line, then Change the quantity on an delivery line, then
see if the packing list is divergent and then see if the packing list is divergent and then
split and defer the packing list split and defer the packing list
Finally, check we can merge if needed
""" """
if not run: return if not run: return
sequence_list = SequenceList() sequence_list = SequenceList()
...@@ -1033,6 +1077,7 @@ class TestPackingList(TestPackingListMixin, ERP5TypeTestCase) : ...@@ -1033,6 +1077,7 @@ class TestPackingList(TestPackingListMixin, ERP5TypeTestCase) :
Tic Tic
CheckPackingListIsSolved CheckPackingListIsSolved
CheckPackingListSplitted CheckPackingListSplitted
MergeSplittedPackingList
""" """
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
......
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