[Erp5-report] r27622 - /erp5/trunk/products/ERP5/Document/

nobody at svn.erp5.org nobody at svn.erp5.org
Wed Jun 17 04:50:07 CEST 2009


Author: yusuke
Date: Wed Jun 17 04:50:06 2009
New Revision: 27622

URL: http://svn.erp5.org?rev=27622&view=rev
Log:
renamed from ProductionOrderRule, TransformationRule and TransformationSourcingRule under the working progress

Added:
    erp5/trunk/products/ERP5/Document/ProductionOrderModelRule.py
      - copied, changed from r27483, erp5/trunk/products/ERP5/Document/ProductionOrderRule.py
    erp5/trunk/products/ERP5/Document/TransformationModelRule.py
      - copied, changed from r27483, erp5/trunk/products/ERP5/Document/TransformationRule.py
    erp5/trunk/products/ERP5/Document/TransformationSourcingModelRule.py
      - copied, changed from r27483, erp5/trunk/products/ERP5/Document/TransformationSourcingRule.py

Copied: erp5/trunk/products/ERP5/Document/ProductionOrderModelRule.py (from r27483, erp5/trunk/products/ERP5/Document/ProductionOrderRule.py)
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/ProductionOrderModelRule.py?p2=erp5/trunk/products/ERP5/Document/ProductionOrderModelRule.py&p1=erp5/trunk/products/ERP5/Document/ProductionOrderRule.py&r1=27483&r2=27622&rev=27622&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/ProductionOrderRule.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/ProductionOrderModelRule.py [utf8] Wed Jun 17 04:50:06 2009
@@ -30,79 +30,79 @@
 from Products.ERP5Type import Permissions, PropertySheet, Constraint, interfaces
 from Products.ERP5.Document.Rule import Rule
 from Products.ERP5.Document.OrderRule import OrderRule
-from Products.ERP5.Document.TransformationRule import TransformationRuleMixin
+from Products.ERP5.Document.TransformationModelRule import TransformationModelRuleMixin
 
 from zLOG import LOG, WARNING
 
-class ProductionOrderRule(TransformationRuleMixin, OrderRule):
+class ProductionOrderModelRule(TransformationModelRuleMixin, OrderRule):
+  """
+    Prouction Order Rule object use a Supply Chain to expand a 
+    Production Order.
+  """
+
+  # CMF Type Definition
+  meta_type = 'ERP5 Production Order Model Rule'
+  portal_type = 'Production Order Model Rule'
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+  __implements = ( interfaces.IPredicate,
+                   interfaces.IRule )
+
+  # Default Properties
+  property_sheets = ( PropertySheet.Base
+                    , PropertySheet.XMLObject
+                    , PropertySheet.CategoryCore
+                    , PropertySheet.DublinCore
+                    , PropertySheet.Task
+                    , PropertySheet.AppliedRule
+                    )
+
+  # Simulation workflow
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            '_getExpandablePropertyDict')
+  def _getExpandablePropertyDict(self, applied_rule, movement, **kw):
     """
-      Prouction Order Rule object use a Supply Chain to expand a 
-      Production Order.
+    Return a Dictionary with the Properties used to edit 
+    the simulation movement.
     """
+    property_dict = {}
 
-    # CMF Type Definition
-    meta_type = 'ERP5 Production Order Rule'
-    portal_type = 'Production Order Rule'
+    default_property_list = self.getExpandablePropertyList()
+    # For backward compatibility, we keep for some time the list
+    # of hardcoded properties. Theses properties should now be
+    # defined on the rule itself
+    if len(default_property_list) == 0:
+      LOG("Order Rule , _getExpandablePropertyDict", WARNING,
+                 "Hardcoded properties set, please define your rule correctly")
+      default_property_list = (
+        'destination', 
+        'destination_section',
+        'start_date', 
+        'stop_date',
+        'resource', 
+        'variation_category_list',
+        'variation_property_dict', 
+        'aggregate_list',
+        'price', 
+        'price_currency',
+        'quantity', 
+        'quantity_unit', 
+      )
 
-    # Declarative security
-    security = ClassSecurityInfo()
-    security.declareObjectProtected(Permissions.AccessContentsInformation)
+    for prop in default_property_list:
+      property_dict[prop] = movement.getProperty(prop)
 
-    __implements = ( interfaces.IPredicate,
-                     interfaces.IRule )
+    explanation = self.getExplanation(applied_rule=applied_rule)
+    path = self.getSpecialise(applied_rule=applied_rule).getRootExplanationValue()
+    property_dict['source_section'] = path.getDestinationSection(explanation)
+    property_dict['source'] = path.getDestination(explanation)
 
-    # Default Properties
-    property_sheets = ( PropertySheet.Base
-                      , PropertySheet.XMLObject
-                      , PropertySheet.CategoryCore
-                      , PropertySheet.DublinCore
-                      , PropertySheet.Task
-                      , PropertySheet.AppliedRule
-                      )
+    import pdb; pdb.set_trace()
+    successor = path.getSuccessorValue()
+    if successor is not None:
+      property_dict['causality_list'] = successor.getPredecessorRelatedList()
 
-    # Simulation workflow
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              '_getExpandablePropertyDict')
-    def _getExpandablePropertyDict(self, applied_rule, movement, **kw):
-      """
-      Return a Dictionary with the Properties used to edit 
-      the simulation movement.
-      """
-      property_dict = {}
-
-      default_property_list = self.getExpandablePropertyList()
-      # For backward compatibility, we keep for some time the list
-      # of hardcoded properties. Theses properties should now be
-      # defined on the rule itself
-      if len(default_property_list) == 0:
-        LOG("Order Rule , _getExpandablePropertyDict", WARNING,
-                   "Hardcoded properties set, please define your rule correctly")
-        default_property_list = (
-          'destination', 
-          'destination_section',
-          'start_date', 
-          'stop_date',
-          'resource', 
-          'variation_category_list',
-          'variation_property_dict', 
-          'aggregate_list',
-          'price', 
-          'price_currency',
-          'quantity', 
-          'quantity_unit', 
-        )
-    
-      root_explanation = self.getRootExplanation(
-          self.getBusinessProcess(applied_rule=applied_rule))
-      property_dict['source_section'] = root_explanation.getSourceSection()
-      source_method_id = root_explanation.getSourceMethodId()
-      if source_method_id is None:
-        property_dict['source'] = root_explanation.getSource()
-      else:
-        property_dict['source'] = getattr(root_explanation, source_method_id)()
-      property_dict['causality'] = root_explanation.getRelativeUrl()
-
-      for prop in default_property_list:
-        property_dict[prop] = movement.getProperty(prop)
-    
-      return property_dict
+    return property_dict

Copied: erp5/trunk/products/ERP5/Document/TransformationModelRule.py (from r27483, erp5/trunk/products/ERP5/Document/TransformationRule.py)
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/TransformationModelRule.py?p2=erp5/trunk/products/ERP5/Document/TransformationModelRule.py&p1=erp5/trunk/products/ERP5/Document/TransformationRule.py&r1=27483&r2=27622&rev=27622&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/TransformationRule.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/TransformationModelRule.py [utf8] Wed Jun 17 04:50:06 2009
@@ -43,7 +43,7 @@
     """
     return the list of a request which to be used to apply movements
     """
-    raise NotImplementedError, 'Must be implemented'
+    raise NotImplementedError, 'Must be implemented on each child'
 
   def _getCausalityList(self, causality=None, causality_value=None,
                         causality_list=None, causality_value_list=None,
@@ -101,7 +101,7 @@
       diff_movement.edit(**request)
 
 
-class TransformationMovementFactory(MovementFactory):
+class TransformationModelMovementFactory(MovementFactory):
   def __init__(self):
     self.product = None # base information to use for making movements
     self.produced_list = list()
@@ -132,7 +132,7 @@
     return _list
 
 
-class TransformationRuleMixin(Base):
+class TransformationModelRuleMixin(Base):
   security = ClassSecurityInfo()
 
   security.declareProtected(Permissions.View, 'getTransformation')
@@ -146,7 +146,7 @@
     order_movement = movement.getRootSimulationMovement().getOrderValue()
     explanation = self.getExplanation(movement=movement,
                                       applied_rule=applied_rule)
-    # find line recursively
+    # find the line of order recursively
     order_line = order_movement
     while order_line.getParentValue() != explanation:
       order_line = order_line.getParentValue()
@@ -166,31 +166,25 @@
     if transformation.getResource() == movement.getResource():
       return transformation
 
-  security.declareProtected(Permissions.View, 'getBusinessProcess')
-  def getBusinessProcess(self, **kwargs):
-    """
-    Return business process related to root causality.
-    """
-    explanation = self.getExplanation(**kwargs)
+  security.declareProtected(Permissions.View, 'getSpecialise')
+  def getSpecialise(self, movement=None, applied_rule=None, portal_type_list=None):
+    """
+    Return a business process related to the root causality.
+    """
+    if portal_type_list is None:
+      portal_type_list = self.getPortalBusinessProcessTypeList()
+
+    explanation = self.getExplanation(movement=movement,
+                                      applied_rule=applied_rule)
     if explanation is not None:
       specialise = explanation.getSpecialiseValue()
       business_process_type_list = self.getPortalBusinessProcessTypeList()
       # because trade condition can be specialised
       while specialise is not None and \
-            specialise.getPortalType() not in business_process_type_list:
+            hasattr(specialise, 'getSpecialiseValue') and \
+            specialise.getPortalType() not in portal_type_list:
         specialise = specialise.getSpecialiseValue()
       return specialise
-
-  security.declareProtected(Permissions.View, 'getRootExplanation')
-  def getRootExplanation(self, business_process):
-    """
-    the method of ProductionOrderRule returns most tail path of business process
-    """
-    if business_process is not None:
-      for business_path in business_process.contentValues(
-        portal_type=self.getPortalBusinessPathTypeList()):
-        if business_path.isDeliverable():
-          return business_path
 
   security.declareProtected(Permissions.View, 'getExplanation')
   def getExplanation(self, movement=None, applied_rule=None):
@@ -200,14 +194,22 @@
       return movement.getRootSimulationMovement()\
              .getOrderValue().getExplanationValue()
 
-
-class TransformationRule(TransformationRuleMixin, Rule):
+  def getHeadProductionPathValueList(self, transformation, business_process):
+    """
+    Return list of path which is head of transformation trade_phases
+    """
+    return business_process.getHeadPathValueList(
+      set([amount.getTradePhase()
+           for amount in transformation.getAggregatedAmountList()]))
+
+
+class TransformationModelRule(TransformationModelRuleMixin, Rule):
   """
   """
 
   # CMF Type Definition
-  meta_type = 'ERP5 Transformation Rule'
-  portal_type = 'Transformation Rule'
+  meta_type = 'ERP5 Transformation Model Rule'
+  portal_type = 'Transformation Model Rule'
   # Declarative security
   security = ClassSecurityInfo()
   security.declareObjectProtected(Permissions.AccessContentsInformation)
@@ -222,43 +224,8 @@
                       , PropertySheet.Task
                       )
 
-  def getHeadProductionPathList(self, transformation, business_process):
-    """
-    Return list of path which is head of transformation trade_phases
-
-    this method assumes trade_phase of head paths is only one
-    """
-    production_trade_phase_set = set([amount.getTradePhase()
-                                      for amount in transformation\
-                                      .getAggregatedAmountList()])
-    head_path_list = []
-    for state in business_process.objectValues(
-      portal_type=self.getPortalBusinessStateTypeList()):
-      if len(state.getSuccessorRelatedValueList()) == 0:
-        head_path_list.extend(state.getPredecessorRelatedValueList())
-
-    result_list = []
-    for path in head_path_list:
-      result_list += self._getHeadPathByTradePhaseList(path, production_trade_phase_set)
-
-    return map(lambda t: t[0], filter(lambda t: t != (None, None), result_list))
-
-  def _getHeadPathByTradePhaseList(self, path, trade_phase_set):
-    _set = set(path.getTradePhaseList())
-    if _set & trade_phase_set:
-      return [(path, _set & trade_phase_set)]
-
-    successor_node = path.getSuccessorValue()
-    if successor_node is None:
-      return [(None, None)]
-
-    _list = []
-    for next_path in successor_node.getPredecessorRelatedValueList():
-      _list += self._getHeadPathByTradePhaseList(next_path, trade_phase_set)
-    return _list
-
   def getFactory(self):
-    return TransformationMovementFactory()
+    return TransformationModelMovementFactory()
 
   security.declareProtected(Permissions.ModifyPortalContent, 'expand')
   def expand(self, applied_rule, **kw):
@@ -267,15 +234,16 @@
     parent_movement = applied_rule.getParentValue()
 
     transformation = self.getTransformation(movement=parent_movement)
-    business_process = self.getBusinessProcess(movement=parent_movement)
+    business_process = self.getSpecialise(movement=parent_movement)
     explanation = self.getExplanation(movement=parent_movement)
 
     # get all trade_phase of the Business Process
     trade_phase_list = business_process.getTradePhaseList()
 
     # get head of production path from business process with trade_phase_list
-    head_production_path_list = self.getHeadProductionPathList(transformation,
-                                                               business_process)
+    head_production_path_value_list = self.getHeadProductionPathValueList(transformation,
+                                                                          business_process)
+    # the factory which is to make simulation movements
     factory = self.getFactory()
     factory.product = dict(
       resource=transformation.getResource(),
@@ -288,121 +256,97 @@
     amount_dict = {}
     for amount in transformation.getAggregatedAmountList():
       phase = amount.getTradePhase()
-
       if phase not in trade_phase_list:
         raise TransformationRuleError,\
-              "Trade phase %r is not part of Business Process %r" % (phase, business_process)
-
+              "the trade phase %r is not part of Business Process %r" % (phase, business_process)
       amount_dict.setdefault(phase, [])
       amount_dict[phase].append(amount)
 
     last_phase_path_list = list() # to keep phase_path_list
     last_prop_dict = dict()
     for (phase, amount_list) in amount_dict.items():
-      phase_path_list = business_process.getPathValueList(phase)
+      phase_path_value_list = business_process.getPathValueList(phase)
       """
       XXX: In this context, we assume quantity as ratio,
-      but this "quantity as ratio" is consistent with transformation.
+           but this "quantity as ratio" is consistent with transformation.
       """
-      if sum(map(lambda path: path.getQuantity(), phase_path_list)) != 1:
+      if sum(map(lambda path: path.getQuantity(), phase_path_value_list)) != 1:
         raise TransformationRuleError,\
-              "sum ratio of Trade Phase %r of Business Process %r is not one"\
+              "the sum ratio at the Trade Phase %r on the Business Process %r is not 1"\
               % (phase, business_process)
 
-      for path in phase_path_list:
-        # source, source_section
-        source_section = path.getSourceSection() # only support a static access 
-        source_method_id = path.getSourceMethodId()
-        if source_method_id is None:
-          source = path.getSource()
-        else:
-          source = getattr(path, source_method_id)()
-        # destination, destination_section
-        destination_section = path.getDestinationSection() # only support a static access 
-        destination_method_id = path.getDestinationMethodId()
-        if destination_method_id is None:
-          destination = path.getDestination()
-        else:
-          destination = getattr(path, destination_method_id)()
-
-        start_date = path.getExpectedStartDate(explanation)
-        stop_date = path.getExpectedStopDate(explanation)
+      for path in phase_path_value_list:
+        path_common_dict = dict(causality_value=path,
+                                start_date=path.getExpectedStartDate(explanation),
+                                stop_date=path.getExpectedStopDate(explanation))
+
+        # the quantity which is produced/consumed at the path.
+        quantity = factory.product['quantity'] * path.getQuantity()
+
+        # nodes at the path
+        source_section = path.getSourceSection(explanation)
+        destination_section = path.getDestinationSection(explanation)
+        source = path.getSource(explanation)
+        destination = path.getDestination(explanation)
+
+        # the remaining at the start and the end on the path
         predecessor_remaining_phase_list = path.getPredecessorValue()\
           .getRemainingTradePhaseList(explanation,
                                       trade_phase_list=trade_phase_list)
         successor_remaining_phase_list = path.getSuccessorValue()\
           .getRemainingTradePhaseList(explanation,
                                       trade_phase_list=trade_phase_list)
-
-        # checking which is not last path of transformation
+ 
+        consumed_common_dict = dict(source_section=source_section,
+                                    destination_section=destination_section,
+                                    source=source,
+                                    **path_common_dict)
+
+        produced_common_dict = dict(source_section=source_section,
+                                    destination_section=destination_section,
+                                    destination=destination,
+                                    trade_phase_value_list=successor_remaining_phase_list,
+                                    **path_common_dict)
+
+        # when the path is not a part in the last phase on the transformation.
         if len(successor_remaining_phase_list) != 0:
           # partial produced movement
           factory.requestProduced(
-            causality_value=path,
-            start_date=start_date,
-            stop_date=stop_date,
-            # when last path of transformation, path.getQuantity() will be return 1.
-            quantity=factory.product['quantity'] * path.getQuantity(),
-            source_section=source_section,
-            destination_section=destination_section,
-            destination=destination,
-            trade_phase_value_list=successor_remaining_phase_list)
+            quantity=quantity,
+            **produced_common_dict)
         else:
-          # for making movement of last product of the transformation
           last_phase_path_list.append(path)
 
-          # path params must be same
-          if last_prop_dict.get('start_date', None) is None:
-            last_prop_dict['start_date'] = start_date
-          if last_prop_dict.get('stop_date', None) is None:
-            last_prop_dict['stop_date'] = stop_date
-          # trade phase of product is must be empty []
-          if last_prop_dict.get('trade_phase_value_list', None) is None:
-            last_prop_dict['trade_phase_value_list'] = successor_remaining_phase_list
-          if last_prop_dict.get('source_section', None) is None:
-            last_prop_dict['source_section'] = source_section
-          # for the source, it is not need, because the produced.
-          if last_prop_dict.get('destination_section', None) is None:
-            last_prop_dict['destination_section'] = destination_section
-          if last_prop_dict.get('destination', None) is None:
-            last_prop_dict['destination'] = destination
-
-          if last_prop_dict['start_date'] != start_date or\
-             last_prop_dict['stop_date'] != stop_date or\
-             last_prop_dict['trade_phase_value_list'] != successor_remaining_phase_list or\
-             last_prop_dict['source_section'] != source_section or\
-             last_prop_dict['destination_section'] != destination_section or\
-             last_prop_dict['destination'] != destination:
+          # used for matching
+          work_dict = dict(filter(lambda x: x[0] != 'causality_value',
+                                  produced_common_dict.items()))
+
+          # when empty
+          if not last_prop_dict:
+            last_prop_dict.update(work_dict)
+
+          # must be same, because the path(s) are integrated in the last phase on the transformation.
+          if last_prop_dict != work_dict:
             raise TransformationRuleError,\
-              """Returned property is different on Transformation %r and Business Process %r"""\
+                  """the Properties which is used to make a movement on the last path
+are different with the Transformation %r and the Business Process %r"""\
               % (transformation, business_process)
 
-        # when the path is part of production but not first, consume previous partial product
-        if path not in head_production_path_list:
+        # when the path is part of production, but not first, consume previous partial product
+        if path not in head_production_path_value_list:
           factory.requestConsumed(
-            causality_value=path,
-            start_date=start_date,
-            stop_date=stop_date,
-            quantity=factory.product['quantity'] * path.getQuantity(),
-            source_section=source_section,
-            destination_section=destination_section,
-            source=source,
-            trade_phase_value_list=predecessor_remaining_phase_list)
+            quantity=quantity,
+            trade_phase_value_list=predecessor_remaining_phase_list,
+            **consumed_common_dict)
 
         # consumed movement
         for amount in amount_list:
           factory.requestConsumed(
-            causality_value=path,
-            start_date=start_date,
-            stop_date=stop_date,
             resource=amount.getResource(),
-            quantity=factory.product['quantity'] * amount.getQuantity()\
-              / amount.getEfficiency() * path.getQuantity(),
+            quantity=quantity * amount.getQuantity() / amount.getEfficiency(),
             quantity_unit=amount.getQuantityUnit(),
-            source_section=source_section,
-            destination_section=destination_section,
-            source=source,
-            trade_phase=path.getTradePhase())
+            trade_phase=path.getTradePhase(),
+            **consumed_common_dict)
 
     """
     valid graph for transformation
@@ -427,14 +371,22 @@
     # when empty
     if last_phase_path_list is None or len(last_phase_path_list) == 0:
       raise TransformationRuleError,\
-            """Could not make the product by Transformation %r and Business Process %r,
-which last_phase_path_list is empty.""" % (transformation, business_process)
+            """could not make the product with the Transformation %r on the Business Process %r,
+because last_phase_path_list is empty.""" % (transformation, business_process)
 
     factory.requestProduced(
       causality_value_list=last_phase_path_list,
-      # when last path of transformation, path.getQuantity() will be return 1.
-      quantity=factory.product['quantity'] * path.getQuantity(),
+      # in the last phase of transformation, produced quantity must be planned as same as ordered.
+      quantity=factory.product['quantity'],
       **last_prop_dict)
 
+    # make actual simulation movements
     factory.makeMovements(applied_rule)
+
     Rule.expand(self, applied_rule, **kw)
+
+  # Deliverability / orderability
+  def isDeliverable(self, m):
+    return 1
+  def isOrderable(self, m):
+    return 0

Copied: erp5/trunk/products/ERP5/Document/TransformationSourcingModelRule.py (from r27483, erp5/trunk/products/ERP5/Document/TransformationSourcingRule.py)
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/TransformationSourcingModelRule.py?p2=erp5/trunk/products/ERP5/Document/TransformationSourcingModelRule.py&p1=erp5/trunk/products/ERP5/Document/TransformationSourcingRule.py&r1=27483&r2=27622&rev=27622&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/TransformationSourcingRule.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/TransformationSourcingModelRule.py [utf8] Wed Jun 17 04:50:06 2009
@@ -33,7 +33,7 @@
 
 from Products.ERP5Type import Permissions, PropertySheet, Constraint, interfaces
 from Products.ERP5.Document.Rule import Rule
-from Products.ERP5.Document.TransformationRule import MovementFactory, TransformationRuleMixin
+from Products.ERP5.Document.TransformationModelRule import MovementFactory, TransformationModelRuleMixin
 
 from zLOG import LOG
 
@@ -49,14 +49,14 @@
   def getRequestList(self):
     return self.request_list
 
-class TransformationSourcingRule(TransformationRuleMixin, Rule):
+class TransformationSourcingModelRule(TransformationModelRuleMixin, Rule):
   """
   Transformation Sourcing Rule object make sure
   items required in a Transformation are sourced
   """
   # CMF Type Definition
-  meta_type = 'ERP5 Transformation Sourcing Rule'
-  portal_type = 'Transformation Sourcing Rule'
+  meta_type = 'ERP5 Transformation Sourcing Model Rule'
+  portal_type = 'Transformation Sourcing Model Rule'
   # Declarative security
   security = ClassSecurityInfo()
   security.declareObjectProtected(Permissions.AccessContentsInformation)
@@ -94,20 +94,10 @@
 
     path = path_list[0]
 
-    # source, source_section
-    source_section = path.getSourceSection() # only support a static access 
-    source_method_id = path.getSourceMethodId()
-    if source_method_id is None:
-      source = path.getSource()
-    else:
-      source = getattr(path, source_method_id)()
-    # destination, destination_section
-    destination_section = path.getDestinationSection() # only support a static access 
-    destination_method_id = path.getDestinationMethodId()
-    if destination_method_id is None:
-      destination = path.getDestination()
-    else:
-      destination = getattr(path, destination_method_id)()
+    source_section = self.getSourceSection(path, applied_rule=applied_rule)
+    destination_section = self.getDestinationSection(path, applied_rule=applied_rule)
+    source = self.getSource(path, applied_rule=applied_rule)
+    destination = self.getDestination(path, applied_rule=applied_rule)
 
     start_date = path.getExpectedStartDate(explanation)
     stop_date = path.getExpectedStopDate(explanation)
@@ -138,3 +128,14 @@
     factory.makeMovements(applied_rule)
     Rule.expand(self, applied_rule, **kw)
 
+  def isDeliverable(self, m):
+    resource = m.getResource()
+    # operation is not deliverable
+    if resource is None or \
+       resource.find('operation/') >= 0:
+      return 0
+    else:
+      return 1
+
+  def isOrderable(self, m):
+    return 0




More information about the Erp5-report mailing list