[Erp5-report] r28471 - /erp5/trunk/products/ERP5/Document/DeliveryLine.py

nobody at svn.erp5.org nobody at svn.erp5.org
Wed Aug 19 18:31:27 CEST 2009


Author: luke
Date: Wed Aug 19 18:31:25 2009
New Revision: 28471

URL: http://svn.erp5.org?rev=28471&view=rev
Log:
 - cleanup imports
 - add delivery line solve method
 - put solving/divergence methods near each other

Modified:
    erp5/trunk/products/ERP5/Document/DeliveryLine.py

Modified: erp5/trunk/products/ERP5/Document/DeliveryLine.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/DeliveryLine.py?rev=28471&r1=28470&r2=28471&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/DeliveryLine.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/DeliveryLine.py [utf8] Wed Aug 19 18:31:25 2009
@@ -28,15 +28,13 @@
 
 from AccessControl import ClassSecurityInfo
 
-from Products.ERP5Type import Permissions, PropertySheet, Constraint, interfaces
+from Products.ERP5Type import Permissions, PropertySheet
 from Products.ERP5Type.XMLMatrix import XMLMatrix
 from Products.ERP5Type.XMLObject import XMLObject
 
 from Products.ERP5.Document.Movement import Movement
 from Products.ERP5.Variated import Variated
 from Products.ERP5.Document.ImmobilisationMovement import ImmobilisationMovement
-
-from zLOG import LOG
 
 class DeliveryLine(Movement, XMLObject, XMLMatrix, Variated,
                    ImmobilisationMovement):
@@ -225,34 +223,6 @@
 
       return XMLMatrix.newCell(self, *kw, **kwd)
 
-    security.declareProtected(Permissions.View, 'isDivergent')
-    def isDivergent(self):
-      """
-        Returns 1 if the target is not met according to the current information
-        After and edit, the isOutOfTarget will be checked. If it is 1,
-        a message is emitted
-
-        emit targetUnreachable !
-      """
-      if self.getDivergenceList() == []:
-        return 0
-      else:
-        return 1
-  
-    security.declareProtected(Permissions.View, 'getDivergenceList')
-    def getDivergenceList(self):
-      """
-      Return a list of messages that contains the divergences
-      """
-      divergence_list = []
-      if self.hasCellContent():
-        for cell in self.contentValues(filter={
-                'portal_type': self.getPortalDeliveryMovementTypeList()}):
-          divergence_list.extend(cell.getDivergenceList())
-        return divergence_list
-      else:
-        return Movement.getDivergenceList(self)
-     
     def applyToDeliveryLineRelatedMovement(self, portal_type='Simulation Movement', method_id = 'expand'):
       # Find related in simulation
       for my_simulation_movement in self.getDeliveryRelatedValueList(
@@ -395,3 +365,203 @@
         container.reindexObject()
       return Movement.manage_beforeDelete(self, item, container)
 
+# divergence support with solving
+
+    security.declareProtected(Permissions.View, 'isDivergent')
+    def isDivergent(self):
+      """
+        Returns 1 if the target is not met according to the current information
+        After and edit, the isOutOfTarget will be checked. If it is 1,
+        a message is emitted
+
+        emit targetUnreachable !
+      """
+      if self.getDivergenceList() == []:
+        return 0
+      else:
+        return 1
+
+    security.declareProtected(Permissions.View, 'getDivergenceList')
+    def getDivergenceList(self):
+      """
+      Return a list of messages that contains the divergences
+      """
+      divergence_list = []
+      if self.hasCellContent():
+        for cell in self.contentValues(filter={
+                'portal_type': self.getPortalDeliveryMovementTypeList()}):
+          divergence_list.extend(cell.getDivergenceList())
+        return divergence_list
+      else:
+        return Movement.getDivergenceList(self)
+
+    def _distributePropertyToSimulation(self, decision):
+      """Distributes property from self to all related simulation movements
+
+      AKA - accept decision"""
+      for simulation_movement in self.getDeliveryRelatedValueList(
+          portal_type='Simulation Movement'):
+        simulation_movement.edit(**{
+          decision.divergence.tested_property:
+            self.getProperty(decision.divergence.tested_property)
+        })
+
+    def _updatePropertyFromSimulation(self, decision_list):
+      """Update property from simulation
+      'Stolen' from Products.ERP5.Document.DeliveryBuilder._solveDivergence
+
+      Another possibility is to just simply copy properties or, in case of
+      quantity, add from all simulation movements.
+      """
+      simulation_movement_list = self.getDeliveryRelatedValueList(
+                                      portal_type="Simulation Movement")
+
+      business_path = simulation_movement_list[0].getCausalityValue()
+      delivery = self.getExplanationValue()
+      delivery_portal_type = delivery.getPortalType()
+      delivery_line_portal_type = self.getPortalType()
+      # we need to find only one matching delivery builder
+      for delivery_builder in business_path.getDeliveryBuilderValueList():
+        if delivery_builder.getDeliveryPortalType() == \
+             delivery_portal_type and \
+           delivery_builder.getDeliveryLinePortalType() == \
+             delivery_line_portal_type:
+          break
+      else:
+        raise ValueError('No builder found')
+
+      self.edit(quantity=0) # adoption have to 'rebuild' delivery line
+      movement_type_list = (delivery_builder.getDeliveryLinePortalType(),
+              delivery_builder.getDeliveryCellPortalType())
+      # Collect
+      root_group_node = delivery_builder.collectMovement(
+          simulation_movement_list)
+
+      divergence_list = [decision.divergence for decision in decision_list]
+
+      # Build
+      portal = self.getPortalObject()
+      delivery_module = getattr(portal, delivery_builder.getDeliveryModule())
+      delivery_to_update_list = [delivery]
+      delivery_builder._resetUpdated()
+      delivery_list = delivery_builder._processDeliveryGroup(
+        delivery_module,
+        root_group_node,
+        delivery_builder.getDeliveryMovementGroupList(),
+        delivery_to_update_list=delivery_to_update_list,
+        divergence_list=divergence_list,
+        force_update=1)
+
+      new_delivery_list = [x for x in delivery_list if x != delivery]
+      if new_delivery_list:
+        raise ValueError('No new deliveries shall be created')
+
+      # Then, we should re-apply quantity divergence according to 'Do
+      # nothing' quantity divergence list because all quantity are already
+      # calculated in adopt prevision phase.
+      quantity_dict = {}
+      for divergence in self.getDivergenceList():
+        if divergence.getProperty('divergence_scope') != 'quantity' or \
+               divergence in divergence_list:
+          continue
+        s_m = divergence.getProperty('simulation_movement')
+        delivery_movement = s_m.getDeliveryValue()
+        assert delivery_movement == self
+        quantity_gap = divergence.getProperty('decision_value') - \
+                       divergence.getProperty('prevision_value')
+        delivery_movement.setQuantity(delivery_movement.getQuantity() + \
+                                      quantity_gap)
+        quantity_dict[s_m] = \
+            divergence.getProperty('decision_value')
+
+      # Finally, recalculate delivery_ratio
+      #
+      # Here, created/updated movements are not indexed yet. So we try to
+      # gather delivery relations from simulation movements.
+      delivery_dict = {}
+      for s_m in simulation_movement_list:
+        delivery_path = s_m.getDelivery()
+        delivery_dict[delivery_path] = \
+                                     delivery_dict.get(delivery_path, []) + \
+                                     [s_m]
+
+      for s_m_list_per_movement in delivery_dict.values():
+        total_quantity = sum([quantity_dict.get(s_m, s_m.getQuantity()) \
+                              for s_m in s_m_list_per_movement])
+        if total_quantity != 0.0:
+          for s_m in s_m_list_per_movement:
+            delivery_ratio = quantity_dict.get(s_m, s_m.getQuantity()) \
+                                               / total_quantity
+            s_m.edit(delivery_ratio=delivery_ratio)
+        else:
+          for s_m in s_m_list_per_movement:
+            delivery_ratio = 1.0 / len(s_m_list_per_movement)
+            s_m.edit(delivery_ratio=delivery_ratio)
+
+    def solve(self, decision_list):
+      """Solves line according to decision list
+      decision_list is list of DivergenceDecision class instance
+      """
+
+      """How to play
+delivery_line = context
+from DateTime import DateTime
+from Products.ERP5.DivergenceDecision import DivergenceDecision
+decision_list = []
+
+# adopt
+for d in context.getDivergenceList():
+  decision = DivergenceDecision(d, 'adopt', None, None)
+  decision_list.append(decision)
+
+delivery_line.solve(decision_list)
+return 'ok'
+
+# split
+for d in delivery_line.getDivergenceList():
+  if d.tested_property == 'quantity':
+    split_kw = {}
+    split_kw.update(start_date = DateTime('2009/01/01'),
+                    stop_date = DateTime('2009/01/10'))
+    decision = DivergenceDecision(d, 'split', None, 'SplitAndDefer',
+                                  split_kw = split_kw)
+    decision_list.append(decision)
+
+delivery_line.solve(decision_list)
+return 'ok'
+
+# adopt
+for d in delivery_line.getDivergenceList():
+  if d.tested_property == 'quantity':
+    decision = DivergenceDecision(d, 'adopt', None, None)
+    decision_list.append(decision)
+
+delivery_line.solve(decision_list)
+return 'ok'
+      """
+      simulation_tool = self.getPortalObject().portal_simulation
+      solveMovement = simulation_tool.solveMovement
+      solve_result_list = []
+      # accept + split
+      for decision in [q for q in decision_list if q.decision != 'adopt']:
+        for simulation_movement in self.getDeliveryRelatedValueList(
+            portal_type='Simulation Movement'):
+          simulation_movement.appendDecision(decision)
+        if decision.decision == 'accept':
+          # accepting - in case of passed DeliverySolver use it, otherwise
+          # simply copy values to simulation
+          if not decision.delivery_solver_name:
+            self._distributePropertyToSimulation(decision)
+          solveMovement(self, decision.delivery_solver_name,
+              decision.target_solver_name)
+        elif decision.decision == 'split':
+          solveMovement(self, decision.delivery_solver_name,
+              decision.target_solver_name, **decision.split_kw)
+        else: # aka - do nothing
+          pass
+      # adopt
+      adopt_decision_list = [q for q in decision_list \
+                             if q.decision == 'adopt']
+      if adopt_decision_list:
+        # XXX/FIXME appendDecision in this case
+        self._updatePropertyFromSimulation(adopt_decision_list)




More information about the Erp5-report mailing list