Commit e72e22f6 authored by Julien Muchembled's avatar Julien Muchembled

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.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@34217 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 9b907283
...@@ -87,9 +87,7 @@ if price_currency:\n ...@@ -87,9 +87,7 @@ if price_currency:\n
\n \n
def copyPaymentCondition(paysheet, model):\n def copyPaymentCondition(paysheet, model):\n
filter_dict = {\'portal_type\': \'Payment Condition\'}\n filter_dict = {\'portal_type\': \'Payment Condition\'}\n
effective_model_list = model.findEffectiveSpecialiseValueList(\\\n effective_model_list = model.findEffectiveSpecialiseValueList(paysheet)\n
context=model,\n
start_date=paysheet.getStartDate(), stop_date=paysheet.getStopDate())\n
for effective_model in effective_model_list:\n for effective_model in effective_model_list:\n
to_copy = effective_model.contentIds(filter=filter_dict)\n to_copy = effective_model.contentIds(filter=filter_dict)\n
if len(to_copy) > 0 :\n if len(to_copy) > 0 :\n
......
...@@ -153,7 +153,7 @@ def getPaymentConditionText(order):\n ...@@ -153,7 +153,7 @@ def getPaymentConditionText(order):\n
def getSocialOrganisationValue():\n def getSocialOrganisationValue():\n
model = context.getSpecialiseValue()\n model = context.getSpecialiseValue()\n
if model is not None:\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 context=context, portal_type_list=[\'Business Process\'])\n
business_process = None\n business_process = None\n
if len(business_process_list):\n if len(business_process_list):\n
......
559 560
\ No newline at end of file \ No newline at end of file
...@@ -36,11 +36,12 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces ...@@ -36,11 +36,12 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5.Document.ImmobilisationDelivery import ImmobilisationDelivery from Products.ERP5.Document.ImmobilisationDelivery import ImmobilisationDelivery
from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from zLOG import LOG, PROBLEM 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 Each time delivery is modified, it MUST launch a reindexing of
inventories which are related to the resources contained in the Delivery inventories which are related to the resources contained in the Delivery
......
...@@ -30,8 +30,10 @@ from AccessControl import ClassSecurityInfo ...@@ -30,8 +30,10 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.TradeCondition import TradeCondition 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. """A PaySheetModel defines calculation rules for paysheets.
PaySheetModel are used to define calculating rules specific to a PaySheetModel are used to define calculating rules specific to a
...@@ -64,3 +66,74 @@ class PaySheetModel(TradeCondition): ...@@ -64,3 +66,74 @@ class PaySheetModel(TradeCondition):
, PropertySheet.DefaultAnnotationLine , 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
...@@ -32,7 +32,6 @@ from Products.ERP5Type import Permissions, PropertySheet ...@@ -32,7 +32,6 @@ from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.Invoice import Invoice from Products.ERP5.Document.Invoice import Invoice
#XXX TODO: review naming of new methods #XXX TODO: review naming of new methods
#XXX WARNING: current API naming may change although model should be stable.
class PaySheetTransaction(Invoice): class PaySheetTransaction(Invoice):
""" """
...@@ -135,13 +134,11 @@ class PaySheetTransaction(Invoice): ...@@ -135,13 +134,11 @@ class PaySheetTransaction(Invoice):
If property_list is provided, only subobjects with at least one of those If property_list is provided, only subobjects with at least one of those
properties will be taken into account properties will be taken into account
''' '''
model = self.getSpecialiseValue().getEffectiveModel(\ model = self.getSpecialiseValue()
start_date=self.getStartDate(),
stop_date=self.getStopDate())
sub_object_list = [] sub_object_list = []
if model is not None: if model is not None:
# if there is an effective model # if there is an effective model
model_reference_dict = model.getInheritanceReferenceDict( model_reference_dict = model.getInheritanceReferenceDict(self,
portal_type_list=portal_type_list, portal_type_list=portal_type_list,
property_list=property_list) property_list=property_list)
traverse = self.getPortalObject().unrestrictedTraverse traverse = self.getPortalObject().unrestrictedTraverse
...@@ -166,9 +163,8 @@ class PaySheetTransaction(Invoice): ...@@ -166,9 +163,8 @@ class PaySheetTransaction(Invoice):
if len(parent.contentValues(portal_type='Pay Sheet Cell')) == 0: if len(parent.contentValues(portal_type='Pay Sheet Cell')) == 0:
# the line contain no movements, remove it # the line contain no movements, remove it
self.manage_delObjects(parent.getId()) self.manage_delObjects(parent.getId())
business_process_list = paysheet_model.findSpecialiseValueList(\ business_process_list = paysheet_model.findEffectiveSpecialiseValueList(
context=paysheet_model, self, portal_type_list=['Business Process'])
portal_type_list=['Business Process'])
if len(business_process_list): if len(business_process_list):
# XXX currently, we consider that is to complicated to use more than one # 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 # Business Process, so we take the first (wich is the nearest from
......
...@@ -34,10 +34,10 @@ from collections import deque ...@@ -34,10 +34,10 @@ from collections import deque
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces 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.Transformation import Transformation
from Products.ERP5.Document.Path import Path from Products.ERP5.Document.Path import Path
from Products.ERP5.AggregatedAmountList import AggregatedAmountList from Products.ERP5.AggregatedAmountList import AggregatedAmountList
from Products.ERP5Type.XMLMatrix import XMLMatrix
from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
import zope.interface import zope.interface
...@@ -47,7 +47,7 @@ import zope.interface ...@@ -47,7 +47,7 @@ import zope.interface
# XXX TODO: review naming of new methods # XXX TODO: review naming of new methods
# XXX WARNING: current API naming may change although model should be stable. # 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,...) Trade Conditions are used to store the conditions (payment, logistic,...)
which should be applied (and used in the orders) when two companies make which should be applied (and used in the orders) when two companies make
...@@ -120,19 +120,9 @@ class TradeCondition(Path, Transformation, XMLMatrix): ...@@ -120,19 +120,9 @@ class TradeCondition(Path, Transformation, XMLMatrix):
return {'movement_to_delete_list' : movement_to_delete_list, return {'movement_to_delete_list' : movement_to_delete_list,
'movement_to_add_list': movement_to_add_list} '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, security.declareProtected(Permissions.AccessContentsInformation,
'findEffectiveSpecialiseValueList') 'findEffectiveSpecialiseValueList')
def findEffectiveSpecialiseValueList(self, context, start_date=None, def findEffectiveSpecialiseValueList(self, context, portal_type_list=None):
stop_date=None, portal_type_list=None):
"""Return a list of effective specialised objects that is the """Return a list of effective specialised objects that is the
inheritance tree. inheritance tree.
An effective object is an object which have start_date and stop_date An effective object is an object which have start_date and stop_date
...@@ -142,30 +132,13 @@ class TradeCondition(Path, Transformation, XMLMatrix): ...@@ -142,30 +132,13 @@ class TradeCondition(Path, Transformation, XMLMatrix):
""" """
portal_type_set = set(portal_type_list or portal_type_set = set(portal_type_list or
self.getPortalAmountGeneratorTypeList()) self.getPortalAmountGeneratorTypeList())
def getEffectiveModel(model): return [x for x in context._findEffectiveSpecialiseValueList()
try: if x.getPortalType() in portal_type_set]
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
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getTradeModelLineComposedList') '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. """Returns list of Trade Model Lines using composition.
Reference of Trade Model Line is used to hide other Trade Model Line Reference of Trade Model Line is used to hide other Trade Model Line
...@@ -176,32 +149,12 @@ class TradeCondition(Path, Transformation, XMLMatrix): ...@@ -176,32 +149,12 @@ class TradeCondition(Path, Transformation, XMLMatrix):
""" """
if portal_type_list is None: if portal_type_list is None:
portal_type_list = self.model_line_portal_type_list portal_type_list = self.model_line_portal_type_list
try:
reference_list = [] context = context.getExplanationValue()
trade_model_line_composed_list = [] except AttributeError:
containing_object_list = [] pass
start_date = None trade_model_line_composed_list = \
stop_date = None context.asComposedDocument().contentValues(portal_type=portal_type_list)
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)
# build a graph of precedences # build a graph of precedences
# B---\ # B---\
...@@ -296,116 +249,8 @@ class TradeCondition(Path, Transformation, XMLMatrix): ...@@ -296,116 +249,8 @@ class TradeCondition(Path, Transformation, XMLMatrix):
return aggregated_amount_list 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, security.declareProtected(Permissions.AccessContentsInformation,
'getEffectiveModel') 'getEffectiveModel')
def getEffectiveModel(self, start_date=None, stop_date=None): def getEffectiveModel(self, start_date=None, stop_date=None):
'''Return the more appropriate model using effective_date, expiration_date return _getEffectiveModel(self, start_date, stop_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
...@@ -196,12 +196,12 @@ class TradeModelLine(Predicate, XMLMatrix, Amount): ...@@ -196,12 +196,12 @@ class TradeModelLine(Predicate, XMLMatrix, Amount):
update = 1 update = 1
else: else:
# get source and destination using Business Process # 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 # if parent don't have findSpecialiseValueList, this mean it's on the
# specialise_value # specialise_value
document = self.getParentValue().getSpecialiseValue() document = self.getParentValue().getSpecialiseValue()
try: try:
business_process_list = document.findSpecialiseValueList( business_process_list = document.findEffectiveSpecialiseValueList(
context=context, portal_type_list=['Business Process']) context=context, portal_type_list=['Business Process'])
except AttributeError: except AttributeError:
business_process_list = [] business_process_list = []
......
# -*- 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
...@@ -1371,14 +1371,17 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -1371,14 +1371,17 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
quantity=4) quantity=4)
def stepCheckInheritanceModelReferenceDict(self, sequence=None, **kw): def stepCheckInheritanceModelReferenceDict(self, sequence=None, **kw):
paysheet = self.createPaysheet()
model_employee = sequence.get('model_employee') model_employee = sequence.get('model_employee')
paysheet.setSpecialiseValue(model_employee)
model_employee_url = model_employee.getRelativeUrl() model_employee_url = model_employee.getRelativeUrl()
model_company_url = sequence.get('model_company').getRelativeUrl() model_company_url = sequence.get('model_company').getRelativeUrl()
model_company_alt_url = sequence.get('model_company_alt').getRelativeUrl() model_company_alt_url = sequence.get('model_company_alt').getRelativeUrl()
model_country_url = sequence.get('model_country').getRelativeUrl() model_country_url = sequence.get('model_country').getRelativeUrl()
model_reference_dict = model_employee.getInheritanceReferenceDict(\ model_reference_dict = model_employee.getInheritanceReferenceDict(
portal_type_list=('Annotation Line',)) paysheet, portal_type_list=('Annotation Line',))
self.assertEquals(len(model_reference_dict), 3) # there is 4 model but two self.assertEquals(len(model_reference_dict), 3) # there is 4 model but two
# models have the same # models have the same
# reference. # reference.
...@@ -1394,8 +1397,6 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -1394,8 +1397,6 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
self.assertNotEquals(model_reference_dict.has_key(model_country_url), True) self.assertNotEquals(model_reference_dict.has_key(model_country_url), True)
# check the object list : # check the object list :
paysheet = self.createPaysheet()
paysheet.setSpecialiseValue(model_employee)
object_list = paysheet.getInheritedObjectValueList(portal_type_list=\ object_list = paysheet.getInheritedObjectValueList(portal_type_list=\
('Annotation Line',)) ('Annotation Line',))
self.assertEquals(len(object_list), 3) # one line have the same reference self.assertEquals(len(object_list), 3) # one line have the same reference
...@@ -1527,6 +1528,7 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -1527,6 +1528,7 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
base_contribution_list=['base_amount/payroll/base/contribution', base_contribution_list=['base_amount/payroll/base/contribution',
'base_amount/payroll/report/salary/gross'], 'base_amount/payroll/report/salary/gross'],
quantity=10000) quantity=10000)
self.stepTic()
# create a paysheet without date # create a paysheet without date
paysheet_without_date = self.createPaysheet() paysheet_without_date = self.createPaysheet()
...@@ -1694,9 +1696,7 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -1694,9 +1696,7 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
# check the effective model tree list # check the effective model tree list
effective_value_list = specialise_value.findEffectiveSpecialiseValueList(\ effective_value_list = specialise_value.findEffectiveSpecialiseValueList(\
context=specialise_value, context=paysheet)
start_date=paysheet.getStartDate(),
stop_date=paysheet.getStopDate())
self.assertEquals(effective_value_list, [model_2]) self.assertEquals(effective_value_list, [model_2])
def stepCreateModelLineZeroPrice(self, sequence=None, **kw): def stepCreateModelLineZeroPrice(self, sequence=None, **kw):
...@@ -1857,30 +1857,15 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -1857,30 +1857,15 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
model_1.setSpecialiseValue(model_4) model_1.setSpecialiseValue(model_4)
model_4.setSpecialiseValue(model_6) model_4.setSpecialiseValue(model_6)
paysheet.PaySheetTransaction_applyModel() paysheet.PaySheetTransaction_applyModel()
self.assertEquals(specialise_value.findSpecialiseValueList(context=paysheet), self.assertEquals([model_2],
[model_1, model_4, model_6]) specialise_value.findEffectiveSpecialiseValueList(context=paysheet))
self.assertEquals(specialise_value.findEffectiveSpecialiseValueList(\
context=paysheet, start_date=paysheet.getStartDate(),
stop_date=paysheet.getStopDate()), [model_2,])
model_1.setSpecialiseValue(None) model_1.setSpecialiseValue(None)
model_2.setSpecialiseValue(model_5) model_2.setSpecialiseValue(model_5)
model_5.setSpecialiseValue(model_6) model_5.setSpecialiseValue(model_6)
paysheet.PaySheetTransaction_applyModel() paysheet.PaySheetTransaction_applyModel()
self.assertEquals(specialise_value.findSpecialiseValueList(context=paysheet), self.assertEquals([model_2, model_5, model_7],
[model_1,]) specialise_value.findEffectiveSpecialiseValueList(context=paysheet))
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])
def stepCheckPropertiesAreCopiedFromModelLineToPaySheetLine(self, def stepCheckPropertiesAreCopiedFromModelLineToPaySheetLine(self,
sequence=None, **kw): sequence=None, **kw):
...@@ -2383,6 +2368,7 @@ class TestPayroll(TestPayrollMixin): ...@@ -2383,6 +2368,7 @@ class TestPayroll(TestPayrollMixin):
sequence_string = """ sequence_string = """
CreateModelTree CreateModelTree
ModelTreeAddAnnotationLines ModelTreeAddAnnotationLines
Tic
CheckInheritanceModelReferenceDict CheckInheritanceModelReferenceDict
""" """
sequence_list.addSequenceString(sequence_string) sequence_list.addSequenceString(sequence_string)
......
...@@ -1369,31 +1369,10 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1369,31 +1369,10 @@ class TestTradeModelLine(TestTradeModelLineMixin):
order_line_discounted.getTotalPrice() * 0.32) * 0.8 order_line_discounted.getTotalPrice() * 0.32) * 0.8
) )
# Tests def assertSameUidSet(self, a, b, msg=None):
def test_TradeConditionTradeModelLineBasicComposition(self): self.assertEqual(set(x.uid for x in a), set(x.uid for x in b), msg)
"""
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()
)
# Tests
def test_TradeConditionTradeModelLineBasicCompositionWithOrder(self): def test_TradeConditionTradeModelLineBasicCompositionWithOrder(self):
trade_condition_1 = self.createTradeCondition() trade_condition_1 = self.createTradeCondition()
trade_condition_2 = self.createTradeCondition() trade_condition_2 = self.createTradeCondition()
...@@ -1414,66 +1393,26 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1414,66 +1393,26 @@ class TestTradeModelLine(TestTradeModelLineMixin):
order, order,
reference='C') reference='C')
self.assertSameSet( self.assertSameUidSet(
[trade_condition_1_trade_model_line, trade_condition_2_trade_model_line],
trade_condition_1.getTradeModelLineComposedList()
)
self.assertSameSet(
[trade_condition_1_trade_model_line, trade_condition_2_trade_model_line, [trade_condition_1_trade_model_line, trade_condition_2_trade_model_line,
order_trade_model_line], order_trade_model_line],
trade_condition_1.getTradeModelLineComposedList(context=order) trade_condition_1.getTradeModelLineComposedList(context=order)
) )
def test_TradeConditionCircularCompositionIsSafe(self): def test_TradeConditionCircularCompositionIsSafe(self):
order = self.createOrder()
trade_condition_1 = self.createTradeCondition() trade_condition_1 = self.createTradeCondition()
trade_condition_2 = self.createTradeCondition() trade_condition_2 = self.createTradeCondition()
order.setSpecialiseValue(trade_condition_1)
trade_condition_1.setSpecialiseValue(trade_condition_2) trade_condition_1.setSpecialiseValue(trade_condition_2)
trade_condition_2.setSpecialiseValue(trade_condition_1) trade_condition_2.setSpecialiseValue(trade_condition_1)
self.assertEquals(trade_condition_1. \ self.assertEqual(trade_condition_1.findEffectiveSpecialiseValueList(order),
findSpecialiseValueList(trade_condition_1),
[trade_condition_1, trade_condition_2] [trade_condition_1, trade_condition_2]
) )
def test_findSpecialiseValueList(self): def test_findEffectiveSpecialiseValueListWithPortalType(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):
''' '''
check that findSpecialiseValueList is able to return all the inheritance check that findSpecialiseValueList is able to return all the inheritance
model tree using Depth-first search with a specific portal_type asked model tree using Depth-first search with a specific portal_type asked
...@@ -1495,45 +1434,28 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1495,45 +1434,28 @@ class TestTradeModelLine(TestTradeModelLineMixin):
As only business_process will be a "Business Process" and we search for business process As only business_process will be a "Business Process" and we search for business process
the result must be [business_process] the result must be [business_process]
''' '''
order = self.createOrder()
trade_condition_1 = self.createTradeCondition() trade_condition_1 = self.createTradeCondition()
trade_condition_2 = self.createTradeCondition() trade_condition_2 = self.createTradeCondition()
trade_condition_3 = self.createTradeCondition() trade_condition_3 = self.createTradeCondition()
trade_condition_4 = self.createTradeCondition() trade_condition_4 = self.createTradeCondition()
business_process = self.createBusinessProcess() business_process = self.createBusinessProcess()
order.setSpecialiseValue(trade_condition_1)
trade_condition_1.setSpecialiseValueList((trade_condition_2, trade_condition_1.setSpecialiseValueList((trade_condition_2,
trade_condition_3)) trade_condition_3))
trade_condition_2.setSpecialiseValue(trade_condition_4) trade_condition_2.setSpecialiseValue(trade_condition_4)
trade_condition_4.setSpecialiseValue(business_process) trade_condition_4.setSpecialiseValue(business_process)
specialise_value_list = trade_condition_1.findSpecialiseValueList( self.assertEqual(trade_condition_1.findEffectiveSpecialiseValueList(order),
portal_type_list = ['Business Process'], [trade_condition_1, trade_condition_2, trade_condition_3,
context=trade_condition_1) trade_condition_4])
self.assertEquals(len(specialise_value_list), 1) self.assertEqual(trade_condition_1.findEffectiveSpecialiseValueList(order,
self.assertEquals([business_process,] , specialise_value_list) portal_type_list = ['Business Process']), [business_process])
def test_TradeConditionTradeModelLineReferenceIsShadowingComposition(self): def test_TradeConditionTradeModelLineReferenceIsShadowingComposition(self):
trade_condition_1 = self.createTradeCondition() trade_condition_1 = self.createTradeCondition()
trade_condition_2 = 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() order = self.createOrder()
trade_condition_1.setSpecialiseValue(trade_condition_2) trade_condition_1.setSpecialiseValue(trade_condition_2)
...@@ -1551,13 +1473,7 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1551,13 +1473,7 @@ class TestTradeModelLine(TestTradeModelLineMixin):
order, order,
reference = 'B') reference = 'B')
self.assertSameSet( self.assertSameUidSet(
[trade_condition_1_trade_model_line,
trade_condition_2_trade_model_line],
trade_condition_1.getTradeModelLineComposedList()
)
self.assertSameSet(
[trade_condition_1_trade_model_line, order_trade_model_line], [trade_condition_1_trade_model_line, order_trade_model_line],
trade_condition_1.getTradeModelLineComposedList(context=order) trade_condition_1.getTradeModelLineComposedList(context=order)
) )
...@@ -1568,7 +1484,9 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1568,7 +1484,9 @@ class TestTradeModelLine(TestTradeModelLineMixin):
where we create trade model line in a wrong order in comparison to application relations 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 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() trade_condition = self.createTradeCondition()
order.setSpecialiseValue(trade_condition)
A = self.createTradeModelLine(trade_condition, reference='A', id=1, A = self.createTradeModelLine(trade_condition, reference='A', id=1,
base_contribution_list=['base_amount/total']) base_contribution_list=['base_amount/total'])
...@@ -1579,7 +1497,7 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1579,7 +1497,7 @@ class TestTradeModelLine(TestTradeModelLineMixin):
C = self.createTradeModelLine(trade_condition, reference='C', id=3, C = self.createTradeModelLine(trade_condition, reference='C', id=3,
base_contribution_list=['base_amount/total_tax'], base_contribution_list=['base_amount/total_tax'],
base_application_list=['base_amount/total']) 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], self.assertEquals([q.getReference() for q in trade_model_line_list],
[q.getReference() for q in [A, C, B,]]) [q.getReference() for q in [A, C, B,]])
...@@ -1646,7 +1564,9 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1646,7 +1564,9 @@ class TestTradeModelLine(TestTradeModelLineMixin):
* (DEFG) (BC) A * (DEFG) (BC) A
where everything in parenthesis can be not sorted where everything in parenthesis can be not sorted
""" """
order = self.createOrder()
trade_condition = self.createTradeCondition() trade_condition = self.createTradeCondition()
order.setSpecialiseValue(trade_condition)
A = self.createTradeModelLine(trade_condition, reference='A', A = self.createTradeModelLine(trade_condition, reference='A',
base_application_list=['base_amount/total']) base_application_list=['base_amount/total'])
...@@ -1675,7 +1595,7 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1675,7 +1595,7 @@ class TestTradeModelLine(TestTradeModelLineMixin):
base_contribution_list=['base_amount/total_discount'], base_contribution_list=['base_amount/total_discount'],
base_application_list=['base_amount/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 = [ possible_sort_list = [
[[D,E], [B], [F, G], [C], [A]], [[D,E], [B], [F, G], [C], [A]],
...@@ -1704,7 +1624,9 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1704,7 +1624,9 @@ class TestTradeModelLine(TestTradeModelLineMixin):
* A (BC) D * A (BC) D
where everything in parenthesis can be not sorted where everything in parenthesis can be not sorted
""" """
order = self.createOrder()
trade_condition = self.createTradeCondition() trade_condition = self.createTradeCondition()
order.setSpecialiseValue(trade_condition)
C = self.createTradeModelLine(trade_condition, reference='C', C = self.createTradeModelLine(trade_condition, reference='C',
base_contribution_list=['base_amount/total'], base_contribution_list=['base_amount/total'],
...@@ -1722,7 +1644,7 @@ class TestTradeModelLine(TestTradeModelLineMixin): ...@@ -1722,7 +1644,7 @@ class TestTradeModelLine(TestTradeModelLineMixin):
base_contribution_list=['base_amount/total'], base_contribution_list=['base_amount/total'],
base_application_list=['base_amount/total_tax']) 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 = [ possible_sort_list = [
[[A], [B,C], [D]] [[A], [B,C], [D]]
......
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