Commit 01872342 authored by Jean-Paul Smets's avatar Jean-Paul Smets

New Predicate API


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@3274 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent cf11d044
......@@ -31,7 +31,7 @@
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.PredicateGroup import PredicateGroup as Predicate
from Products.ERP5.Document.Predicate import Predicate
from Products.ERP5.Document.Invoice import Invoice
class AccountingRuleCell(Predicate, Invoice):
......
......@@ -194,9 +194,9 @@ Une ligne tarifaire."""
"""
return self.getStopDate()
# SKU vs. CU
security.declareProtected(Permissions.AccessContentsInformation, 'getSourceStandardInventoriatedQuantity')
def getSourceStandardInventoriatedQuantity(self):
# Pricing in standard currency
security.declareProtected(Permissions.AccessContentsInformation, 'getPrice')
def getPrice(self):
"""
The inventoriated quantity converted in a default unit
......@@ -211,24 +211,5 @@ Une ligne tarifaire."""
if source is not None and resource is not None:
return resource.convertCurrency(result, source.getPriceCurrencyValue())
return None
security.declareProtected(Permissions.AccessContentsInformation, 'getDestinationStandardInventoriatedQuantity')
def getDestinationStandardInventoriatedQuantity(self):
"""
The inventoriated quantity converted in a default unit
For assortments, returns the inventoriated quantity in terms of number of items
in the assortemnt.
For accounting, returns the quantity converted in a default unit
"""
result = self.getInventoriatedQuantity()
resource = self.getResourceValue()
destination = self.getSourceValue()
if destination is not None and resource is not None:
return resource.convertCurrency(result, destination.getPriceCurrencyValue())
return None
\ No newline at end of file
......@@ -29,11 +29,11 @@
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.Amount import Amount
from Products.ERP5.Document.SetMappedValue import SetMappedValue
from Products.ERP5.Document.MappedValue import MappedValue
from zLOG import LOG
class AmountFilter(SetMappedValue, Amount):
class AmountFilter(MappedValue, Amount):
"""
An AmountFilter allows to define last minute
changes in a transformation. For example: different
......
......@@ -32,12 +32,12 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5.Document.MetaNode import MetaNode
from Products.ERP5.Document.MetaResource import MetaResource
from Products.ERP5Type import Interface, Permissions, PropertySheet
from Products.ERP5.Document.PredicateGroup import PredicateGroup
from Products.ERP5.Document.Predicate import Predicate
from zLOG import LOG
class Category(CMFCategory, PredicateGroup, MetaNode, MetaResource):
class Category(CMFCategory, Predicate, MetaNode, MetaResource):
"""
Category objects allow to define classification categories
in an ERP5 portal. For example, a document may be assigned a color
......@@ -106,5 +106,7 @@ class Category(CMFCategory, PredicateGroup, MetaNode, MetaResource):
)
property_sheets = ( PropertySheet.Base
, PropertySheet.SimpleItem )
, PropertySheet.SimpleItem
, PropertySheet.CategoryCore )
......@@ -31,9 +31,9 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.PredicateGroup import PredicateGroup
from Products.ERP5.Document.Predicate import Predicate
class Domain(PredicateGroup):
class Domain(Predicate):
"""
An abstract class subclassed by reports and mapped values
......
......@@ -49,6 +49,11 @@ class MappedValue(Domain, Amount):
MappedValue.
XXX - Amount should be remove from here
Interesting Idea: properties and categories of the mapped value
(not of the predicate) could be handled through additional matrix
dimensions rather than through ad-hoc definition.
"""
meta_type = 'ERP5 Mapped Value'
portal_type = 'Mapped Value'
......
......@@ -26,40 +26,239 @@
#
##############################################################################
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from Acquisition import aq_base, aq_inner
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5Type.Document.Folder import Folder
from Products.ERP5Type.Document import newTempBase
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Utils import convertToUpperCase
from zLOG import LOG
class Predicate:
class Predicate(Folder):
"""
Mix-in class for Predicate
A predicate group allows to combine simple predicates
"""
meta_type = 'ERP5 Predicate'
portal_type = 'Predicate'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
isPredicate = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.View)
security.declareProtected( Permissions.View, 'getOperatorList' )
def getOperatorList(self):
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.Predicate
, PropertySheet.SortIndex
)
# Declarative interfaces
__implements__ = ( Interface.Predicate )
def test(self, context,**kw):
"""
A Predicate can be tested on a given context
We can pass parameters in order to ignore some conditions.
"""
self = self.asPredicate()
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)
#LOG('context.getProperty', 0, repr(( result, property, 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)
#LOG('self._range_criterion.items min', 0, repr(( result, property, context.getProperty(property), min )))
if max is not None:
result = result and (value < max)
#LOG('self._range_criterion.items max', 0, repr(( result, property, context.getProperty(property), 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.keys() and bc in multimembership_criterion_base_category_list:
tested_base_category[bc] = 1
elif not bc in tested_base_category.keys() and bc in membership_criterion_base_category_list:
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)
result = result and (0 not in tested_base_category.values())
#LOG('self.getMembershipCriterionCategoryList', 0, repr(( result, tested_base_category.items() )))
# Test method calls
test_method_id = self.getTestMethodId()
if test_method_id is not None and result:
method = getattr(context,test_method_id)
result = result and method()
#LOG('self.getTestMethodId', 0, repr(( result, test_method_id, method() )))
# XXX Add here additional method calls
return result
def asPythonExpression():
"""
A Predicate can be rendered as a python expression. This
is the preferred approach within Zope.
"""
pass
def asSqlExpression():
"""
A Predicate can use a built-in operator
A Predicate can be rendered as a python expression. This
is the preferred approach within Zope.
"""
return map(lambda o: o['id'], self._operators)
pass
security.declareProtected( Permissions.View, 'getTypeList' )
def getTypeList(self):
security.declareProtected( Permissions.AccessContentsInformation, 'getCriterionList' )
def getCriterionList(self, **kw):
"""
A Predicate can use a built-in operator
Returns a list of criterion
"""
return ('string', 'int', 'float', 'date', 'set')
#security.declareProtected( Permissions.View, 'getTitle' )
#def getTitle(self):
# """
# The title of a predicate is its operator representations
# """
# return "%s %s %s" % (self.predicate_property, self.predicate_operator, self.predicate_value)
# Compatibility
security.declareProtected( Permissions.View, 'getPredicateAttribute' )
def getPredicateAttribute(self):
return self.getPredicateProperty()
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, 'setCriterion' )
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 = {}
if identity != None :
self._identity_criterion[property] = identity
if min != '' or max != '' :
self._range_criterion[property] = (min, max)
self.reindexObject()
security.declareProtected( Permissions.ModifyPortalContent, 'edit' )
def edit(self, **kwd) :
if not hasattr(aq_base(self), '_identity_criterion'):
self._identity_criterion = {}
self._range_criterion = {}
if 'criterion_property_list' in kwd.keys() :
criterion_property_list = kwd['criterion_property_list']
identity_criterion = {}
range_criterion = {}
for criterion in self._identity_criterion.keys() :
if criterion in criterion_property_list :
identity_criterion[criterion] = self._identity_criterion[criterion]
for criterion in self._range_criterion.keys() :
if criterion in criterion_property_list :
range_criterion[criterion] = self._range_criterion[criterion]
self._identity_criterion = identity_criterion
self._range_criterion = range_criterion
return self._edit(**kwd)
# Predicate fusion method
def setPredicateCategoryList(self, category_list):
category_tool = aq_inner(self.portal_categories)
base_category_id_list = category_tool.objectIds()
membership_criterion_category_list = []
membership_criterion_base_category_list = []
multimembership_criterion_base_category_list = []
test_method_id_list = []
criterion_property_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 is not None:
criterion_property_list.extend(predicate_value.getCriterionPropertyList())
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())
test_method_id_list += list(predicate_value.getTestMethodIdList() or [])
for p in predicate_value.getCriterionList():
self.setCriterion(p.property, identity=p.identity, min=p.min, max=p.max)
self.setCriterionPropertyList(criterion_property_list)
self._setMembershipCriterionCategoryList(membership_criterion_category_list)
self._setMembershipCriterionBaseCategoryList(membership_criterion_base_category_list)
self._setMultimembershipCriterionBaseCategoryList(multimembership_criterion_base_category_list)
self._setTestMethodIdList(test_method_id_list)
self.reindexObject()
# Predicate handling
security.declareProtected(Permissions.AccessContentsInformation, 'asPredicate')
def asPredicate(self):
"""
Returns a temporary Predicate based on the Resource properties
"""
category_tool = getToolByName(self,'portal_categories')
membership_criterion_category_list = list(self.getMembershipCriterionCategoryList())
multimembership_criterion_base_category_list = list(self.getMultimembershipCriterionBaseCategoryList())
# Look at local and acquired categories and make it criterion membership
for base_category in self.getPortalCriterionBaseCategoryList():
category_list = self.getProperty(base_category + '_list')
if category_list is not None and len(category_list)>0:
for category in category_list:
membership_criterion_category_list.append(base_category + '/' + category)
if base_category not in multimembership_criterion_base_category_list:
multimembership_criterion_base_category_list.append(base_category)
criterion_property_list = list(self.getCriterionPropertyList())
identity_criterion = getattr(self,'_identity_criterion',{})
range_criterion = getattr(self,'_range_criterion',{})
# Look at local properties and make it criterion properties
for property in self.getPortalCriterionPropertyList():
if property not in self.getCriterionPropertyList() \
and property in self.propertyIds():
criterion_property_list.append(property)
property_min = property + '_range_min'
property_max = property + '_range_max'
if hasattr(self,'get%s' % convertToUpperCase(property)) \
and self.getProperty(property) is not None:
identity_criterion[property] = self.getProperty(property)
elif hasattr(self,'get%s' % convertToUpperCase(property_min)):
min = self.getProperty(property_min)
max = self.getProperty(property_max)
range_criterion[property] = (min,max)
# Return a new context with new properties, like if
# we have a predicate with local properties
new_self = self.asContext(
membership_criterion_category=membership_criterion_category_list,
multimembership_criterion_base_category=multimembership_criterion_base_category_list,
criterion_property_list=criterion_property_list,
_identity_criterion=identity_criterion,
_range_criterion=range_criterion)
# LOG('PredicateGroup.asPredicate, new_self.getMembershipCriterionCategoryList',0,new_self.getMembershipCriterionCategoryList())
# LOG('PredicateGroup.asPredicate, new_self.getMultiMembershipCriterionBaseCategoryList',0,new_self.getMultimembershipCriterionBaseCategoryList())
# LOG('PredicateGroup.asPredicate, new_self.__class__',0,new_self.__class__)
return new_self
# Just for compatibility
class PredicateGroup(Predicate):
meta_type = 'ERP5 Predicate Group'
portal_type = 'Predicate Group'
\ No newline at end of file
......@@ -34,9 +34,9 @@ from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5Type.XMLMatrix import XMLMatrix
from Products.ERP5.Document.Resource import Resource
from Products.ERP5.Document.SetMappedValue import SetMappedValue
from Products.ERP5.Document.MappedValue import MappedValue
class SetPricing(SetMappedValue, XMLMatrix):
class SetPricing(MappedValue, XMLMatrix):
"""
Un element de tarif est un prix pour un ensemble de conditions d'application...
"""
......
......@@ -34,9 +34,9 @@ from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.DeliveryCell import DeliveryCell
from Products.ERP5.Document.Path import Path
from Products.ERP5.Document.PredicateGroup import PredicateGroup
from Products.ERP5.Document.Predicate import Predicate
class SupplyCell(PredicateGroup, DeliveryCell, Path):
class SupplyCell(Predicate, DeliveryCell, Path):
"""
A DeliveryCell allows to define specific quantities
for each variation of a resource in a delivery line.
......
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