[Erp5-report] r34252 jm - in /erp5/trunk/products: ERP5/Document/ ERP5/mixin/ ERP5/tests/ E...
nobody at svn.erp5.org
nobody at svn.erp5.org
Thu Apr 1 19:58:52 CEST 2010
Author: jm
Date: Thu Apr 1 19:58:52 2010
New Revision: 34252
URL: http://svn.erp5.org?rev=34252&view=rev
Log:
Make composition work for movements and use transactional cache
Modified:
erp5/trunk/products/ERP5/Document/Movement.py
erp5/trunk/products/ERP5/mixin/composition.py
erp5/trunk/products/ERP5/tests/testTradeModelLine.py
erp5/trunk/products/ERP5Type/Base.py
Modified: erp5/trunk/products/ERP5/Document/Movement.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/Movement.py?rev=34252&r1=34251&r2=34252&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/Movement.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/Movement.py [utf8] Thu Apr 1 19:58:52 2010
@@ -36,12 +36,12 @@
#from Products.ERP5.Core import MetaNode, MetaResource
from Products.ERP5Type.XMLObject import XMLObject
-
+from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5.Document.Amount import Amount
from zLOG import LOG, WARNING
-class Movement(XMLObject, Amount):
+class Movement(XMLObject, Amount, CompositionMixin):
"""
The Movement class allows to implement ERP5 universal accounting model.
Modified: erp5/trunk/products/ERP5/mixin/composition.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/mixin/composition.py?rev=34252&r1=34251&r2=34252&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/mixin/composition.py [utf8] (original)
+++ erp5/trunk/products/ERP5/mixin/composition.py [utf8] Thu Apr 1 19:58:52 2010
@@ -2,6 +2,7 @@
##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
+# Julien Muchembled <jm at nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
@@ -29,9 +30,12 @@
from AccessControl import ClassSecurityInfo
from Acquisition import aq_base
from Products.ERP5Type import Permissions
+from Products.ERP5Type.Cache import transactional_cached
from Products.ERP5.Document.Predicate import Predicate
from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
+
+ at transactional_cached()
def _getEffectiveModel(self, start_date=None, stop_date=None):
"""Return the most appropriate model using effective_date, expiration_date
and version number.
@@ -69,6 +73,72 @@
sort_on=(('version', 'descending'),))
return model_list[0].getObject()
+
+ at transactional_cached()
+def _findPredicateList(*container_list):
+ predicate_list = []
+ reference_dict = {}
+ line_count = 0
+ for container in container_list:
+ for ob in container.contentValues():
+ if isinstance(ob, Predicate):
+ # reference is used to hide lines on farther containers
+ reference = ob.getProperty('reference')
+ if reference:
+ reference_set = reference_dict.setdefault(ob.getPortalType(), set())
+ if reference in reference_set:
+ continue
+ reference_set.add(reference)
+ id = str(line_count)
+ line_count += 1
+ predicate_list.append(aq_base(ob.asContext(id=id)))
+ return predicate_list
+
+
+class _asComposedDocument(object):
+ """Return a temporary object which is the composition of all effective models
+
+ The returned value is a temporary copy of the given object. The list of all
+ effective models (specialise values) is stored in a private attribute.
+ Collecting predicates (from effective models) is done lazily. Predicates can
+ be accessed through standard Folder API (ex: contentValues).
+ """
+
+ def __new__(cls, orig_self):
+ if '_effective_model_list' in orig_self.__dict__:
+ return orig_self # if asComposedDocument is called on a composed
+ # document after any access to its subobjects
+ self = orig_self.asContext()
+ self._initBTrees()
+ base_class = self.__class__
+ # this allows to intercept first access to '_folder_handler'
+ self.__class__ = type(base_class.__name__, (cls, base_class),
+ {'__module__': base_class.__module__})
+ self._effective_model_list = orig_self._findEffectiveSpecialiseValueList()
+ return self
+
+ def __init__(self, orig_self):
+ # __new__ does not call __init__ because returned object
+ # is wrapped in an acquisition context.
+ assert False
+
+ def asComposedDocument(self):
+ return self # if asComposedDocument is called on a composed
+ # document before any access to its subobjects
+
+ @property
+ def _folder_handler(self):
+ # restore the original class
+ # because we don't need to hook _folder_handler anymore
+ self.__class__ = self.__class__.__bases__[1]
+ # we filter out objects without any subobject to make the cache of
+ # '_findPredicateList' useful. Otherwise, the key would be always different
+ # (starting with 'orig_self').
+ for ob in _findPredicateList(*filter(None, self._effective_model_list)):
+ self._setOb(ob.id, ob)
+ return self._folder_handler
+
+
class CompositionMixin:
"""
"""
@@ -79,26 +149,10 @@
security.declareProtected(Permissions.AccessContentsInformation,
'asComposedDocument')
- def asComposedDocument(self):
- container_list = self._findEffectiveSpecialiseValueList()
- self = self.asContext()
- self._initBTrees()
- reference_dict = {}
- line_count = 0
- for container in container_list:
- for ob in container.contentValues():
- if isinstance(ob, Predicate):
- # reference is used to hide lines on farther containers
- reference = ob.getProperty('reference')
- if reference:
- reference_set = reference_dict.setdefault(ob.getPortalType(), set())
- if reference in reference_set:
- continue
- reference_set.add(reference)
- id = str(line_count)
- line_count += 1
- self._setOb(id, aq_base(ob.asContext(id=id)))
- return self
+ asComposedDocument = transactional_cached()(_asComposedDocument)
+
+ # XXX add accessors to get properties from '_effective_model_list' ?
+ # (cf PaySheetModel)
def _findEffectiveSpecialiseValueList(self):
"""Return a list of effective specialised objects that is the
@@ -118,9 +172,18 @@
while model_index < len(model_list):
model = model_list[model_index]
model_index += 1
- for model in map(getEffectiveModel, model.getSpecialiseValueList()):
+ # we don't use getSpecialiseValueList to avoid acquisition on the parent
+ for model in map(getEffectiveModel, model.getValueList('specialise')):
if model not in model_set:
model_set.add(model)
- if 1: #model.test(self):
+ if 1: #model.test(self): # XXX
model_list.append(model)
+ try:
+ parent_asComposedDocument = self.getParentValue().asComposedDocument
+ except AttributeError:
+ pass
+ else:
+ model_list += [model
+ for model in parent_asComposedDocument()._effective_model_list
+ if model not in model_set]
return model_list
Modified: erp5/trunk/products/ERP5/tests/testTradeModelLine.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testTradeModelLine.py?rev=34252&r1=34251&r2=34252&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testTradeModelLine.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testTradeModelLine.py [utf8] Thu Apr 1 19:58:52 2010
@@ -2632,6 +2632,7 @@
# change tax trade model line to `movement` level
tax.edit(target_level=TARGET_LEVEL_MOVEMENT)
+ transaction.commit() # flush transactional cache
def getTotalAmount(amount_list):
result = 0
Modified: erp5/trunk/products/ERP5Type/Base.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/Base.py?rev=34252&r1=34251&r2=34252&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/Base.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/Base.py [utf8] Thu Apr 1 19:58:52 2010
@@ -2811,7 +2811,7 @@
if k != 'SESSION':
setattr(context, k, REQUEST[k])
# Define local properties
- if kw is not None: context.__dict__.update(kw)
+ context.__dict__.update(kw)
# Make it a temp content
temp_object = TempBase(self.getId())
for k in ('isIndexable', 'reindexObject', 'recursiveReindexObject', 'activate', 'setUid', ):
More information about the Erp5-report
mailing list