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 @@ ...@@ -39,6 +39,7 @@
<key> <string>group_list</string> </key> <key> <string>group_list</string> </key>
<value> <value>
<tuple> <tuple>
<string>amount_generator_cell</string>
<string>model_path</string> <string>model_path</string>
</tuple> </tuple>
</value> </value>
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
<key> <string>group_list</string> </key> <key> <string>group_list</string> </key>
<value> <value>
<tuple> <tuple>
<string>amount_generator_line</string>
<string>model_path</string> <string>model_path</string>
</tuple> </tuple>
</value> </value>
......
...@@ -98,15 +98,18 @@ class TradeModelRuleMovementGenerator(MovementGeneratorMixin): ...@@ -98,15 +98,18 @@ class TradeModelRuleMovementGenerator(MovementGeneratorMixin):
Generates list of movements Generates list of movements
""" """
movement_list = [] movement_list = []
trade_condition = context.getTradeConditionValue() # XXX-JPS - which API ?
business_process = context.getBusinessProcessValue() business_process = context.getBusinessProcessValue()
if trade_condition is None or business_process is None: if business_process is None:
return movement_list return movement_list
context_movement = context.getParentValue() context_movement = context.getParentValue()
rule = context.getSpecialiseValue() 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 specific
business_path_list = business_process.getPathValueList( business_path_list = business_process.getPathValueList(
trade_phase=amount.getTradePhaseList()) # Why a list of trade phases ? XXX-JPS 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 @@ ...@@ -19,7 +19,7 @@
</item> </item>
<item> <item>
<key> <string>acquisition_portal_type</string> </key> <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>
<item> <item>
<key> <string>categories</string> </key> <key> <string>categories</string> </key>
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
</item> </item>
<item> <item>
<key> <string>acquisition_portal_type</string> </key> <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>
<item> <item>
<key> <string>categories</string> </key> <key> <string>categories</string> </key>
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
<key> <string>group_list</string> </key> <key> <string>group_list</string> </key>
<value> <value>
<tuple> <tuple>
<string>amount_generator_cell</string>
<string>model_path</string> <string>model_path</string>
</tuple> </tuple>
</value> </value>
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
<key> <string>group_list</string> </key> <key> <string>group_list</string> </key>
<value> <value>
<tuple> <tuple>
<string>amount_generator_line</string>
<string>model_path</string> <string>model_path</string>
</tuple> </tuple>
</value> </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 @@ ...@@ -105,7 +105,9 @@
<item> <item>
<key> <string>left</string> </key> <key> <string>left</string> </key>
<value> <value>
<list/> <list>
<string>listbox_int_index</string>
</list>
</value> </value>
</item> </item>
<item> <item>
......
...@@ -13,11 +13,12 @@ ...@@ -13,11 +13,12 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>columns</string>
<string>editable_columns</string> <string>editable_columns</string>
<string>title</string>
<string>selection_name</string>
<string>portal_types</string> <string>portal_types</string>
<string>columns</string> <string>selection_name</string>
<string>sort</string>
<string>title</string>
</list> </list>
</value> </value>
</item> </item>
...@@ -82,6 +83,10 @@ ...@@ -82,6 +83,10 @@
<key> <string>columns</string> </key> <key> <string>columns</string> </key>
<value> <value>
<list> <list>
<tuple>
<string>int_index</string>
<string>Sort Index</string>
</tuple>
<tuple> <tuple>
<string>title</string> <string>title</string>
<string>Title</string> <string>Title</string>
...@@ -121,6 +126,10 @@ ...@@ -121,6 +126,10 @@
<key> <string>editable_columns</string> </key> <key> <string>editable_columns</string> </key>
<value> <value>
<list> <list>
<tuple>
<string>int_index</string>
<string>int_index</string>
</tuple>
<tuple> <tuple>
<string>price</string> <string>price</string>
<string>price</string> <string>price</string>
...@@ -155,6 +164,17 @@ ...@@ -155,6 +164,17 @@
<key> <string>selection_name</string> </key> <key> <string>selection_name</string> </key>
<value> <string>trade_condition_view_trade_model_line_list_selection</string> </value> <value> <string>trade_condition_view_trade_model_line_list_selection</string> </value>
</item> </item>
<item>
<key> <string>sort</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string></string>
</tuple>
</list>
</value>
</item>
<item> <item>
<key> <string>target</string> </key> <key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value> <value> <string>Click to edit the target</string> </value>
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>my_target_level</string> </value> <value> <string>listbox_int_index</string> </value>
</item> </item>
<item> <item>
<key> <string>message_values</string> </key> <key> <string>message_values</string> </key>
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>field_id</string> </key> <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>
<item> <item>
<key> <string>form_id</string> </key> <key> <string>form_id</string> </key>
......
...@@ -108,8 +108,6 @@ ...@@ -108,8 +108,6 @@
<string>my_price</string> <string>my_price</string>
<string>my_quantity</string> <string>my_quantity</string>
<string>my_efficiency</string> <string>my_efficiency</string>
<string>my_target_level</string>
<string>my_calculation_script_id</string>
<string>my_create_line</string> <string>my_create_line</string>
</list> </list>
</value> </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 ...@@ -163,4 +163,5 @@ Sale Trade Condition | view_payment
Sale Trade Condition | view_profile Sale Trade Condition | view_profile
Sale Trade Condition | view_trade_model_line_list Sale Trade Condition | view_trade_model_line_list
System Preference | trade_preference System Preference | trade_preference
Trade Model Line | predicate_view
Trade Model Line | view Trade Model Line | view
\ No newline at end of file
...@@ -220,16 +220,6 @@ class AppliedRule(XMLObject): ...@@ -220,16 +220,6 @@ class AppliedRule(XMLObject):
movement = self.getParentValue() movement = self.getParentValue()
return findSpecialiseValueBySimulation(movement) 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, security.declareProtected(Permissions.AccessContentsInformation,
'getBusinessProcessValue') 'getBusinessProcessValue')
def getBusinessProcessValue(self): def getBusinessProcessValue(self):
......
...@@ -36,12 +36,14 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces ...@@ -36,12 +36,14 @@ 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.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.composition import CompositionMixin 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, CompositionMixin): class Delivery(XMLObject, ImmobilisationDelivery,
CompositionMixin, AmountGeneratorMixin):
""" """
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
...@@ -69,7 +71,9 @@ class Delivery(XMLObject, ImmobilisationDelivery, CompositionMixin): ...@@ -69,7 +71,9 @@ class Delivery(XMLObject, ImmobilisationDelivery, CompositionMixin):
) )
# Declarative interfaces # Declarative interfaces
zope.interface.implements(interfaces.IDivergenceController,) zope.interface.implements(interfaces.IAmountGenerator,
interfaces.IDivergenceController,
interfaces.IMovementCollection)
security.declareProtected(Permissions.AccessContentsInformation, 'isAccountable') security.declareProtected(Permissions.AccessContentsInformation, 'isAccountable')
def isAccountable(self): def isAccountable(self):
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Acquisition import aq_base
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5.Document.Predicate import Predicate from Products.ERP5.Document.Predicate import Predicate
...@@ -83,7 +84,7 @@ class MappedValue(Predicate): ...@@ -83,7 +84,7 @@ class MappedValue(Predicate):
- add unit tests - add unit tests
""" """
if key in self.getMappedValuePropertyList(): if key in self.getMappedValuePropertyList():
result = getattr(self, key, _MARKER) result = getattr(aq_base(self), key, _MARKER)
if result is not _MARKER: if result is not _MARKER:
return result return result
if d is _MARKER: if d is _MARKER:
...@@ -100,7 +101,7 @@ class MappedValue(Predicate): ...@@ -100,7 +101,7 @@ class MappedValue(Predicate):
- add unit tests - add unit tests
""" """
if key in self.getMappedValuePropertyList(): if key in self.getMappedValuePropertyList():
result = getattr(self, key, _MARKER) result = getattr(aq_base(self), key, _MARKER)
if result is not _MARKER: if result is not _MARKER:
return result return result
if d is None: if d is None:
......
...@@ -36,12 +36,13 @@ from Products.ERP5Type.Base import Base ...@@ -36,12 +36,13 @@ from Products.ERP5Type.Base import Base
#from Products.ERP5.Core import MetaNode, MetaResource #from Products.ERP5.Core import MetaNode, MetaResource
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.composition import CompositionMixin from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5.Document.Amount import Amount from Products.ERP5.Document.Amount import Amount
from zLOG import LOG, WARNING 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. The Movement class allows to implement ERP5 universal accounting model.
...@@ -181,8 +182,9 @@ class Movement(XMLObject, Amount, CompositionMixin): ...@@ -181,8 +182,9 @@ class Movement(XMLObject, Amount, CompositionMixin):
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative interfaces # Declarative interfaces
zope.interface.implements( interfaces.IVariated, zope.interface.implements(interfaces.IAmountGenerator,
interfaces.IMovement ) interfaces.IVariated,
interfaces.IMovement)
# Declarative properties # Declarative properties
property_sheets = ( PropertySheet.Base property_sheets = ( PropertySheet.Base
......
...@@ -57,6 +57,8 @@ class PaySheetModel(TradeCondition, XMLMatrix): ...@@ -57,6 +57,8 @@ class PaySheetModel(TradeCondition, XMLMatrix):
, PropertySheet.DublinCore , PropertySheet.DublinCore
, PropertySheet.Folder , PropertySheet.Folder
, PropertySheet.Comment , PropertySheet.Comment
, PropertySheet.Reference
, PropertySheet.Version
, PropertySheet.Arrow , PropertySheet.Arrow
, PropertySheet.TradeCondition , PropertySheet.TradeCondition
, PropertySheet.Order , PropertySheet.Order
......
...@@ -147,6 +147,26 @@ class PaySheetTransaction(Invoice): ...@@ -147,6 +147,26 @@ class PaySheetTransaction(Invoice):
sub_object_list.extend([model._getOb(x) for x in id_list]) sub_object_list.extend([model._getOb(x) for x in id_list])
return sub_object_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, security.declareProtected(Permissions.ModifyPortalContent,
'applyTransformation') 'applyTransformation')
def applyTransformation(self): def applyTransformation(self):
...@@ -155,7 +175,7 @@ class PaySheetTransaction(Invoice): ...@@ -155,7 +175,7 @@ class PaySheetTransaction(Invoice):
''' '''
portal = self.getPortalObject() portal = self.getPortalObject()
paysheet_model = self.getSpecialiseValue() paysheet_model = self.getSpecialiseValue()
movement_dict = paysheet_model.updateAggregatedAmountList(context=self) movement_dict = self.updateAggregatedAmountList()
for movement in movement_dict['movement_to_delete_list']: for movement in movement_dict['movement_to_delete_list']:
parent = movement.getParentValue() parent = movement.getParentValue()
if parent.getPortalType() == 'Pay Sheet Line': if parent.getPortalType() == 'Pay Sheet Line':
......
...@@ -306,6 +306,22 @@ class SimulationMovement(Movement, PropertyRecordableMixin): ...@@ -306,6 +306,22 @@ class SimulationMovement(Movement, PropertyRecordableMixin):
if explanation_value != portal: if explanation_value != portal:
return explanation_value 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 # Deliverability / orderability
security.declareProtected( Permissions.AccessContentsInformation, security.declareProtected( Permissions.AccessContentsInformation,
'isOrderable') 'isOrderable')
......
...@@ -30,18 +30,17 @@ ...@@ -30,18 +30,17 @@
# #
############################################################################## ##############################################################################
from collections import deque import warnings
import zope.interface import zope.interface
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.Utils import deprecated
from Products.ERP5.mixin.composition import _getEffectiveModel from Products.ERP5.mixin.composition import _getEffectiveModel
from Products.ERP5.Document.Transformation import Transformation from Products.ERP5.Document.Transformation import Transformation
from Products.ERP5.AggregatedAmountList import AggregatedAmountList from Products.ERP5.AggregatedAmountList import AggregatedAmountList
from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
from Products.ERP5.Document.MappedValue import MappedValue from Products.ERP5.Document.MappedValue import MappedValue
from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin
from Products.ERP5.mixin.variated import VariatedMixin from Products.ERP5.mixin.variated import VariatedMixin
...@@ -51,9 +50,6 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin): ...@@ -51,9 +50,6 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin):
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
business together business together
""" """
edited_property_list = ['price', 'resource', 'quantity',
'reference', 'base_application_list', 'base_contribution_list']
meta_type = 'ERP5 Trade Condition' meta_type = 'ERP5 Trade Condition'
portal_type = 'Trade Condition' portal_type = 'Trade Condition'
model_line_portal_type_list = ('Trade Model Line',) model_line_portal_type_list = ('Trade Model Line',)
...@@ -69,6 +65,8 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin): ...@@ -69,6 +65,8 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin):
, PropertySheet.DublinCore , PropertySheet.DublinCore
, PropertySheet.Folder , PropertySheet.Folder
, PropertySheet.Comment , PropertySheet.Comment
, PropertySheet.Reference
, PropertySheet.Version
, PropertySheet.Arrow , PropertySheet.Arrow
, PropertySheet.TradeCondition , PropertySheet.TradeCondition
, PropertySheet.Order , PropertySheet.Order
...@@ -87,29 +85,9 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin): ...@@ -87,29 +85,9 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin):
def getMappedValueBaseCategoryList(self): def getMappedValueBaseCategoryList(self):
return () 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, security.declareProtected(Permissions.AccessContentsInformation,
'findEffectiveSpecialiseValueList') 'findEffectiveSpecialiseValueList')
#deprecated # XXX
def findEffectiveSpecialiseValueList(self, context, portal_type_list=None): def findEffectiveSpecialiseValueList(self, context, 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.
...@@ -123,91 +101,24 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin): ...@@ -123,91 +101,24 @@ class TradeCondition(MappedValue, AmountGeneratorMixin, VariatedMixin):
return [x for x in context._findEffectiveSpecialiseValueList() return [x for x in context._findEffectiveSpecialiseValueList()
if x.getPortalType() in portal_type_set] if x.getPortalType() in portal_type_set]
security.declareProtected(Permissions.AccessContentsInformation, def getAggregatedAmountList(self, *args, **kw):
'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.
""" """
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 # Detect old use of getAggregatedAmountList
""" if 'context' in kw:
return self.getGeneratedAmountList(context, amount_list=amount_list, **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, security.declareProtected(Permissions.AccessContentsInformation,
'getEffectiveModel') 'getEffectiveModel')
def getEffectiveModel(self, start_date=None, stop_date=None): def getEffectiveModel(self, start_date=None, stop_date=None):
......
...@@ -72,13 +72,6 @@ class TradeModelCell(TradeModelLine, MappedValue): ...@@ -72,13 +72,6 @@ class TradeModelCell(TradeModelLine, MappedValue):
""" """
return 0 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, security.declareProtected(Permissions.AccessContentsInformation,
'getPrice') 'getPrice')
def getPrice(self): def getPrice(self):
......
This diff is collapsed.
...@@ -217,9 +217,6 @@ class Transformation(XMLObject, Predicate, Variated): ...@@ -217,9 +217,6 @@ class Transformation(XMLObject, Predicate, Variated):
render(object_list)) render(object_list))
return variation_category_item_list return variation_category_item_list
def updateAggregatedAmountList(self, context, **kw):
raise NotImplementedError, 'need?'
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getAggregatedAmountList') 'getAggregatedAmountList')
def getAggregatedAmountList(self, context=None, REQUEST=None, def getAggregatedAmountList(self, context=None, REQUEST=None,
......
...@@ -128,9 +128,6 @@ class TransformedResource(Predicate, XMLObject, XMLMatrix, Amount): ...@@ -128,9 +128,6 @@ class TransformedResource(Predicate, XMLObject, XMLMatrix, Amount):
self._setVVariationBaseCategoryList(value) self._setVVariationBaseCategoryList(value)
self.reindexObject() self.reindexObject()
def updateAggregatedAmountList(self, context, **kw):
raise NotImplementedError('TODO')
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getAggregatedAmountList') 'getAggregatedAmountList')
def getAggregatedAmountList(self, context, REQUEST=None, **kw): def getAggregatedAmountList(self, context, REQUEST=None, **kw):
......
...@@ -35,4 +35,5 @@ class Delivery: ...@@ -35,4 +35,5 @@ class Delivery:
Delivery objects usually have a causality. Delivery objects usually have a causality.
""" """
_categories = ('causality', 'incoterm', 'delivery_mode', 'solver') _categories = ('causality', 'incoterm', 'delivery_mode', 'solver',
'base_contribution')
...@@ -28,12 +28,6 @@ ...@@ -28,12 +28,6 @@
############################################################################## ##############################################################################
from AccessControl import ModuleSecurityInfo 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: class TradeModelLine:
""" """
...@@ -47,33 +41,6 @@ class TradeModelLine: ...@@ -47,33 +41,6 @@ class TradeModelLine:
'mode' : 'w', 'mode' : 'w',
'default' : True, '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 = ( _categories = (
......
...@@ -43,19 +43,21 @@ class IAmountGenerator(Interface): ...@@ -43,19 +43,21 @@ class IAmountGenerator(Interface):
and Trade Conditions. 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. 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 rounding - Boolean argument, which controls if rounding shall be applied on
whenever context is an IMovementCollection and whenever generated movements or not.
we want to filter context.getMovementList
rounding - boolean argument, which controls if rounding shall be applied on amount_generator_type_list - Optional list of portal type names to filter
generated movements or not specialise objects and amount generator lines.
NOTE: NOTE:
- implement rounding appropriately (True or False seems - implement rounding appropriately (True or False seems
...@@ -63,18 +65,20 @@ class IAmountGenerator(Interface): ...@@ -63,18 +65,20 @@ class IAmountGenerator(Interface):
- define how to retrieve divergence testers in the context - 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 rounding - Boolean argument, which controls if rounding shall be applied on
whenever context is an IMovementCollection and whenever generated movements or not.
we want to filter context.getMovementList
rounding - boolean argument, which controls if rounding shall be applied on amount_generator_type_list - Optional list of portal type names to filter
generated movements or not specialise objects and amount generator lines.
NOTE: NOTE:
- implement rounding appropriately (True or False seems - implement rounding appropriately (True or False seems
......
This diff is collapsed.
...@@ -47,7 +47,7 @@ def _getEffectiveModel(self, start_date=None, stop_date=None): ...@@ -47,7 +47,7 @@ def _getEffectiveModel(self, start_date=None, stop_date=None):
XXX Should we moved this function to a class ? Which one ? XXX Should we moved this function to a class ? Which one ?
What about reusing IVersionable ? What about reusing IVersionable ?
""" """
reference = self.getReference() reference = self.getProperty('reference')
if not reference: if not reference:
return self return self
......
...@@ -178,7 +178,7 @@ class RuleMixin: ...@@ -178,7 +178,7 @@ class RuleMixin:
exclude_quantity -- if set to true, do not consider exclude_quantity -- if set to true, do not consider
quantity divergence testers quantity divergence testers
""" """
if exclude_quantity: if exclude_quantity:
return filter(lambda x:x.isDivergenceProvider() and \ return filter(lambda x:x.isDivergenceProvider() and \
'quantity' not in x.getTestedPropertyList(), self.objectValues( 'quantity' not in x.getTestedPropertyList(), self.objectValues(
...@@ -203,7 +203,7 @@ class RuleMixin: ...@@ -203,7 +203,7 @@ class RuleMixin:
exclude_quantity -- if set to true, do not consider exclude_quantity -- if set to true, do not consider
quantity divergence testers quantity divergence testers
""" """
if exclude_quantity: if exclude_quantity:
return filter(lambda x:x.isUpdatingProvider() and \ return filter(lambda x:x.isUpdatingProvider() and \
'quantity' not in x.getTestedPropertyList(), self.objectValues( 'quantity' not in x.getTestedPropertyList(), self.objectValues(
......
...@@ -506,9 +506,9 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -506,9 +506,9 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
mapped_value_property_list=('quantity', 'price')) mapped_value_property_list=('quantity', 'price'))
cell2.edit(quantity=1000, price=1, contribution_share='employer') 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): 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_delete = movement_dict['movement_to_delete_list']
movement_to_add = movement_dict['movement_to_add_list'] movement_to_add = movement_dict['movement_to_add_list']
self.assertEquals(len(movement_to_delete), self.assertEquals(len(movement_to_delete),
...@@ -516,27 +516,23 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -516,27 +516,23 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
self.assertEquals(len(movement_to_add), expected_movement_to_add_count) self.assertEquals(len(movement_to_add), expected_movement_to_add_count)
def stepCheckUpdateAggregatedAmountListReturn(self, sequence=None, **kw): def stepCheckUpdateAggregatedAmountListReturn(self, sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 2) self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 2)
def stepCheckUpdateAggregatedAmountListReturnUsingSlices(self, def stepCheckUpdateAggregatedAmountListReturnUsingSlices(self,
sequence=None, **kw): sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 6) self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 6)
def stepCheckUpdateAggregatedAmountListReturnUsingComplexSlices(self, def stepCheckUpdateAggregatedAmountListReturnUsingComplexSlices(self,
sequence=None, **kw): sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 4) self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 4)
def stepCheckUpdateAggregatedAmountListReturnUsingPredicate(self, def stepCheckUpdateAggregatedAmountListReturnUsingPredicate(self,
sequence=None, **kw): sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 4) self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 4)
def stepCheckUpdateAggregatedAmountListReturnAfterChangePredicate(self, def stepCheckUpdateAggregatedAmountListReturnAfterChangePredicate(self,
sequence=None, **kw): sequence=None, **kw):
...@@ -544,15 +540,13 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -544,15 +540,13 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
# insurance model_line will not be applied but old age insurance yes. # insurance model_line will not be applied but old age insurance yes.
# So two movements will be deleted (from sickness insurance) and two should # So two movements will be deleted (from sickness insurance) and two should
# be added (from old age insurance) # be added (from old age insurance)
model = sequence.get('model')
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 2, 2) self.checkUpdateAggregatedAmountListReturn(paysheet, 2, 2)
def stepCheckUpdateAggregatedAmountListReturnAfterRemoveLine(self, def stepCheckUpdateAggregatedAmountListReturnAfterRemoveLine(self,
sequence=None, **kw): sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 2, 0) self.checkUpdateAggregatedAmountListReturn(paysheet, 2, 0)
def stepPaysheetApplyTransformation(self, sequence=None, **kw): def stepPaysheetApplyTransformation(self, sequence=None, **kw):
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
...@@ -836,8 +830,7 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -836,8 +830,7 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
def stepCheckUpdateAggregatedAmountListReturnNothing(self, sequence=None, **kw): def stepCheckUpdateAggregatedAmountListReturnNothing(self, sequence=None, **kw):
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
model = sequence.get('model') movement_dict = paysheet.updateAggregatedAmountList()
movement_dict = model.updateAggregatedAmountList(context=paysheet)
movement_to_delete = movement_dict['movement_to_delete_list'] movement_to_delete = movement_dict['movement_to_delete_list']
movement_to_add = movement_dict['movement_to_add_list'] movement_to_add = movement_dict['movement_to_add_list']
self.assertEquals(len(movement_to_delete), 0) self.assertEquals(len(movement_to_delete), 0)
...@@ -1207,9 +1200,8 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin): ...@@ -1207,9 +1200,8 @@ class TestPayrollMixin(ERP5ReportTestCase, TestTradeModelLineMixin):
def stepCheckUpdateAggregatedAmountListReturnWithModelLineOnPaysheet(self, def stepCheckUpdateAggregatedAmountListReturnWithModelLineOnPaysheet(self,
sequence=None, **kw): sequence=None, **kw):
model = sequence.get('model')
paysheet = sequence.get('paysheet') paysheet = sequence.get('paysheet')
self.checkUpdateAggregatedAmountListReturn(model, paysheet, 0, 4) self.checkUpdateAggregatedAmountListReturn(paysheet, 0, 4)
def stepCheckPaysheetLineAreCreatedWithModelLineOnPaysheet(self, def stepCheckPaysheetLineAreCreatedWithModelLineOnPaysheet(self,
sequence=None, **kw): sequence=None, **kw):
......
This diff is collapsed.
...@@ -51,7 +51,8 @@ class TradeModelRule(Rule): ...@@ -51,7 +51,8 @@ class TradeModelRule(Rule):
"""Generates list of movements (as dicts), and let parent class to decide """Generates list of movements (as dicts), and let parent class to decide
which is to add, modify or delete""" which is to add, modify or delete"""
movement_list = [] movement_list = []
trade_condition = applied_rule.getTradeConditionValue() trade_condition = applied_rule._getExplanationSpecialiseValue(
('Purchase Trade Condition', 'Sale Trade Condition'))
business_process = applied_rule.getBusinessProcessValue() business_process = applied_rule.getBusinessProcessValue()
if trade_condition is None or business_process is None: 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