From 78951be66b79e3e647eba0b5e5cbb34b482227b4 Mon Sep 17 00:00:00 2001 From: Romain Courteaud <romain@nexedi.com> Date: Thu, 5 May 2005 09:00:56 +0000 Subject: [PATCH] Modify API and implementation in order to fusion some SimulationMovement. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@2992 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5/MovementGroup.py | 305 ++++++++++++++++++++++++++++------ 1 file changed, 254 insertions(+), 51 deletions(-) diff --git a/product/ERP5/MovementGroup.py b/product/ERP5/MovementGroup.py index 3c766370f3..8ec4fa65c3 100755 --- a/product/ERP5/MovementGroup.py +++ b/product/ERP5/MovementGroup.py @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved. +# Copyright (c) 2002, 2005 Nexedi SARL and Contributors. All Rights Reserved. # Sebastien Robin <seb@nexedi.com> # Yoshinori Okuji <yo@nexedi.com> # Romain Courteaud <romain@nexedi.com> @@ -39,56 +39,64 @@ from Products.PythonScripts.Utility import allow_class class RootMovementGroup: + def __init__(self, class_list, movement=None, last_line_class_name=None, + separate_method_name_list=[]): + self._nested_class = None + self.setNestedClass(class_list=class_list) + self._movement_list = [] + self._group_list = [] + + self._class_list = class_list + self._last_line_class_name = last_line_class_name + self._separate_method_name_list = separate_method_name_list + + if movement is not None : + self.append(movement) + def getNestedClass(self, class_list): if len(class_list)>0: return class_list[0] return None - def setNestedClass(self,class_list=None): + def setNestedClass(self,class_list): """ This sets an appropriate nested class. """ - #LOG('RootGroup.setNestedClass, class_list:',0,class_list) - for i in range(len(class_list)): - #LOG('RootGroup.setNestedClass, class_list[i]:',0,class_list[i]) - #LOG('RootGroup.setNestedClass, class_list[i].getId():',0,class_list[i].getId()) - #LOG('RootGroup.setNestedClass, self.__class__:',0,self.__class__) - if class_list[i] == self.__class__: + self._nested_class = self.getNestedClass(class_list) + + def _appendGroup(self, movement): + nested_instance = self._nested_class( + movement=movement, + class_list=self._class_list[1:], + last_line_class_name=self._last_line_class_name, + separate_method_name_list=self._separate_method_name_list) + self._group_list.append(nested_instance) + + def append(self, movement): + is_movement_in_group = 0 + for group in self.getGroupList(): + if group.test(movement) : + group.append(movement) + is_movement_in_group = 1 break - else: - raise RuntimeError, "no appropriate nested class is found for %s" % str(self) - - self.nested_class = self.getNestedClass(class_list[i+1:]) - - def __init__(self, movement=None,class_list=None): - self.nested_class = None - class_list = [RootMovementGroup] + list(class_list) - self.setNestedClass(class_list=class_list) - self._movement_list = [] - self.group_list = [] - if movement is not None : - self.append(movement,class_list=class_list) + if is_movement_in_group == 0 : + if self._nested_class is not None: + self._appendGroup(movement) + else: + # We are on a node group + movement_list = self.getMovementList() + if len(movement_list) > 0: + # We have a conflict here, because it is forbidden to have + # 2 movements on the same node group + tmp_result = self._separate(movement) + self._movement_list, split_movement_list = tmp_result + # XXX Do something with split_movement_list ! + else: + # No movement on this node, we can add it + self._movement_list.append(movement) def getGroupList(self): - return self.group_list - - def appendGroup(self, movement,class_list=None): - if self.nested_class is not None: - #LOG('RootGroup.appendGroup, class_list',0,class_list) - nested_instance = self.nested_class(movement=movement,class_list=class_list) - self.group_list.append(nested_instance) - - def append(self,movement,class_list=None): - self._movement_list.append(movement) - movement_in_group = 0 - for group in self.group_list : - if group.test(movement) : - group.append(movement,class_list=class_list) - movement_in_group = 1 - break - if movement_in_group == 0 : - #LOG('RootGroup.append, class_list',0,class_list) - self.appendGroup(movement,class_list=class_list) + return self._group_list def setGroupEdit(self, **kw): """ @@ -109,15 +117,77 @@ class RootMovementGroup: """ Return movement list in the current group """ - return self._movement_list + movement_list = [] + group_list = self.getGroupList() + if len(group_list) == 0: + return self._movement_list + else: + for group in group_list: + movement_list.extend(group.getMovementList()) + return movement_list + + def _separate(self, movement): + """ + Separate 2 movements on a node group + """ + movement_list = self.getMovementList() + if len(movement_list) != 1: + raise "ProgrammingError", "Can separate only 2 movements" + else: + old_movement = self.getMovementList()[0] + + new_stored_movement = old_movement + added_movement = movement + rejected_movement = None + for separate_method_name in self._separate_method_name_list: + method = getattr(self, separate_method_name) + + new_stored_movement,\ + rejected_movement= method(new_stored_movement, + added_movement=added_movement) + added_movement = None + + return [new_stored_movement], [rejected_movement] + + ######################################################## + # Separate methods + ######################################################## + def _genericCalculation(self, movement, added_movement=None): + """ + Generic creation of FakeMovement + """ + if added_movement is not None: + # Create a fake movement + new_movement = FakeMovement([movement, added_movement]) + else: + new_movement = movement + return new_movement + + def calculateAveragePrice(self, movement, added_movement=None): + """ + Create a new movement with a average price + """ + new_movement = self._genericCalculation(movement, + added_movement=added_movement) + new_movement.setPriceMethod("getAveragePrice") + return new_movement, None + + def calculateAddQuantity(self, movement, added_movement=None): + """ + Create a new movement with the sum of quantity + """ + new_movement = self._genericCalculation(movement, + added_movement=added_movement) + new_movement.setQuantityMethod("getAddQuantity") + return new_movement, None allow_class(RootMovementGroup) class OrderMovementGroup(RootMovementGroup): - def __init__(self,movement,**kw): + def __init__(self,movement, **kw): #LOG('OrderMovementGroup.__init__, kw:',0,kw) - RootMovementGroup.__init__(self,movement,**kw) + RootMovementGroup.__init__(self, movement=movement, **kw) if hasattr(movement, 'getRootAppliedRule'): # This is a simulation movement order_value = movement.getRootAppliedRule().getCausalityValue( @@ -168,7 +238,7 @@ allow_class(OrderMovementGroup) class PathMovementGroup(RootMovementGroup): def __init__(self,movement,**kw): - RootMovementGroup.__init__(self,movement,**kw) + RootMovementGroup.__init__(self, movement=movement, **kw) self.source = movement.getSource() #LOG('PathGroup.__init__ source',0,self.source) self.destination = movement.getDestination() @@ -200,7 +270,7 @@ allow_class(PathMovementGroup) class DateMovementGroup(RootMovementGroup): def __init__(self,movement,**kw): - RootMovementGroup.__init__(self,movement,**kw) + RootMovementGroup.__init__(self, movement=movement, **kw) self.start_date = movement.getStartDate() self.stop_date = movement.getStopDate() self.setGroupEdit( @@ -220,7 +290,7 @@ allow_class(DateMovementGroup) class CriterionMovementGroup(RootMovementGroup): def __init__(self,movement,**kw): - RootMovementGroup.__init__(self,movement,**kw) + RootMovementGroup.__init__(self, movement=movement, **kw) if hasattr(movement, 'getGroupCriterion'): self.criterion = movement.getGroupCriterion() else: @@ -239,7 +309,7 @@ allow_class(CriterionMovementGroup) class ResourceMovementGroup(RootMovementGroup): def __init__(self,movement,**kw): - RootMovementGroup.__init__(self,movement,**kw) + RootMovementGroup.__init__(self, movement=movement, **kw) self.resource = movement.getResource() self.setGroupEdit( resource_value=self.resource @@ -256,7 +326,7 @@ allow_class(ResourceMovementGroup) class BaseVariantMovementGroup(RootMovementGroup): def __init__(self,movement,**kw): - RootMovementGroup.__init__(self,movement,**kw) + RootMovementGroup.__init__(self, movement=movement, **kw) self.base_category_list = movement.getVariationBaseCategoryList() if self.base_category_list is None: #LOG('BaseVariantGroup __init__', 0, 'movement = %s, movement.showDict() = %s' % (repr(movement), repr(movement.showDict()))) @@ -283,7 +353,7 @@ allow_class(BaseVariantMovementGroup) class VariantMovementGroup(RootMovementGroup): def __init__(self,movement,**kw): - RootMovementGroup.__init__(self,movement,**kw) + RootMovementGroup.__init__(self, movement=movement, **kw) self.category_list = movement.getVariationCategoryList() if self.category_list is None: #LOG('VariantGroup __init__', 0, 'movement = %s, movement.showDict() = %s' % (repr(movement), repr(movement.showDict()))) @@ -315,9 +385,8 @@ class CategoryMovementGroup(RootMovementGroup): """ This seems to be a useless class """ - def __init__(self,movement,**kw): - RootMovementGroup.__init__(self,movement,**kw) + RootMovementGroup.__init__(self, movement=movement, **kw) self.category_list = list(movement.getCategoryList()) if self.category_list is None: self.category_list = [] @@ -334,3 +403,137 @@ class CategoryMovementGroup(RootMovementGroup): return 0 allow_class(CategoryMovementGroup) + +class FakeMovement: + """ + A fake movement which simulate some methods on a movement needed + by DeliveryBuilder. + It contents a list a real ERP5 Movement and can modify them. + """ + def __init__(self, movement_list): + """ + Create a fake movement and store the list of real movement + """ + self.__price_method = None + self.__quantity_method = None + self.__movement_list = [] + for movement in movement_list: + self.append(movement) + # This object must not be use when there is not 2 or more movements + if len(movement_list) < 2: + raise "ProgrammingError", "FakeMovement used where it does not." + # All movements must share the same getVariationCategoryList + # So, verify and raise a error if not + # But, if DeliveryBuilder is well configured, this can never append ;) + reference_variation_category_list = movement_list[0].\ + getVariationCategoryList() + error_raising_needed = 0 + for movement in movement_list[1:]: + variation_category_list = movement.getVariationCategoryList() + if len(variation_category_list) !=\ + len(reference_variation_category_list): + error_raising_needed = 1 + break + + for variation_category in variation_category_list: + if variation_category not in reference_variation_category_list: + error_raising_needed = 1 + break + + if error_raising_needed == 1: + raise "ProgrammingError", "FakeMovement not well used." + + def append(self, movement): + """ + Append movement to the movement list + """ + if movement.__class__.__name__ == "FakeMovement": + self.__movement_list.extend(movement.getMovementList()) + self.__price_method = movement.__price_method + self.__quantity_method = movement.__quantity_method + else: + self.__movement_list.append(movement) + + def getMovementList(self): + """ + Return content movement list + """ + return self.__movement_list + + def _setDeliveryValue(self, object): + """ + Set Delivery value for each movement + And calculate delivery_ratio + """ + for movement in self.__movement_list: + movement._setDeliveryValue(object) + movement.setDeliveryRatio(movement.getQuantity() / object.getQuantity()) + + def getPrice(self): + """ + Return calculated price + """ + return getattr(self, self.__price_method)() + + def setPriceMethod(self, method): + """ + Set the price method + """ + self.__price_method = method + + def getQuantity(self): + """ + Return calculated quantity + """ + return getattr(self, self.__quantity_method)() + + def setQuantityMethod(self, method): + """ + Set the quantity method + """ + self.__quantity_method = method + + def getAveragePrice(self): + """ + Return average price + """ + return (self.getAddPrice() / self.getAddQuantity()) + + def getAddQuantity(self): + """ + Return the total quantity + """ + total_quantity = 0 + for movement in self.getMovementList(): + total_quantity += movement.getQuantity() + return total_quantity + + def getAddPrice(self): + """ + Return total price + """ + total_price = 0 + for movement in self.getMovementList(): + total_price += (movement.getQuantity() * movement.getPrice()) + return total_price + + def recursiveReindexObject(self): + """ + Reindex all movements + """ + for movement in self.getMovementList(): + movement.recursiveReindexObject() + + def getVariationBaseCategoryList(self): + """ + Return variation base category list + Which must be shared by all movement + """ + return self.__movement_list[0].getVariationBaseCategoryList() + + def getVariationCategoryList(self): + """ + Return variation base category list + Which must be shared by all movement + """ + return self.__movement_list[0].getVariationCategoryList() -- 2.30.9