Commit 42b6d309 authored by Julien Muchembled's avatar Julien Muchembled

Commit current status of new amount generator

git-svn-id: https://svn.erp5.org/repos/public/erp5/sandbox/amount_generator@34653 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 85dca7cc
......@@ -39,6 +39,7 @@
<key> <string>group_list</string> </key>
<value>
<tuple>
<string>amount_generator_cell</string>
<string>model_path</string>
</tuple>
</value>
......
......@@ -56,6 +56,7 @@
<key> <string>group_list</string> </key>
<value>
<tuple>
<string>amount_generator_line</string>
<string>model_path</string>
</tuple>
</value>
......
......@@ -98,15 +98,18 @@ class TradeModelRuleMovementGenerator(MovementGeneratorMixin):
Generates list of movements
"""
movement_list = []
trade_condition = context.getTradeConditionValue() # XXX-JPS - which API ?
business_process = context.getBusinessProcessValue()
if trade_condition is None or business_process is None:
if business_process is None:
return movement_list
context_movement = context.getParentValue()
rule = context.getSpecialiseValue()
for amount in trade_condition.getAggregatedAmountList(context_movement):
for amount in context_movement.getAggregatedAmountList(
# XXX add a 'trade_amount_generator' group type
amount_generator_type_list=('Purchase Trade Condition',
'Sale Trade Condition',
'Trade Model Line')):
# business path specific
business_path_list = business_process.getPathValueList(
trade_phase=amount.getTradePhaseList()) # Why a list of trade phases ? XXX-JPS
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="ActionInformation" module="Products.CMFCore.ActionInformation"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/object_view</string>
</tuple>
</value>
</item>
<item>
<key> <string>category</string> </key>
<value> <string>object_view</string> </value>
</item>
<item>
<key> <string>condition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>predicate_view</string> </value>
</item>
<item>
<key> <string>permissions</string> </key>
<value>
<tuple>
<string>View</string>
</tuple>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Action Information</string> </value>
</item>
<item>
<key> <string>priority</string> </key>
<value> <float>2.0</float> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Predicate</string> </value>
</item>
<item>
<key> <string>visible</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<tuple>
<global name="Expression" module="Products.CMFCore.Expression"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>text</string> </key>
<value> <string>string:${object_url}/Predicate_view</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -19,7 +19,7 @@
</item>
<item>
<key> <string>acquisition_portal_type</string> </key>
<value> <string>python: portal.getPortalMovementTypeList()</string> </value>
<value> <string>python: portal.getPortalMovementTypeList() + portal.getPortalAmountGeneratorLineTypeList()</string> </value>
</item>
<item>
<key> <string>categories</string> </key>
......
......@@ -19,7 +19,7 @@
</item>
<item>
<key> <string>acquisition_portal_type</string> </key>
<value> <string>python: portal.getPortalMovementTypeList()</string> </value>
<value> <string>python: portal.getPortalMovementTypeList() + portal.getPortalAmountGeneratorLineTypeList()</string> </value>
</item>
<item>
<key> <string>categories</string> </key>
......
......@@ -38,6 +38,7 @@
<key> <string>group_list</string> </key>
<value>
<tuple>
<string>amount_generator_cell</string>
<string>model_path</string>
</tuple>
</value>
......
......@@ -37,6 +37,7 @@
<key> <string>group_list</string> </key>
<value>
<tuple>
<string>amount_generator_line</string>
<string>model_path</string>
</tuple>
</value>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>"""Updates context\'s movements which are related to getAggregatedAmountList models\n
Returns dictionary of needed to add or delete movements"""\n
delivery = context\n
trade_condition_portal_type_list = (\'Sale Trade Condition\',\n
\'Purchase Trade Condition\')\n
\n
trade_condition = delivery.getSpecialiseValue(portal_type=\n
trade_condition_portal_type_list)\n
\n
if trade_condition is not None:\n
return trade_condition.updateAggregatedAmountList(delivery)\n
return None\n
</string> </value>
</item>
<item>
<key> <string>_code</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>*args, **kwargs</string> </value>
</item>
<item>
<key> <string>errors</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>func_code</string> </key>
<value>
<object>
<klass>
<global name="FuncCode" module="Shared.DC.Scripts.Signature"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>co_argcount</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>co_varnames</string> </key>
<value>
<tuple>
<string>args</string>
<string>kwargs</string>
<string>context</string>
<string>delivery</string>
<string>trade_condition_portal_type_list</string>
<string>_getattr_</string>
<string>trade_condition</string>
<string>None</string>
</tuple>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>func_defaults</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Delivery_updateAggregatedAmountList</string> </value>
</item>
<item>
<key> <string>warnings</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -105,7 +105,9 @@
<item>
<key> <string>left</string> </key>
<value>
<list/>
<list>
<string>listbox_int_index</string>
</list>
</value>
</item>
<item>
......
......@@ -13,11 +13,12 @@
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>columns</string>
<string>editable_columns</string>
<string>title</string>
<string>selection_name</string>
<string>portal_types</string>
<string>columns</string>
<string>selection_name</string>
<string>sort</string>
<string>title</string>
</list>
</value>
</item>
......@@ -82,6 +83,10 @@
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string>Sort Index</string>
</tuple>
<tuple>
<string>title</string>
<string>Title</string>
......@@ -121,6 +126,10 @@
<key> <string>editable_columns</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string>int_index</string>
</tuple>
<tuple>
<string>price</string>
<string>price</string>
......@@ -155,6 +164,17 @@
<key> <string>selection_name</string> </key>
<value> <string>trade_condition_view_trade_model_line_list_selection</string> </value>
</item>
<item>
<key> <string>sort</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string></string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
......
......@@ -17,7 +17,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_target_level</string> </value>
<value> <string>listbox_int_index</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......@@ -74,7 +74,7 @@
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_target_level</string> </value>
<value> <string>my_view_mode_int_index</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
......
......@@ -108,8 +108,6 @@
<string>my_price</string>
<string>my_quantity</string>
<string>my_efficiency</string>
<string>my_target_level</string>
<string>my_calculation_script_id</string>
<string>my_create_line</string>
</list>
</value>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<tuple>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
<tuple/>
</tuple>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_calculation_script_id</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_calculation_script_id</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -163,4 +163,5 @@ Sale Trade Condition | view_payment
Sale Trade Condition | view_profile
Sale Trade Condition | view_trade_model_line_list
System Preference | trade_preference
Trade Model Line | predicate_view
Trade Model Line | view
\ No newline at end of file
......@@ -220,16 +220,6 @@ class AppliedRule(XMLObject):
movement = self.getParentValue()
return findSpecialiseValueBySimulation(movement)
security.declareProtected(Permissions.AccessContentsInformation,
'getTradeConditionValue')
def getTradeConditionValue(self):
"""Return the trade condition that has been used in this
simulation, or None if none has been used.
"""
return self._getExplanationSpecialiseValue(
('Purchase Trade Condition', 'Sale Trade Condition'))
security.declareProtected(Permissions.AccessContentsInformation,
'getBusinessProcessValue')
def getBusinessProcessValue(self):
......
......@@ -36,12 +36,14 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces
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.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
from zLOG import LOG, PROBLEM
class Delivery(XMLObject, ImmobilisationDelivery, CompositionMixin):
class Delivery(XMLObject, ImmobilisationDelivery,
CompositionMixin, AmountGeneratorMixin):
"""
Each time delivery is modified, it MUST launch a reindexing of
inventories which are related to the resources contained in the Delivery
......@@ -69,7 +71,9 @@ class Delivery(XMLObject, ImmobilisationDelivery, CompositionMixin):
)
# Declarative interfaces
zope.interface.implements(interfaces.IDivergenceController,)
zope.interface.implements(interfaces.IAmountGenerator,
interfaces.IDivergenceController,
interfaces.IMovementCollection)
security.declareProtected(Permissions.AccessContentsInformation, 'isAccountable')
def isAccountable(self):
......
......@@ -29,6 +29,7 @@
import zope.interface
from AccessControl import ClassSecurityInfo
from Acquisition import aq_base
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.Document.Predicate import Predicate
......@@ -83,7 +84,7 @@ class MappedValue(Predicate):
- add unit tests
"""
if key in self.getMappedValuePropertyList():
result = getattr(self, key, _MARKER)
result = getattr(aq_base(self), key, _MARKER)
if result is not _MARKER:
return result
if d is _MARKER:
......@@ -100,7 +101,7 @@ class MappedValue(Predicate):
- add unit tests
"""
if key in self.getMappedValuePropertyList():
result = getattr(self, key, _MARKER)
result = getattr(aq_base(self), key, _MARKER)
if result is not _MARKER:
return result
if d is None:
......
......@@ -36,12 +36,13 @@ from Products.ERP5Type.Base import Base
#from Products.ERP5.Core import MetaNode, MetaResource
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5.Document.Amount import Amount
from zLOG import LOG, WARNING
class Movement(XMLObject, Amount, CompositionMixin):
class Movement(XMLObject, Amount, CompositionMixin, AmountGeneratorMixin):
"""
The Movement class allows to implement ERP5 universal accounting model.
......@@ -181,8 +182,9 @@ class Movement(XMLObject, Amount, CompositionMixin):
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative interfaces
zope.interface.implements( interfaces.IVariated,
interfaces.IMovement )
zope.interface.implements(interfaces.IAmountGenerator,
interfaces.IVariated,
interfaces.IMovement)
# Declarative properties
property_sheets = ( PropertySheet.Base
......
......@@ -57,6 +57,8 @@ class PaySheetModel(TradeCondition, XMLMatrix):
, PropertySheet.DublinCore
, PropertySheet.Folder
, PropertySheet.Comment
, PropertySheet.Reference
, PropertySheet.Version
, PropertySheet.Arrow
, PropertySheet.TradeCondition
, PropertySheet.Order
......
......@@ -147,6 +147,26 @@ class PaySheetTransaction(Invoice):
sub_object_list.extend([model._getOb(x) for x in id_list])
return sub_object_list
security.declarePrivate('updateAggregatedAmountList')
def updateAggregatedAmountList(self, *args, **kw):
amount_dict = dict(((x.reference, tuple(x.getVariationCategoryList())), x)
for x in self.getAggregatedAmountList(*args, **kw))
movement_to_delete_list = []
for movement in self.getMovementList():
if movement.getBaseApplication():
amount = amount_dict.pop((movement.getProperty('reference'),
tuple(movement.getVariationCategoryList())),
None)
if amount is None:
movement_to_delete_list.append(movement)
else:
movement.edit(**dict((x, amount.getProperty(x))
for x in ('price', 'resource', 'quantity',
'base_application_list', 'base_contribution_list')))
return {'movement_to_delete_list': movement_to_delete_list,
'movement_to_add_list': amount_dict.values()}
security.declareProtected(Permissions.ModifyPortalContent,
'applyTransformation')
def applyTransformation(self):
......@@ -155,7 +175,7 @@ class PaySheetTransaction(Invoice):
'''
portal = self.getPortalObject()
paysheet_model = self.getSpecialiseValue()
movement_dict = paysheet_model.updateAggregatedAmountList(context=self)
movement_dict = self.updateAggregatedAmountList()
for movement in movement_dict['movement_to_delete_list']:
parent = movement.getParentValue()
if parent.getPortalType() == 'Pay Sheet Line':
......
......@@ -306,6 +306,22 @@ class SimulationMovement(Movement, PropertyRecordableMixin):
if explanation_value != portal:
return explanation_value
def asComposedDocument(self, *args, **kw):
# XXX: What delivery should be used to find amount generator lines ?
# With the currently enabled code, entire branches in the simulation
# tree get (temporary) deleted when new delivery lines are being built
# (and don't have yet a specialise value).
# With the commented code, changing the STC on a SIT generated from a
# SPL/SO would have no impact (and would never make the SIT divergent).
#return self.getRootSimulationMovement() \
# .getDeliveryValue() \
# .asComposedDocument(*args, **kw)
while 1:
delivery_value = self.getDeliveryValue()
if delivery_value is not None:
return delivery_value.asComposedDocument(*args, **kw)
self = self.getParentValue().getParentValue()
# Deliverability / orderability
security.declareProtected( Permissions.AccessContentsInformation,
'isOrderable')
......
......@@ -30,18 +30,17 @@
#
##############################################################################
from collections import deque
import warnings
import zope.interface
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.Utils import deprecated
from Products.ERP5.mixin.composition import _getEffectiveModel
from Products.ERP5.Document.Transformation import Transformation
from Products.ERP5.AggregatedAmountList import AggregatedAmountList
from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
from Products.ERP5.Document.MappedValue import MappedValue
from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.variated import VariatedMixin
......@@ -51,9 +50,6 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin):
which should be applied (and used in the orders) when two companies make
business together
"""
edited_property_list = ['price', 'resource', 'quantity',
'reference', 'base_application_list', 'base_contribution_list']
meta_type = 'ERP5 Trade Condition'
portal_type = 'Trade Condition'
model_line_portal_type_list = ('Trade Model Line',)
......@@ -69,6 +65,8 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin):
, PropertySheet.DublinCore
, PropertySheet.Folder
, PropertySheet.Comment
, PropertySheet.Reference
, PropertySheet.Version
, PropertySheet.Arrow
, PropertySheet.TradeCondition
, PropertySheet.Order
......@@ -87,29 +85,9 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin):
def getMappedValueBaseCategoryList(self):
return ()
# Amount Generator Mixin
def _getGlobalPropertyDict(self, context, amount_list=None, rounding=False):
"""
No global properties needed
"""
return {
'delivery_count' : 1, # Use a better category here if possible - XXX - System preference
}
def _getAmountPropertyDict(self, amount, amount_list=None, rounding=False):
"""
Produced amount quantity is needed to initialize transformation
"""
result = {
'quantity' : amount.getQuantity(), # Use a better category here if possible - XXX - System preference
# and possibly make it extensible
}
for category in amount.getBaseContributionList():
result[category] = amount.getTotalPrice()
return result
security.declareProtected(Permissions.AccessContentsInformation,
'findEffectiveSpecialiseValueList')
#deprecated # XXX
def findEffectiveSpecialiseValueList(self, context, portal_type_list=None):
"""Return a list of effective specialised objects that is the
inheritance tree.
......@@ -123,91 +101,24 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin):
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):
"""Returns list of Trade Model Lines using composition.
Reference of Trade Model Line is used to hide other Trade Model Line
In chain first found Trade Model Line has precedence
Context's, if not None, Trade Model Lines have precedence
Result is sorted in safe order to do one time pass - movements which
applies are before its possible contributions.
def getAggregatedAmountList(self, *args, **kw):
"""
if portal_type_list is None:
portal_type_list = self.model_line_portal_type_list
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---\
# \
# C-----> A
# A is parent of B and C, and returned order should be
# (BC) A
# where (BC) cannot be sorted
parent_dict = {}
# B and C are leaves
leaf_line_list = []
for line in trade_model_line_composed_list:
has_child = False
for other_line in trade_model_line_composed_list:
if line == other_line:
continue
parent_dict.setdefault(other_line, [])
for base_application in line.getBaseApplicationList():
if base_application in other_line.getBaseContributionList():
parent_dict[other_line].append(line)
has_child = True
if not has_child:
leaf_line_list.append(line)
final_list = []
if len(parent_dict):
# longest distance to a root (A)
depth = {}
tovisit = leaf_line_list
while tovisit:
node = tovisit[-1]
if node in depth:
tovisit.pop()
continue
parent_list = parent_dict.get(node, [])
if len(parent_list) == 0:
depth[node] = 0
tovisit.pop()
else:
for parent in parent_list:
if parent not in depth:
tovisit.append(parent)
if tovisit[-1] == node:
depth[node] = max(depth[p] for p in parent_list) + 1
tovisit.pop()
# the farther a line is from a root, the earlier it should be returned
final_list = sorted(depth.iterkeys(), key=depth.get, reverse=True)
if len(final_list) == 0:
# at least return original lines retrieved
final_list = trade_model_line_composed_list
return final_list
security.declareProtected(Permissions.AccessContentsInformation,
'getAggregatedAmountList')
def getAggregatedAmountList(self, context, amount_list=None,
force_create_line=False, **kw):
"""
XXX-JPS - TODO
"""
return self.getGeneratedAmountList(context, amount_list=amount_list, **kw)
# Detect old use of getAggregatedAmountList
if 'context' in kw:
context = kw.pop('context')
else:
if 'force_create_line' in kw:
del kw['force_create_line']
elif not args or isinstance(args[0], (list, tuple)):
return AmountGeneratorMixin.getAggregatedAmountList(self, *args, **kw)
context, args = args[0], args[1:]
warnings.warn("The API of getAggregatedAmountList has changed:"
" it must be called on the context instead of passing"
" the context as first parameter", DeprecationWarning)
return context.getAggregatedAmountList(*args, **kw)
#deprecated # XXX
security.declareProtected(Permissions.AccessContentsInformation,
'getEffectiveModel')
def getEffectiveModel(self, start_date=None, stop_date=None):
......
......@@ -72,13 +72,6 @@ class TradeModelCell(TradeModelLine, MappedValue):
"""
return 0
def updateAggregatedAmountList(self, context, **kw):
raise NotImplementedError('TODO')
def getAggregatedAmountList(self, context, movement_list = None,
current_aggregated_amount_list = None, **kw):
raise NotImplementedError('TODO')
security.declareProtected(Permissions.AccessContentsInformation,
'getPrice')
def getPrice(self):
......
This diff is collapsed.
......@@ -217,9 +217,6 @@ class Transformation(XMLObject, Predicate, Variated):
render(object_list))
return variation_category_item_list
def updateAggregatedAmountList(self, context, **kw):
raise NotImplementedError, 'need?'
security.declareProtected(Permissions.AccessContentsInformation,
'getAggregatedAmountList')
def getAggregatedAmountList(self, context=None, REQUEST=None,
......
......@@ -128,9 +128,6 @@ class TransformedResource(Predicate, XMLObject, XMLMatrix, Amount):
self._setVVariationBaseCategoryList(value)
self.reindexObject()
def updateAggregatedAmountList(self, context, **kw):
raise NotImplementedError('TODO')
security.declareProtected(Permissions.AccessContentsInformation,
'getAggregatedAmountList')
def getAggregatedAmountList(self, context, REQUEST=None, **kw):
......
......@@ -35,4 +35,5 @@ class Delivery:
Delivery objects usually have a causality.
"""
_categories = ('causality', 'incoterm', 'delivery_mode', 'solver')
_categories = ('causality', 'incoterm', 'delivery_mode', 'solver',
'base_contribution')
......@@ -28,12 +28,6 @@
##############################################################################
from AccessControl import ModuleSecurityInfo
TARGET_LEVEL_DELIVERY = 'DELIVERY'
TARGET_LEVEL_MOVEMENT = 'MOVEMENT'
ModuleSecurityInfo('Products.ERP5.PropertySheet.TradeModelLine').declarePublic(
'TARGET_LEVEL_DELIVERY', 'TARGET_LEVEL_MOVEMENT')
class TradeModelLine:
"""
......@@ -47,33 +41,6 @@ class TradeModelLine:
'mode' : 'w',
'default' : True,
},
{ 'id' : 'calculation_script_id',
'description' : 'If a script is defined on trade model Line, this '
'script will be used for calculation',
'type' : 'string',
'mode' : 'w',
},
{ 'id' : 'target_level',
'description' : 'Target level defines how trade model line is applied to '
'what(a set of movement or a movement). If target level '
'is `delivery`, then this is applied only at delivery '
'level(for example, VAT to total price of order). And if '
'target level is `movement`, then this is applied to one '
'movement and result will not be summed up(for example, '
'VAT to each order line). If target level is neither '
'delivery nor movement, this is applied to anything '
'without restriction.',
'type' : 'selection',
'select_variable' : 'getTargetLevelSelectionList',
'mode' : 'w',
'default' : None,
},
{ 'id' : 'target_level_selection',
'description' : 'List of possible values for target_level property',
'type' : 'tokens',
'mode' : '',
'default' : [TARGET_LEVEL_DELIVERY, TARGET_LEVEL_MOVEMENT],
},
)
_categories = (
......
......@@ -43,19 +43,21 @@ class IAmountGenerator(Interface):
and Trade Conditions.
"""
def getAggregatedAmountList(context, amount_list=None, rounding=False):
def getAggregatedAmountList(amount_list=None, rounding=False,
amount_generator_type_list=None):
"""
Returns an IAmountList generated by a model applied to the context.
Returns an IAmountList generated by a model applied to a list of amounts,
and aggregated according to the context divergence testers.
context - an IMovementCollection, an IAmountList or an IAmount
amount_list - Optional IAmountList that can be passed explicitly.
If not given, it is computed from 'self', which must
be an IMovementCollection, an IAmountList or an IAmount.
amount_list - optional IAmountList which can be passed explicitly
whenever context is an IMovementCollection and whenever
we want to filter context.getMovementList
rounding - Boolean argument, which controls if rounding shall be applied on
generated movements or not.
rounding - boolean argument, which controls if rounding shall be applied on
generated movements or not
amount_generator_type_list - Optional list of portal type names to filter
specialise objects and amount generator lines.
NOTE:
- implement rounding appropriately (True or False seems
......@@ -63,18 +65,20 @@ class IAmountGenerator(Interface):
- define how to retrieve divergence testers in the context
"""
def getGeneratedAmountList(context, amount_list=None, rounding=False):
def getGeneratedAmountList(amount_list=None, rounding=False,
amount_generator_type_list=None):
"""
Returns an IAmountList generated by a model applied to the context.
Returns an IAmountList generated by a model applied to a list of amounts.
context - an IMovementCollection, an IAmountList or an IAmount
amount_list - Optional IAmountList that can be passed explicitly.
If not given, it is computed from 'self', which must
be an IMovementCollection, an IAmountList or an IAmount.
amount_list - optional IAmountList which can be passed explicitly
whenever context is an IMovementCollection and whenever
we want to filter context.getMovementList
rounding - Boolean argument, which controls if rounding shall be applied on
generated movements or not.
rounding - boolean argument, which controls if rounding shall be applied on
generated movements or not
amount_generator_type_list - Optional list of portal type names to filter
specialise objects and amount generator lines.
NOTE:
- implement rounding appropriately (True or False seems
......
This diff is collapsed.
......@@ -47,7 +47,7 @@ def _getEffectiveModel(self, start_date=None, stop_date=None):
XXX Should we moved this function to a class ? Which one ?
What about reusing IVersionable ?
"""
reference = self.getReference()
reference = self.getProperty('reference')
if not reference:
return self
......
......@@ -178,7 +178,7 @@ class RuleMixin:
exclude_quantity -- if set to true, do not consider
quantity divergence testers
"""
"""
if exclude_quantity:
return filter(lambda x:x.isDivergenceProvider() and \
'quantity' not in x.getTestedPropertyList(), self.objectValues(
......@@ -203,7 +203,7 @@ class RuleMixin:
exclude_quantity -- if set to true, do not consider
quantity divergence testers
"""
"""
if exclude_quantity:
return filter(lambda x:x.isUpdatingProvider() and \
'quantity' not in x.getTestedPropertyList(), self.objectValues(
......
......@@ -506,9 +506,9 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
mapped_value_property_list=('quantity', 'price'))
cell2.edit(quantity=1000, price=1, contribution_share='employer')
def checkUpdateAggregatedAmountListReturn(self, model, paysheet,
def checkUpdateAggregatedAmountListReturn(self, paysheet,
expected_movement_to_delete_count, expected_movement_to_add_count):
movement_dict = model.updateAggregatedAmountList(context=paysheet)
movement_dict = paysheet.updateAggregatedAmountList()
movement_to_delete = movement_dict['movement_to_delete_list']
movement_to_add = movement_dict['movement_to_add_list']
self.assertEquals(len(movement_to_delete),
......@@ -516,27 +516,23 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
self.assertEquals(len(movement_to_add), expected_movement_to_add_count)
def stepCheckUpdateAggregatedAmountListReturn(self, sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 2)
self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 2)
def stepCheckUpdateAggregatedAmountListReturnUsingSlices(self,
sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 6)
self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 6)
def stepCheckUpdateAggregatedAmountListReturnUsingComplexSlices(self,
sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 4)
self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 4)
def stepCheckUpdateAggregatedAmountListReturnUsingPredicate(self,
sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 4)
self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 4)
def stepCheckUpdateAggregatedAmountListReturnAfterChangePredicate(self,
sequence=None, **kw):
......@@ -544,15 +540,13 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
# insurance model_line will not be applied but old age insurance yes.
# So two movements will be deleted (from sickness insurance) and two should
# be added (from old age insurance)
model = sequence.get('model')
paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 2, 2)
self.checkUpdateAggregatedAmountListReturn(paysheet, 2, 2)
def stepCheckUpdateAggregatedAmountListReturnAfterRemoveLine(self,
sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 2, 0)
self.checkUpdateAggregatedAmountListReturn(paysheet, 2, 0)
def stepPaysheetApplyTransformation(self, sequence=None, **kw):
paysheet = sequence.get('paysheet')
......@@ -836,8 +830,7 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
def stepCheckUpdateAggregatedAmountListReturnNothing(self, sequence=None, **kw):
paysheet = sequence.get('paysheet')
model = sequence.get('model')
movement_dict = model.updateAggregatedAmountList(context=paysheet)
movement_dict = paysheet.updateAggregatedAmountList()
movement_to_delete = movement_dict['movement_to_delete_list']
movement_to_add = movement_dict['movement_to_add_list']
self.assertEquals(len(movement_to_delete), 0)
......@@ -1207,9 +1200,8 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
def stepCheckUpdateAggregatedAmountListReturnWithModelLineOnPaysheet(self,
sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 4)
self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 4)
def stepCheckPaysheetLineAreCreatedWithModelLineOnPaysheet(self,
sequence=None, **kw):
......
This diff is collapsed.
......@@ -51,7 +51,8 @@ class TradeModelRule(Rule):
"""Generates list of movements (as dicts), and let parent class to decide
which is to add, modify or delete"""
movement_list = []
trade_condition = applied_rule.getTradeConditionValue()
trade_condition = applied_rule._getExplanationSpecialiseValue(
('Purchase Trade Condition', 'Sale Trade Condition'))
business_process = applied_rule.getBusinessProcessValue()
if trade_condition is None or business_process is None:
......
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