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 @@ ...@@ -31,7 +31,7 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface 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 from Products.ERP5.Document.Invoice import Invoice
class AccountingRuleCell(Predicate, Invoice): class AccountingRuleCell(Predicate, Invoice):
......
...@@ -194,9 +194,9 @@ Une ligne tarifaire.""" ...@@ -194,9 +194,9 @@ Une ligne tarifaire."""
""" """
return self.getStopDate() return self.getStopDate()
# SKU vs. CU # Pricing in standard currency
security.declareProtected(Permissions.AccessContentsInformation, 'getSourceStandardInventoriatedQuantity') security.declareProtected(Permissions.AccessContentsInformation, 'getPrice')
def getSourceStandardInventoriatedQuantity(self): def getPrice(self):
""" """
The inventoriated quantity converted in a default unit The inventoriated quantity converted in a default unit
...@@ -212,23 +212,4 @@ Une ligne tarifaire.""" ...@@ -212,23 +212,4 @@ Une ligne tarifaire."""
return resource.convertCurrency(result, source.getPriceCurrencyValue()) return resource.convertCurrency(result, source.getPriceCurrencyValue())
return None 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 @@ ...@@ -29,11 +29,11 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.Amount import Amount 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 from zLOG import LOG
class AmountFilter(SetMappedValue, Amount): class AmountFilter(MappedValue, Amount):
""" """
An AmountFilter allows to define last minute An AmountFilter allows to define last minute
changes in a transformation. For example: different changes in a transformation. For example: different
......
...@@ -32,12 +32,12 @@ from AccessControl import ClassSecurityInfo ...@@ -32,12 +32,12 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5.Document.MetaNode import MetaNode from Products.ERP5.Document.MetaNode import MetaNode
from Products.ERP5.Document.MetaResource import MetaResource from Products.ERP5.Document.MetaResource import MetaResource
from Products.ERP5Type import Interface, Permissions, PropertySheet 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 from zLOG import LOG
class Category(CMFCategory, PredicateGroup, MetaNode, MetaResource): class Category(CMFCategory, Predicate, MetaNode, MetaResource):
""" """
Category objects allow to define classification categories Category objects allow to define classification categories
in an ERP5 portal. For example, a document may be assigned a color in an ERP5 portal. For example, a document may be assigned a color
...@@ -106,5 +106,7 @@ class Category(CMFCategory, PredicateGroup, MetaNode, MetaResource): ...@@ -106,5 +106,7 @@ class Category(CMFCategory, PredicateGroup, MetaNode, MetaResource):
) )
property_sheets = ( PropertySheet.Base property_sheets = ( PropertySheet.Base
, PropertySheet.SimpleItem ) , PropertySheet.SimpleItem
, PropertySheet.CategoryCore )
...@@ -31,9 +31,9 @@ from AccessControl import ClassSecurityInfo ...@@ -31,9 +31,9 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface 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 An abstract class subclassed by reports and mapped values
......
...@@ -49,6 +49,11 @@ class MappedValue(Domain, Amount): ...@@ -49,6 +49,11 @@ class MappedValue(Domain, Amount):
MappedValue. MappedValue.
XXX - Amount should be remove from here 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' meta_type = 'ERP5 Mapped Value'
portal_type = 'Mapped Value' portal_type = 'Mapped Value'
......
...@@ -26,40 +26,239 @@ ...@@ -26,40 +26,239 @@
# #
############################################################################## ##############################################################################
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Acquisition import aq_base, aq_inner
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface 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 # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.View) security.declareObjectProtected(Permissions.View)
security.declareProtected( Permissions.View, 'getOperatorList' ) # Declarative properties
def getOperatorList(self): 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' ) security.declareProtected( Permissions.AccessContentsInformation, 'getCriterionList' )
def getTypeList(self): def getCriterionList(self, **kw):
"""
Returns a list of criterion
""" """
A Predicate can use a built-in operator 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):
""" """
return ('string', 'int', 'float', 'date', 'set') Returns a temporary Predicate based on the Resource properties
"""
#security.declareProtected( Permissions.View, 'getTitle' ) category_tool = getToolByName(self,'portal_categories')
#def getTitle(self): membership_criterion_category_list = list(self.getMembershipCriterionCategoryList())
# """ multimembership_criterion_base_category_list = list(self.getMultimembershipCriterionBaseCategoryList())
# The title of a predicate is its operator representations # Look at local and acquired categories and make it criterion membership
# """ for base_category in self.getPortalCriterionBaseCategoryList():
# return "%s %s %s" % (self.predicate_property, self.predicate_operator, self.predicate_value) category_list = self.getProperty(base_category + '_list')
if category_list is not None and len(category_list)>0:
# Compatibility for category in category_list:
security.declareProtected( Permissions.View, 'getPredicateAttribute' ) membership_criterion_category_list.append(base_category + '/' + category)
def getPredicateAttribute(self): if base_category not in multimembership_criterion_base_category_list:
return self.getPredicateProperty() 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 ...@@ -34,9 +34,9 @@ from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5Type.XMLMatrix import XMLMatrix from Products.ERP5Type.XMLMatrix import XMLMatrix
from Products.ERP5.Document.Resource import Resource 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... 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 ...@@ -34,9 +34,9 @@ from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5.Document.DeliveryCell import DeliveryCell from Products.ERP5.Document.DeliveryCell import DeliveryCell
from Products.ERP5.Document.Path import Path 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 A DeliveryCell allows to define specific quantities
for each variation of a resource in a delivery line. 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