From 08efff2cbd112085e9d8d3a988300664d9ad5dee Mon Sep 17 00:00:00 2001
From: Jean-Paul Smets <jp@nexedi.com>
Date: Mon, 10 May 2004 14:04:31 +0000
Subject: [PATCH] Initial implementation of simplified predicates

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@859 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 product/ERP5/Document/PredicateGroup.py |  85 ++++++++++++++++++-
 product/ERP5/Document/SupplyCell.py     |   2 +
 product/ERP5/Document/SupplyLine.py     | 106 +++++++++++++++++++++++-
 3 files changed, 190 insertions(+), 3 deletions(-)

diff --git a/product/ERP5/Document/PredicateGroup.py b/product/ERP5/Document/PredicateGroup.py
index f7352d9059..c7b9f5b771 100755
--- a/product/ERP5/Document/PredicateGroup.py
+++ b/product/ERP5/Document/PredicateGroup.py
@@ -28,9 +28,11 @@
 
 from Globals import InitializeClass
 from AccessControl import ClassSecurityInfo
+from Acquisition import aq_base
 
 from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
 from Products.ERP5Type.Document.Folder import Folder
+from Products.ERP5Type.Document import newTempBase
 
 from Products.ERP5.Document.Predicate import Predicate
 
@@ -122,7 +124,31 @@ identify a bank account."""
     """
       A Predicate can be tested on a given context
     """
-    pass
+    result = 1
+    if not hasattr(aq_base(self), '_identity_criterion'):
+      self._identity_criterion = {}
+      self._range_criterion = {}       
+    for property, value in self._identity_criterion.items():
+      result = result and (context.getProperty(property) == value)
+    for property, (min, max) in self._range_criterion.items():
+      value = context.getProperty(property)
+      if min is not None:
+        result = result and (value >= min)
+      if max is not None:
+        result = result and (value < max)
+    multimembership_criterion_base_category_list = self.getMultimembershipCriterionBaseCategoryList()
+    membership_criterion_base_category_list = self.getMembershipCriterionBaseCategoryList()
+    tested_base_category = {}
+    for c in self.getMembershipCriterionCategoryList():
+      bc = c.split('/')[0]
+      if not bc in tested_base_category[bc]:
+        tested_base_category[bc] = 0
+      if bc in multimembership_criterion_base_category_list:
+        tested_base_category[bc] = tested_base_category[bc] and context.isMemberOf(c)
+      elif bc in membership_criterion_base_category_list:
+        tested_base_category[bc] = tested_base_category[bc] or context.isMemberOf(c)   
+    # XXX Add here additional method calls       
+    return result and (0 not in tested_base_category.values())
 
   def asPythonExpression():
     """
@@ -145,3 +171,60 @@ identify a bank account."""
     """
     return getattr(self, 'title', self.predicate_operator)
 
+
+  security.declareProtected( Permissions.AccessContentsInformation, 'getCriterionList' )
+  def getCriterionList(self, **kw):
+    """
+      Returns a list of criterion
+    """
+    if not hasattr(aq_base(self), '_identity_criterion'):
+      self._identity_criterion = {}
+      self._range_criterion = {}       
+    criterion_dict = {}
+    for p in self.getCriterionPropertyList():
+      criterion_dict[p] = newTempBase(self, 'new_%s' % p)
+      criterion_dict[p].identity = self._identity_criterion.get(p, None)
+      criterion_dict[p].uid = 'new_%s' % p
+      criterion_dict[p].property = p
+      criterion_dict[p].min = self._range_criterion.get(p, (None, None))[0]
+      criterion_dict[p].max = self._range_criterion.get(p, (None, None))[1]
+    criterion_list = criterion_dict.values()
+    criterion_list.sort()
+    return criterion_list
+  
+  security.declareProtected( Permissions.ModifyPortalContent, 'setCriterionList' )
+  def setCriterion(self, property, identity=None, min=None, max=None, **kw):
+    if not hasattr(aq_base(self), '_identity_criterion'):
+      self._identity_criterion = {}
+      self._range_criterion = {}       
+    self._identity_criterion[property] = identity
+    self._range_criterion[property] = (min, max)
+             
+  # Predicate fusion method
+  def setPredicateCategoryList(self, category_list):
+    category_tool = aq_base(self.portal_categories)
+    base_category_id_list = category_tool.objectIds()
+    membership_criterion_category_list = []
+    membership_criterion_base_category_list = []
+    multimembership_criterion_base_category_list = []
+    for c in category_list:      
+      bc = c.split('/')[0]
+      if bc in base_category_id_list:
+        # This is a category
+        membership_criterion_category_list.append(c)
+        membership_criterion_base_category_list.append(bc)
+      else:
+        predicate_value = category_tool.resolveCategory(c)
+        if predicate_value:
+          membership_criterion_category_list.extend(
+                      predicate_value.getMembershipCriterionCategoryList())
+          membership_criterion_base_category_list.extend(
+                      predicate_value.getMembershipCriterionBaseCategoryList())
+          multimembership_criterion_base_category_list.extend(
+                      predicate_value.getMultimembershipCriterionBaseCategoryList())
+          for p in predicate_value.getCriterionList():
+            self.setCriterion(p.property, identity=p.identity, min=p.min, max=p.max)
+    self.getMembershipCriterionCategoryList(membership_criterion_category_list)
+    self.getMembershipCriterionBaseCategoryList(membership_criterion_base_category_list)
+    self.getMultimembershipCriterionBaseCategoryList(multimembership_criterion_base_category_list)                            
+         
\ No newline at end of file
diff --git a/product/ERP5/Document/SupplyCell.py b/product/ERP5/Document/SupplyCell.py
index 24b0856a49..57fbcf0535 100755
--- a/product/ERP5/Document/SupplyCell.py
+++ b/product/ERP5/Document/SupplyCell.py
@@ -65,6 +65,8 @@ class SupplyCell(DeliveryCell, Path):
                       , PropertySheet.Price
                       , PropertySheet.Path
                       , PropertySheet.FlowCapacity
+                      , PropertySheet.Predicate
+                      , PropertySheet.MappedValue
                       )
 
     # Factory Type Information
diff --git a/product/ERP5/Document/SupplyLine.py b/product/ERP5/Document/SupplyLine.py
index 88087ddb05..907d4a0c80 100755
--- a/product/ERP5/Document/SupplyLine.py
+++ b/product/ERP5/Document/SupplyLine.py
@@ -31,8 +31,10 @@ from AccessControl import ClassSecurityInfo
 
 from Products.CMFCore.WorkflowCore import WorkflowAction
 from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
+from Products.ERP5Type.XMLMatrix import XMLMatrix
 
 from Products.ERP5.Document.DeliveryLine import DeliveryLine
+from Products.ERP5.Document.Movement import Movement
 from Products.ERP5.Document.Path import Path
 
 class SupplyLine(DeliveryLine, Path):
@@ -135,7 +137,7 @@ Une ligne tarifaire."""
       return self.get(id)
 
     security.declareProtected( Permissions.ModifyPortalContent, 'hasCellContent' )
-    def hasCellContent(self, base_id='movement'):
+    def hasCellContent(self, base_id='path'):
       """
           This method can be overriden
       """
@@ -144,7 +146,7 @@ Une ligne tarifaire."""
       return len(self.contentValues()) > 0
 
     security.declareProtected( Permissions.AccessContentsInformation, 'getCellValueList' )
-    def getCellValueList(self, base_id='movement'):
+    def getCellValueList(self, base_id='path'):
       """
           This method can be overriden
       """
@@ -239,3 +241,103 @@ Une ligne tarifaire."""
       return self._getDestinationTotalPrice(self.asContext(context=context, REQUEST=REQUEST, **kw))
 
 
+    # Cell Related
+    security.declareProtected( Permissions.ModifyPortalContent, 'newCellContent' )
+    def newCellContent(self, id):
+      """
+          This method can be overriden
+      """
+      self.invokeFactory(type_name="Supply Cell",id=id)
+      return self.get(id)
+
+    security.declareProtected( Permissions.ModifyPortalContent, 'hasCellContent' )
+    def hasCellContent(self, base_id='path'):
+      """
+          This method can be overriden
+      """
+      return XMLMatrix.hasCellContent(self, base_id=base_id)
+      # If we need it faster, we can use another approach...
+      return len(self.contentValues()) > 0
+
+    security.declareProtected( Permissions.AccessContentsInformation, 'getCellValueList' )
+    def getCellValueList(self, base_id='path'):
+      """
+          This method can be overriden
+      """
+      return XMLMatrix.getCellValueList(self, base_id=base_id)
+
+    security.declareProtected( Permissions.View, 'getCell' )
+    def getCell(self, *kw , **kwd):
+      """
+          This method can be overriden
+      """
+      if 'base_id' not in kwd:
+        kwd['base_id'] = 'movement'
+
+      return XMLMatrix.getCell(self, *kw, **kwd)
+
+    security.declareProtected( Permissions.ModifyPortalContent, 'newCell' )
+    def newCell(self, *kw, **kwd):
+      """
+          This method creates a new cell
+      """
+      if 'base_id' not in kwd:
+        kwd['base_id'] = 'path'
+
+      return XMLMatrix.newCell(self, *kw, **kwd)
+
+    # For generation of matrix lines
+    security.declareProtected( Permissions.ModifyPortalContent, '_setQuantityRangeList' )
+    def _setQuantityRangeList(self, value):        
+      self._baseSetQuantityRangeList(value)
+      value = self.getQuantityRangeList()
+      value.sort()
+      for pid in self.contentIds(filter={'portal_type': 'Predicate'}):
+        self.deleteContent(pid)
+      value = value + [None]
+      for i in range(0, len(value) - 1):
+        p = self.newContent(id = 'quantity_range_%s' % i, portal_type = 'Predicate')
+        p.setCriterionPropertyList(('quantity', ))
+        p.setCriterion('quantity', min=value[i], max=value[i+1])              
+      self._setVariationCategoryList(self.getVariationCategoryList())
+    
+    security.declareProtected( Permissions.ModifyPortalContent, '_setVariationCategoryList' )
+    def _setVariationCategoryList(self, value):
+      """
+          Define the indices provided
+          one list per index (kw)
+
+          Any number of list can be provided
+      """
+      Movement._setVariationCategoryList(self, value)
+      # Update the cell range automatically
+      # This is far from easy and requires some specific wizzardry
+      base_id = 'path'
+      kwd = {'base_id': base_id}
+      new_range = self.SupplyLine_asCellRange() # This is a site dependent script
+      self._setCellRange(*new_range, **kwd )
+      #LOG('setCellRange',0,str(new_range))
+      cell_range_key_list = self.getCellRangeKeyList(base_id = base_id)
+      #LOG('cell_range_key_list',0,str(self.getCellRange(base_id = base_id)))
+      if cell_range_key_list <> [[None, None]] :
+        for k in cell_range_key_list:
+          #LOG('new cell',0,str(k))
+          c = self.newCell(*k, **kwd)
+          c.edit( domain_base_category_list = self.getVariationBaseCategoryList(),
+                  mapped_value_property_list = ( 'price',),
+                  predicate_operator = 'SUPERSET_OF',
+                  predicate_value = filter(lambda k_item: k_item is not None, k),
+                  variation_category_list = filter(lambda k_item: k_item is not None, k),
+                  force_update = 1
+                ) # Make sure we do not take aquisition into account
+      else:
+        # If only one cell, delete it
+        cell_range_id_list = self.getCellRangeIdList(base_id = base_id)
+        for k in cell_range_id_list:
+          if self.get(k) is not None:
+            self[k].flushActivity(invoke=0)
+            self[k].immediateReindexObject() # We are forced to do this is url is changed (not uid)
+            self._delObject(k)
+
+      # TO BE DONE XXX
+      # reindex cells when price, quantity or source/dest changes
-- 
2.30.9