[Erp5-report] r34217 jm - in /erp5/trunk: bt5/erp5_payroll/SkinTemplateItem/portal_skins/er...

nobody at svn.erp5.org nobody at svn.erp5.org
Tue Mar 30 18:57:20 CEST 2010


Author: jm
Date: Tue Mar 30 18:57:17 2010
New Revision: 34217

URL: http://svn.erp5.org?rev=34217&view=rev
Log:
Delivery: add support for composition

CompositionMixin provides a 'asComposedDocument' method replacing
find{Effective,}SpecialiseValueList on Trade Condition.

Some deprecated code in TradeCondition is moved back to PaySheetModel for
compatibility reasons.

Added:
    erp5/trunk/products/ERP5/mixin/composition.py
Modified:
    erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_applyModel.xml
    erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_getODTDataDict.xml
    erp5/trunk/bt5/erp5_payroll/bt/revision
    erp5/trunk/products/ERP5/Document/Delivery.py
    erp5/trunk/products/ERP5/Document/PaySheetModel.py
    erp5/trunk/products/ERP5/Document/PaySheetTransaction.py
    erp5/trunk/products/ERP5/Document/TradeCondition.py
    erp5/trunk/products/ERP5/Document/TradeModelLine.py
    erp5/trunk/products/ERP5/tests/testPayroll.py
    erp5/trunk/products/ERP5/tests/testTradeModelLine.py

Modified: erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_applyModel.xml
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_applyModel.xml?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_applyModel.xml [utf8] (original)
+++ erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_applyModel.xml [utf8] Tue Mar 30 18:57:17 2010
@@ -87,9 +87,7 @@
 \n
 def copyPaymentCondition(paysheet, model):\n
   filter_dict = {\'portal_type\': \'Payment Condition\'}\n
-  effective_model_list = model.findEffectiveSpecialiseValueList(\\\n
-      context=model,\n
-      start_date=paysheet.getStartDate(), stop_date=paysheet.getStopDate())\n
+  effective_model_list = model.findEffectiveSpecialiseValueList(paysheet)\n
   for effective_model in effective_model_list:\n
     to_copy = effective_model.contentIds(filter=filter_dict)\n
     if len(to_copy) > 0 :\n

Modified: erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_getODTDataDict.xml
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_getODTDataDict.xml?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_getODTDataDict.xml [utf8] (original)
+++ erp5/trunk/bt5/erp5_payroll/SkinTemplateItem/portal_skins/erp5_payroll/PaySheetTransaction_getODTDataDict.xml [utf8] Tue Mar 30 18:57:17 2010
@@ -153,7 +153,7 @@
 def getSocialOrganisationValue():\n
   model = context.getSpecialiseValue()\n
   if model is not None:\n
-    business_process_list = model.findSpecialiseValueList(\\\n
+    business_process_list = model.findEffectiveSpecialiseValueList(\\\n
               context=context, portal_type_list=[\'Business Process\'])\n
     business_process = None\n
     if len(business_process_list):\n

Modified: erp5/trunk/bt5/erp5_payroll/bt/revision
URL: http://svn.erp5.org/erp5/trunk/bt5/erp5_payroll/bt/revision?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/bt5/erp5_payroll/bt/revision [utf8] (original)
+++ erp5/trunk/bt5/erp5_payroll/bt/revision [utf8] Tue Mar 30 18:57:17 2010
@@ -1,1 +1,1 @@
-559
+560

Modified: erp5/trunk/products/ERP5/Document/Delivery.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/Delivery.py?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/Delivery.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/Delivery.py [utf8] Tue Mar 30 18:57:17 2010
@@ -36,11 +36,12 @@
 from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
 from Products.ERP5Type.XMLObject import XMLObject
 from Products.ERP5.Document.ImmobilisationDelivery import ImmobilisationDelivery
+from Products.ERP5.mixin.composition import CompositionMixin
 from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
 
 from zLOG import LOG, PROBLEM
 
-class Delivery(XMLObject, ImmobilisationDelivery):
+class Delivery(XMLObject, ImmobilisationDelivery, CompositionMixin):
     """
         Each time delivery is modified, it MUST launch a reindexing of
         inventories which are related to the resources contained in the Delivery

Modified: erp5/trunk/products/ERP5/Document/PaySheetModel.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/PaySheetModel.py?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/PaySheetModel.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/PaySheetModel.py [utf8] Tue Mar 30 18:57:17 2010
@@ -30,8 +30,10 @@
 
 from Products.ERP5Type import Permissions, PropertySheet
 from Products.ERP5.Document.TradeCondition import TradeCondition
+from Products.ERP5Type.XMLMatrix import XMLMatrix
+from Products.ERP5.Document.PaySheetTransaction import PaySheetTransaction
 
-class PaySheetModel(TradeCondition):
+class PaySheetModel(TradeCondition, XMLMatrix):
   """A PaySheetModel defines calculation rules for paysheets.
 
     PaySheetModel are used to define calculating rules specific to a
@@ -64,3 +66,74 @@
                     , PropertySheet.DefaultAnnotationLine
                     )
 
+  security.declareProtected( Permissions.AccessContentsInformation, 'getCell')
+  def getCell(self, *args, **kw):
+    '''Overload the function getCell to be able to search a cell on the
+    inheritance model tree if the cell is not found on current one.
+    '''
+    paysheet = kw.get('paysheet')
+    if paysheet is None:
+      from Products.ERP5Type.Document import newTempPaySheetTransaction
+      paysheet = newTempPaySheetTransaction(self.getPortalObject(), '',
+                                            specialise_value=self)
+    model_list = self.findEffectiveSpecialiseValueList(paysheet)
+    for specialised_model in model_list:
+      cell = XMLMatrix.getCell(specialised_model, *args, **kw)
+      if cell is not None:
+        return cell
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'getReferenceDict')
+  def getReferenceDict(self, portal_type_list, property_list=None):
+    """Return a dict containing all id's of the objects contained in
+    this model and corresponding to the given portal_type. The key of the dict
+    are the reference (or id if no reference)
+    """
+    if property_list is None:
+      property_list=[]
+    reference_dict = {}
+    object_list = self.contentValues(portal_type=portal_type_list,
+        sort_on='id')
+    for obj in object_list:
+      keep = (len(property_list) == 0)
+      for property_ in property_list:
+        if obj.hasProperty(property_):
+          keep = 1
+          break
+      if keep:
+        reference_dict[obj.getProperty('reference', obj.getId())] = obj.getId()
+    return reference_dict
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'getInheritanceReferenceDict')
+  def getInheritanceReferenceDict(self, context, portal_type_list,
+                                  property_list=None):
+    '''Returns a dict with the model url as key and a list of reference as
+    value. A Reference can appear only one time in the final output.
+    If property_list is not empty, documents which don't have any of theses
+    properties will be skipped.
+    '''
+    reference_list = []
+    model_reference_dict = {}
+    for model in self.findEffectiveSpecialiseValueList(context):
+      id_list = []
+      model_reference_list = model.getReferenceDict(
+                            portal_type_list, property_list=property_list)
+      for reference in model_reference_list.keys():
+        if reference not in reference_list:
+          reference_list.append(reference)
+          id_list.append(model_reference_list[reference])
+      if len(id_list) != 0:
+        model_reference_dict[model.getRelativeUrl()]=id_list
+    return model_reference_dict
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+      'getModelInheritanceEffectiveProperty')
+  def getModelInheritanceEffectiveProperty(self, paysheet, property_name):
+    """Get a property from an effective model
+    """
+    model_list = self.findEffectiveSpecialiseValueList(paysheet)
+    for specialised_model in model_list:
+      v = specialised_model.getProperty(property_name)
+      if v:
+        return v

Modified: erp5/trunk/products/ERP5/Document/PaySheetTransaction.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/PaySheetTransaction.py?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/PaySheetTransaction.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/PaySheetTransaction.py [utf8] Tue Mar 30 18:57:17 2010
@@ -32,7 +32,6 @@
 from Products.ERP5.Document.Invoice import Invoice
 
 #XXX TODO: review naming of new methods
-#XXX WARNING: current API naming may change although model should be stable.
 
 class PaySheetTransaction(Invoice):
   """
@@ -135,13 +134,11 @@
       If property_list is provided, only subobjects with at least one of those
       properties will be taken into account
     '''
-    model = self.getSpecialiseValue().getEffectiveModel(\
-        start_date=self.getStartDate(),
-        stop_date=self.getStopDate())
+    model = self.getSpecialiseValue()
     sub_object_list = []
     if model is not None:
       # if there is an effective model
-      model_reference_dict = model.getInheritanceReferenceDict(
+      model_reference_dict = model.getInheritanceReferenceDict(self,
                                      portal_type_list=portal_type_list,
                                      property_list=property_list)
       traverse = self.getPortalObject().unrestrictedTraverse
@@ -166,9 +163,8 @@
       if len(parent.contentValues(portal_type='Pay Sheet Cell')) == 0:
         # the line contain no movements, remove it
         self.manage_delObjects(parent.getId())
-    business_process_list = paysheet_model.findSpecialiseValueList(\
-        context=paysheet_model,
-        portal_type_list=['Business Process'])
+    business_process_list = paysheet_model.findEffectiveSpecialiseValueList(
+        self, portal_type_list=['Business Process'])
     if len(business_process_list):
       # XXX currently, we consider that is to complicated to use more than one
       # Business Process, so we take the first (wich is the nearest from

Modified: erp5/trunk/products/ERP5/Document/TradeCondition.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/TradeCondition.py?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/TradeCondition.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/TradeCondition.py [utf8] Tue Mar 30 18:57:17 2010
@@ -34,10 +34,10 @@
 from AccessControl import ClassSecurityInfo
 
 from Products.ERP5Type import Permissions, PropertySheet, interfaces
+from Products.ERP5.mixin.composition import _getEffectiveModel
 from Products.ERP5.Document.Transformation import Transformation
 from Products.ERP5.Document.Path import Path
 from Products.ERP5.AggregatedAmountList import AggregatedAmountList
-from Products.ERP5Type.XMLMatrix import XMLMatrix
 from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
 
 import zope.interface
@@ -47,7 +47,7 @@
 # XXX TODO: review naming of new methods
 # XXX WARNING: current API naming may change although model should be stable.
 
-class TradeCondition(Path, Transformation, XMLMatrix):
+class TradeCondition(Path, Transformation):
     """
       Trade Conditions are used to store the conditions (payment, logistic,...)
       which should be applied (and used in the orders) when two companies make
@@ -121,18 +121,8 @@
               'movement_to_add_list': movement_to_add_list}
 
     security.declareProtected(Permissions.AccessContentsInformation,
-                              'findSpecialiseValueList')
-    def findSpecialiseValueList(self, context, portal_type_list=None):
-      """Returns a list of specialised objects representing inheritance tree.
-      """
-      return self.findEffectiveSpecialiseValueList(context,
-        portal_type_list=portal_type_list)
-
-
-    security.declareProtected(Permissions.AccessContentsInformation,
                               'findEffectiveSpecialiseValueList')
-    def findEffectiveSpecialiseValueList(self, context, start_date=None,
-                                         stop_date=None, portal_type_list=None):
+    def findEffectiveSpecialiseValueList(self, context, portal_type_list=None):
       """Return a list of effective specialised objects that is the
       inheritance tree.
       An effective object is an object which have start_date and stop_date
@@ -142,30 +132,13 @@
       """
       portal_type_set = set(portal_type_list or
                             self.getPortalAmountGeneratorTypeList())
-      def getEffectiveModel(model):
-        try:
-          getEffectiveModel = model.getEffectiveModel
-        except AttributeError:
-          return model
-        return getEffectiveModel(start_date, stop_date)
-      filtered_list = []
-      specialise_value_list = deque((getEffectiveModel(context),))
-      specialise_value_set = set(specialise_value_list)
-      specialise_index = 0
-      while specialise_value_list:
-        context = specialise_value_list.popleft()
-        if context.getPortalType() in portal_type_set:
-          filtered_list.append(context)
-        for specialise_value in map(getEffectiveModel,
-                                    context.getSpecialiseValueList()):
-          if specialise_value not in specialise_value_set:
-            specialise_value_set.add(specialise_value)
-            specialise_value_list.append(specialise_value)
-      return filtered_list
+      return [x for x in context._findEffectiveSpecialiseValueList()
+                if x.getPortalType() in portal_type_set]
 
     security.declareProtected(Permissions.AccessContentsInformation,
                               'getTradeModelLineComposedList')
-    def getTradeModelLineComposedList(self, context=None, portal_type_list=None):
+    def getTradeModelLineComposedList(self, context=None,
+                                      portal_type_list=None):
       """Returns list of Trade Model Lines using composition.
 
       Reference of Trade Model Line is used to hide other Trade Model Line
@@ -176,32 +149,12 @@
       """
       if portal_type_list is None:
         portal_type_list = self.model_line_portal_type_list
-
-      reference_list = []
-      trade_model_line_composed_list = []
-      containing_object_list = []
-      start_date = None
-      stop_date = None
-      if context is not None:
-        document = context
-        if getattr(context, 'getExplanationValue', None) is not None:
-          # if context is movement it is needed to ask its explanation
-          # for contained Trade Model Lines
-          document = context.getExplanationValue()
-        containing_object_list.append(document)
-        start_date = document.getStartDate()
-        stop_date = document.getStopDate()
-      containing_object_list.extend(\
-          self.findEffectiveSpecialiseValueList(context=self,
-            start_date=start_date, stop_date=stop_date))
-
-      for specialise in containing_object_list:
-        for trade_model_line in specialise.contentValues(
-            portal_type=portal_type_list):
-          reference = trade_model_line.getReference()
-          if reference not in reference_list or reference is None:
-            reference_list.append(reference)
-            trade_model_line_composed_list.append(trade_model_line)
+      try:
+        context = context.getExplanationValue()
+      except AttributeError:
+        pass
+      trade_model_line_composed_list = \
+        context.asComposedDocument().contentValues(portal_type=portal_type_list)
 
       # build a graph of precedences
       # B---\
@@ -296,116 +249,8 @@
 
       return aggregated_amount_list
 
-    security.declareProtected( Permissions.AccessContentsInformation, 'getCell')
-    def getCell(self, *kw , **kwd):
-      '''Overload the function getCell to be able to search a cell on the
-      inheritance model tree if the cell is not found on current one.
-      '''
-      cell = XMLMatrix.getCell(self, *kw, **kwd)
-      if cell is None:
-        # if cell not found, look on the inherited models
-        start_date = kwd.has_key('paysheet') and \
-            kwd['paysheet'].getStartDate() or None
-        stop_date = kwd.has_key('paysheet') and \
-            kwd['paysheet'].getStopDate() or None
-        model_list = self.findEffectiveSpecialiseValueList(\
-            context=self, start_date=start_date, stop_date=stop_date)
-        for specialised_model in model_list:
-          cell = XMLMatrix.getCell(specialised_model, *kw, **kwd)
-          if cell is not None:
-            return cell
-      return cell
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-        'getReferenceDict')
-    def getReferenceDict(self, portal_type_list, property_list=None):
-      """Return a dict containing all id's of the objects contained in
-      this model and corresponding to the given portal_type. The key of the dict
-      are the reference (or id if no reference)
-      """
-      if property_list is None:
-        property_list=[]
-      reference_dict = {}
-      object_list = self.contentValues(portal_type=portal_type_list,
-          sort_on='id')
-      for obj in object_list:
-        keep = (len(property_list) == 0)
-        for property_ in property_list:
-          if obj.hasProperty(property_):
-            keep = 1
-            break
-        if keep:
-          reference_dict[obj.getProperty('reference', obj.getId())] = obj.getId()
-      return reference_dict
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-        'getInheritanceReferenceDict')
-    def getInheritanceReferenceDict(self, portal_type_list,
-        property_list=None):
-      '''Returns a dict with the model url as key and a list of reference as
-      value. A Reference can appear only one time in the final output.
-      If property_list is not empty, documents which don't have any of theses
-      properties will be skipped.
-      '''
-      if property_list is None:
-        property_list=[]
-      model_list = self.findSpecialiseValueList(context=self)
-      reference_list = []
-      model_reference_dict = {}
-      for model in model_list:
-        id_list = []
-        model_reference_list = model.getReferenceDict(
-                             portal_type_list, property_list=property_list)
-        for reference in model_reference_list.keys():
-          if reference not in reference_list:
-            reference_list.append(reference)
-            id_list.append(model_reference_list[reference])
-        if len(id_list) != 0:
-          model_reference_dict[model.getRelativeUrl()]=id_list
-      return model_reference_dict
-
     security.declareProtected(Permissions.AccessContentsInformation,
         'getEffectiveModel')
     def getEffectiveModel(self, start_date=None, stop_date=None):
-      '''Return the more appropriate model using effective_date, expiration_date
-      and version number.
-      An effective model is a model which start and stop_date are equal (or
-      excluded) to the range of the given start and stop_date and with the
-      higher version number (if there is more than one)
-      '''
-      reference = self.getReference()
-      if not reference or (start_date is None and stop_date is None):
-        return self
-      
-      return self.getPortalObject().portal_catalog.unrestrictedGetResultValue(
-                              query=ComplexQuery(
-                                      ComplexQuery(
-                                        Query(effective_date=None),
-                                        Query(effective_date=start_date,
-                                              range='ngt'),
-                                        logical_operator='OR'),
-                                      ComplexQuery(
-                                        Query(expiration_date=None),
-                                        Query(expiration_date=stop_date,
-                                              range='min'),
-                                        logical_operator='OR'),
-                                      Query(reference=reference),
-                                      Query(validation_state=(
-                                              'deleted', 'invalidated'),
-                                            operator='NOT'),
-                                      Query(portal_type=self.getPortalType()),
-                                      logical_operator='AND'),
-                              sort_on=(('version','descending'),))
-
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-        'getModelInheritanceEffectiveProperty')
-    def getModelInheritanceEffectiveProperty(self, paysheet, property_name):
-      """Get a property from an effective model
-      """
-      model_list = self.findEffectiveSpecialiseValueList(context=self,
-          start_date=paysheet.getStartDate(), stop_date=paysheet.getStopDate())
-      for specialised_model in model_list:
-        v = specialised_model.getProperty(property_name)
-        if v:
-          return v
+      return _getEffectiveModel(self, start_date, stop_date)
+

Modified: erp5/trunk/products/ERP5/Document/TradeModelLine.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/TradeModelLine.py?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/TradeModelLine.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/TradeModelLine.py [utf8] Tue Mar 30 18:57:17 2010
@@ -196,12 +196,12 @@
       update = 1
     else:
       # get source and destination using Business Process
-      if getattr(document, 'findSpecialiseValueList', None) is None:
+      if getattr(document, 'findEffectiveSpecialiseValueList', None) is None:
         # if parent don't have findSpecialiseValueList, this mean it's on the
         # specialise_value
         document = self.getParentValue().getSpecialiseValue()
       try:
-        business_process_list = document.findSpecialiseValueList(
+        business_process_list = document.findEffectiveSpecialiseValueList(
             context=context, portal_type_list=['Business Process'])
       except AttributeError:
         business_process_list = []

Added: erp5/trunk/products/ERP5/mixin/composition.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/mixin/composition.py?rev=34217&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/mixin/composition.py (added)
+++ erp5/trunk/products/ERP5/mixin/composition.py [utf8] Tue Mar 30 18:57:17 2010
@@ -1,0 +1,126 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsibility of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# guarantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+
+from AccessControl import ClassSecurityInfo
+from Acquisition import aq_base
+from Products.ERP5Type import Permissions
+from Products.ERP5.Document.Predicate import Predicate
+from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
+
+def _getEffectiveModel(self, start_date=None, stop_date=None):
+  """Return the most appropriate model using effective_date, expiration_date
+  and version number.
+  An effective model is a model which start and stop_date are equal (or
+  excluded) to the range of the given start and stop_date and with the
+  higher version number (if there is more than one)
+
+  XXX Should we moved this function to a class ? Which one ?
+      What about reusing IVersionable ?
+  """
+  reference = self.getReference()
+  if not reference:
+    return self
+
+  query_list = [Query(reference=reference),
+                Query(portal_type=self.getPortalType()),
+                Query(validation_state=('deleted', 'invalidated'),
+                      operator='NOT')]
+  if start_date is not None:
+    query_list.append(ComplexQuery(Query(effective_date=None),
+                                   Query(effective_date=start_date,
+                                         range='ngt'),
+                                   logical_operator='OR'))
+  if stop_date is not None:
+    query_list.append(ComplexQuery(Query(expiration_date=None),
+                                   Query(expiration_date=stop_date,
+                                         range='min'),
+                                   logical_operator='OR'))
+
+  # XXX What to do the catalog returns nothing (either because 'self' was just
+  #     created and not yet indexed, or because it was invalidated) ?
+  #     For the moment, we raise.
+  model_list = self.getPortalObject().portal_catalog.unrestrictedSearchResults(
+      query=ComplexQuery(logical_operator='AND', *query_list),
+      sort_on=(('version', 'descending'),))
+  return model_list[0].getObject()
+
+class CompositionMixin:
+  """
+  """
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+  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
+
+  def _findEffectiveSpecialiseValueList(self):
+    """Return a list of effective specialised objects that is the
+    inheritance tree.
+    An effective object is an object which have start_date and stop_date
+    included to the range of the given parameters start_date and stop_date.
+
+    This algorithm uses Breadth First Search.
+    """
+    start_date = self.getStartDate()
+    stop_date = self.getStopDate()
+    def getEffectiveModel(model):
+      return _getEffectiveModel(model, start_date, stop_date)
+    model_list = [self]
+    model_set = set(model_list)
+    model_index = 0
+    while model_index < len(model_list):
+      model = model_list[model_index]
+      model_index += 1
+      for model in map(getEffectiveModel, model.getSpecialiseValueList()):
+        if model not in model_set:
+          model_set.add(model)
+          if 1: #model.test(self):
+            model_list.append(model)
+    return model_list

Modified: erp5/trunk/products/ERP5/tests/testPayroll.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testPayroll.py?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testPayroll.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testPayroll.py [utf8] Tue Mar 30 18:57:17 2010
@@ -1371,14 +1371,17 @@
                              quantity=4)
 
   def stepCheckInheritanceModelReferenceDict(self, sequence=None, **kw):
+    paysheet = self.createPaysheet()
     model_employee = sequence.get('model_employee')
+    paysheet.setSpecialiseValue(model_employee)
+
     model_employee_url = model_employee.getRelativeUrl()
     model_company_url = sequence.get('model_company').getRelativeUrl()
     model_company_alt_url = sequence.get('model_company_alt').getRelativeUrl()
     model_country_url = sequence.get('model_country').getRelativeUrl()
-    
-    model_reference_dict = model_employee.getInheritanceReferenceDict(\
-        portal_type_list=('Annotation Line',))
+
+    model_reference_dict = model_employee.getInheritanceReferenceDict(
+        paysheet, portal_type_list=('Annotation Line',))
     self.assertEquals(len(model_reference_dict), 3) # there is 4 model but two
                                                     # models have the same
                                                     # reference.
@@ -1394,8 +1397,6 @@
     self.assertNotEquals(model_reference_dict.has_key(model_country_url), True)
     
     # check the object list :
-    paysheet = self.createPaysheet()
-    paysheet.setSpecialiseValue(model_employee)
     object_list = paysheet.getInheritedObjectValueList(portal_type_list=\
         ('Annotation Line',))
     self.assertEquals(len(object_list), 3) # one line have the same reference
@@ -1527,6 +1528,7 @@
         base_contribution_list=['base_amount/payroll/base/contribution',
           'base_amount/payroll/report/salary/gross'],
         quantity=10000)
+    self.stepTic()
 
     # create a paysheet without date
     paysheet_without_date = self.createPaysheet()
@@ -1694,9 +1696,7 @@
 
     # check the effective model tree list
     effective_value_list = specialise_value.findEffectiveSpecialiseValueList(\
-        context=specialise_value,
-        start_date=paysheet.getStartDate(),
-        stop_date=paysheet.getStopDate())
+        context=paysheet)
     self.assertEquals(effective_value_list, [model_2])
 
   def stepCreateModelLineZeroPrice(self, sequence=None, **kw):
@@ -1857,30 +1857,15 @@
     model_1.setSpecialiseValue(model_4)
     model_4.setSpecialiseValue(model_6)
     paysheet.PaySheetTransaction_applyModel()
-    self.assertEquals(specialise_value.findSpecialiseValueList(context=paysheet),
-        [model_1, model_4, model_6])
-    self.assertEquals(specialise_value.findEffectiveSpecialiseValueList(\
-        context=paysheet, start_date=paysheet.getStartDate(),
-        stop_date=paysheet.getStopDate()), [model_2,])
+    self.assertEquals([model_2],
+      specialise_value.findEffectiveSpecialiseValueList(context=paysheet))
 
     model_1.setSpecialiseValue(None)
     model_2.setSpecialiseValue(model_5)
     model_5.setSpecialiseValue(model_6)
     paysheet.PaySheetTransaction_applyModel()
-    self.assertEquals(specialise_value.findSpecialiseValueList(context=paysheet),
-        [model_1,])
-    self.assertEquals(specialise_value.findEffectiveSpecialiseValueList(\
-        context=paysheet, start_date=paysheet.getStartDate(),
-        stop_date=paysheet.getStopDate()), [model_2, model_5, model_7])
-
-    model_3.setSpecialiseValue(model_5)
-    model_5.setSpecialiseValue(model_6)
-    paysheet.PaySheetTransaction_applyModel()
-    self.assertEquals(specialise_value.findSpecialiseValueList(context=paysheet),
-        [model_1,])
-    self.assertEquals(specialise_value.findEffectiveSpecialiseValueList(\
-        context=paysheet, start_date=paysheet.getStartDate(),
-        stop_date=paysheet.getStopDate()), [model_2, model_5, model_7])
+    self.assertEquals([model_2, model_5, model_7],
+      specialise_value.findEffectiveSpecialiseValueList(context=paysheet))
 
   def stepCheckPropertiesAreCopiedFromModelLineToPaySheetLine(self,
       sequence=None, **kw):
@@ -2383,6 +2368,7 @@
     sequence_string = """
                CreateModelTree
                ModelTreeAddAnnotationLines
+               Tic
                CheckInheritanceModelReferenceDict
     """
     sequence_list.addSequenceString(sequence_string)

Modified: erp5/trunk/products/ERP5/tests/testTradeModelLine.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testTradeModelLine.py?rev=34217&r1=34216&r2=34217&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testTradeModelLine.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testTradeModelLine.py [utf8] Tue Mar 30 18:57:17 2010
@@ -1369,31 +1369,10 @@
       order_line_discounted.getTotalPrice() * 0.32) * 0.8
     )
 
+  def assertSameUidSet(self, a, b, msg=None):
+    self.assertEqual(set(x.uid for x in a), set(x.uid for x in b), msg)
+
   # Tests
-  def test_TradeConditionTradeModelLineBasicComposition(self):
-    """
-      If Trade Condition is specialised by another Trade Condition they
-      Trade Model Lines shall be merged.
-    """
-    trade_condition_1 = self.createTradeCondition()
-    trade_condition_2 = self.createTradeCondition()
-
-    trade_condition_1.setSpecialiseValue(trade_condition_2)
-
-    trade_condition_1_trade_model_line = self.createTradeModelLine(
-        trade_condition_1,
-        reference='A')
-
-    trade_condition_2_trade_model_line = self.createTradeModelLine(
-        trade_condition_2,
-        reference='B')
-
-    self.assertSameSet(
-      [trade_condition_1_trade_model_line,
-        trade_condition_2_trade_model_line],
-      trade_condition_1.getTradeModelLineComposedList()
-    )
-
   def test_TradeConditionTradeModelLineBasicCompositionWithOrder(self):
     trade_condition_1 = self.createTradeCondition()
     trade_condition_2 = self.createTradeCondition()
@@ -1414,66 +1393,26 @@
         order,
         reference='C')
 
-    self.assertSameSet(
-      [trade_condition_1_trade_model_line, trade_condition_2_trade_model_line],
-      trade_condition_1.getTradeModelLineComposedList()
-    )
-
-    self.assertSameSet(
+    self.assertSameUidSet(
       [trade_condition_1_trade_model_line, trade_condition_2_trade_model_line,
         order_trade_model_line],
       trade_condition_1.getTradeModelLineComposedList(context=order)
     )
 
   def test_TradeConditionCircularCompositionIsSafe(self):
+    order = self.createOrder()
     trade_condition_1 = self.createTradeCondition()
     trade_condition_2 = self.createTradeCondition()
 
+    order.setSpecialiseValue(trade_condition_1)
     trade_condition_1.setSpecialiseValue(trade_condition_2)
     trade_condition_2.setSpecialiseValue(trade_condition_1)
 
-    self.assertEquals(trade_condition_1. \
-        findSpecialiseValueList(trade_condition_1),
+    self.assertEqual(trade_condition_1.findEffectiveSpecialiseValueList(order),
         [trade_condition_1, trade_condition_2]
     )
 
-  def test_findSpecialiseValueList(self):
-    '''
-      check that findSpecialiseValueList is able to return all the inheritance
-      model tree using Depth-first search
-
-                                  trade_condition_1
-                                    /           \
-                                   /             \
-                                  /               \
-                       trade_condition_2       trade_condition_3
-                               |
-                               |
-                               |
-                        trade_condition_4
-
-      According to Depth-first search algorithm, result of this graph is:
-      [trade_condition_1, trade_condition_2, trade_condition_3,
-      trade_condition_4]
-    '''
-    trade_condition_1 = self.createTradeCondition()
-    trade_condition_2 = self.createTradeCondition()
-    trade_condition_3 = self.createTradeCondition()
-    trade_condition_4 = self.createTradeCondition()
-
-    trade_condition_1.setSpecialiseValueList((trade_condition_2,
-      trade_condition_3))
-    trade_condition_2.setSpecialiseValue(trade_condition_4)
-
-    specialise_value_list = trade_condition_1.findSpecialiseValueList(
-        context=trade_condition_1)
-    self.assertEquals(len(specialise_value_list), 4)
-    self.assertEquals(
-      [trade_condition_1, trade_condition_2, trade_condition_3,
-       trade_condition_4], specialise_value_list)
-
-
-  def test_findSpecialiseValueListWithPortalType(self):
+  def test_findEffectiveSpecialiseValueListWithPortalType(self):
     '''
       check that findSpecialiseValueList is able to return all the inheritance
       model tree using Depth-first search with a specific portal_type asked
@@ -1495,45 +1434,28 @@
     As only business_process will be a "Business Process" and we search for business process
     the result must be [business_process]
     '''
+    order = self.createOrder()
     trade_condition_1 = self.createTradeCondition()
     trade_condition_2 = self.createTradeCondition()
     trade_condition_3 = self.createTradeCondition()
     trade_condition_4 = self.createTradeCondition()
     business_process = self.createBusinessProcess()
-    
+
+    order.setSpecialiseValue(trade_condition_1)
     trade_condition_1.setSpecialiseValueList((trade_condition_2,
       trade_condition_3))
     trade_condition_2.setSpecialiseValue(trade_condition_4)
     trade_condition_4.setSpecialiseValue(business_process)
-    
-    specialise_value_list = trade_condition_1.findSpecialiseValueList(
-      portal_type_list = ['Business Process'],
-      context=trade_condition_1)
-    self.assertEquals(len(specialise_value_list), 1)
-    self.assertEquals([business_process,] , specialise_value_list)
+
+    self.assertEqual(trade_condition_1.findEffectiveSpecialiseValueList(order),
+      [trade_condition_1, trade_condition_2, trade_condition_3,
+       trade_condition_4])
+    self.assertEqual(trade_condition_1.findEffectiveSpecialiseValueList(order,
+      portal_type_list = ['Business Process']), [business_process])
 
   def test_TradeConditionTradeModelLineReferenceIsShadowingComposition(self):
     trade_condition_1 = self.createTradeCondition()
     trade_condition_2 = self.createTradeCondition()
-
-    trade_condition_1.setSpecialiseValue(trade_condition_2)
-
-    trade_condition_1_trade_model_line = self.createTradeModelLine(
-        trade_condition_1,
-        reference='A')
-
-    trade_condition_2_trade_model_line = self.createTradeModelLine(
-        trade_condition_2,
-        reference='A')
-
-    self.assertSameSet(
-      [trade_condition_1_trade_model_line],
-      trade_condition_1.getTradeModelLineComposedList()
-    )
-
-  def test_TradeConditionTradeModelLineReferenceIsShadowingCompositionWithOrder(self):
-    trade_condition_1 = self.createTradeCondition()
-    trade_condition_2 = self.createTradeCondition()
     order = self.createOrder()
 
     trade_condition_1.setSpecialiseValue(trade_condition_2)
@@ -1551,13 +1473,7 @@
         order,
         reference = 'B')
 
-    self.assertSameSet(
-      [trade_condition_1_trade_model_line,
-        trade_condition_2_trade_model_line],
-      trade_condition_1.getTradeModelLineComposedList()
-    )
-
-    self.assertSameSet(
+    self.assertSameUidSet(
       [trade_condition_1_trade_model_line, order_trade_model_line],
       trade_condition_1.getTradeModelLineComposedList(context=order)
     )
@@ -1568,7 +1484,9 @@
     where we create trade model line in a wrong order in comparison to application relations
     We have a contribution graph like this A ---> C ---> B so final order must be A, C, B
     """
+    order = self.createOrder()
     trade_condition = self.createTradeCondition()
+    order.setSpecialiseValue(trade_condition)
     A = self.createTradeModelLine(trade_condition, reference='A', id=1,
         base_contribution_list=['base_amount/total'])
 
@@ -1579,7 +1497,7 @@
     C = self.createTradeModelLine(trade_condition, reference='C', id=3,
         base_contribution_list=['base_amount/total_tax'],
         base_application_list=['base_amount/total'])
-    trade_model_line_list = trade_condition.getTradeModelLineComposedList()
+    trade_model_line_list = trade_condition.getTradeModelLineComposedList(order)
 
     self.assertEquals([q.getReference() for q in trade_model_line_list],
         [q.getReference() for q in [A, C, B,]])
@@ -1646,7 +1564,9 @@
       * (DEFG) (BC) A
     where everything in parenthesis can be not sorted
     """
+    order = self.createOrder()
     trade_condition = self.createTradeCondition()
+    order.setSpecialiseValue(trade_condition)
 
     A = self.createTradeModelLine(trade_condition, reference='A',
         base_application_list=['base_amount/total'])
@@ -1675,7 +1595,7 @@
         base_contribution_list=['base_amount/total_discount'],
         base_application_list=['base_amount/discount'])
 
-    trade_model_line_list = trade_condition.getTradeModelLineComposedList()
+    trade_model_line_list = trade_condition.getTradeModelLineComposedList(order)
 
     possible_sort_list = [
                           [[D,E], [B], [F, G], [C], [A]],
@@ -1704,7 +1624,9 @@
       * A (BC) D
     where everything in parenthesis can be not sorted
     """
+    order = self.createOrder()
     trade_condition = self.createTradeCondition()
+    order.setSpecialiseValue(trade_condition)
 
     C = self.createTradeModelLine(trade_condition, reference='C',
         base_contribution_list=['base_amount/total'],
@@ -1722,7 +1644,7 @@
         base_contribution_list=['base_amount/total'],
         base_application_list=['base_amount/total_tax'])
 
-    trade_model_line_list = trade_condition.getTradeModelLineComposedList()
+    trade_model_line_list = trade_condition.getTradeModelLineComposedList(order)
 
     possible_sort_list = [
                           [[A], [B,C], [D]]




More information about the Erp5-report mailing list