Commit 5a116387 authored by Jérome Perrin's avatar Jérome Perrin

trade: new "Replace" mode for Trade Model Path scripts

Trade model path scripts does not allow to unset a category on an input
movement. To allow this while keeping backward compatibility with
existing scripts, introduce new boolean properties "{source,destination}
replace categories" that if set to True will make the trade model path
consider only dynamic categories returned by the script and will not
copy categories that might be set on the trade model path itself or on
the movement.
parent 458ae10c
...@@ -159,23 +159,35 @@ class TradeModelPath(Path): ...@@ -159,23 +159,35 @@ class TradeModelPath(Path):
# XXX-JPS UNkonwn ? # XXX-JPS UNkonwn ?
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getArrowCategoryDict') 'getArrowCategoryDict')
def getArrowCategoryDict(self, context=None, **kw): # XXX-JPS do we need it in API ? def getArrowCategoryDict(self, context=None, **kw): # XXX-JPS do we need it in API ?
# This method returns the dict like # This method returns the dict like
# {base_category_id:[category value url list], ...} # {base_category_id:[category value url list], ...}
# for all Arrow base categories. # for all Arrow base categories.
# Each category values are self's category values (if exist) or # Each category values are self's category values (if exist) or
# dynamically computed values (if not exist). # dynamically computed values (if not exist), but on trade model path
# we can also configure if we want the script to define **all** categories,
# which means that if script does not return some categories they are not
# set on the resulting movement, even if they were set on the input movement.
result = {} result = {}
dynamic_category_list = self._getDynamicCategoryList(context) dynamic_category_list = self._getDynamicCategoryList(context)
for base_category in self.getSourceArrowBaseCategoryList() +\ for base_category_list, script_replace_category in (
self.getDestinationArrowBaseCategoryList(): (self.getSourceArrowBaseCategoryList(),
category_url_list = self._getAcquiredCategoryMembershipList( self.getSourceMethodReplaceCategory()),
base_category, **kw) (self.getDestinationArrowBaseCategoryList(),
if len(category_url_list) == 0 and len(dynamic_category_list) > 0: self.getDestinationMethodReplaceCategory()),
category_url_list = self._filterCategoryList(dynamic_category_list, ):
base_category, **kw) for base_category in base_category_list:
if len(category_url_list) > 0: if script_replace_category and context is not None:
result[base_category] = category_url_list result[base_category] = self._filterCategoryList(
dynamic_category_list, base_category, **kw)
else:
category_url_list = super(TradeModelPath, self)._getAcquiredCategoryMembershipList(
base_category, **kw)
if context is not None and not category_url_list:
category_url_list = self._filterCategoryList(
dynamic_category_list, base_category, **kw)
if category_url_list:
result[base_category] = category_url_list
return result return result
def _filterCategoryList( def _filterCategoryList(
......
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
<value> <value>
<list> <list>
<string>my_source_method_id</string> <string>my_source_method_id</string>
<string>my_source_method_replace_category</string>
<string>my_source_section_title</string> <string>my_source_section_title</string>
<string>my_source_title</string> <string>my_source_title</string>
<string>my_source_decision_title</string> <string>my_source_decision_title</string>
...@@ -91,6 +92,7 @@ ...@@ -91,6 +92,7 @@
<value> <value>
<list> <list>
<string>my_destination_method_id</string> <string>my_destination_method_id</string>
<string>my_destination_method_replace_category</string>
<string>my_destination_section_title</string> <string>my_destination_section_title</string>
<string>my_destination_title</string> <string>my_destination_title</string>
<string>my_destination_decision_title</string> <string>my_destination_decision_title</string>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="CheckBoxField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_destination_method_replace_category</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>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>This field is mandatory.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Destination Method Replace Categories</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="CheckBoxField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_source_method_replace_category</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>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>This field is mandatory.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Source Method Replace Categories</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/boolean</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>If set to True, only categories returned by destination method will be set on the resulting movement. If False, categories from the input movements will also be copied.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>destination_method_replace_category_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>mode</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/boolean</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>If set to True, only categories returned by source method will be set on the resulting movement. If False, categories from the input movements will also be copied.</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>source_method_replace_category_property</string> </value>
</item>
<item>
<key> <string>mode</string> </key>
<value> <string>w</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
import unittest import unittest
from Products.ERP5Type.tests.utils import createZODBPythonScript
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from DateTime import DateTime from DateTime import DateTime
from Products.ERP5Type.tests.utils import reindex from Products.ERP5Type.tests.utils import reindex
...@@ -448,6 +449,29 @@ class TestBPMImplementation(TestBPMDummyDeliveryMovementMixin): ...@@ -448,6 +449,29 @@ class TestBPMImplementation(TestBPMDummyDeliveryMovementMixin):
self.assertEqual(None, business_path.getSourceValue()) self.assertEqual(None, business_path.getSourceValue())
self.assertFalse(business_path.getArrowCategoryDict(context=context_movement).has_key('source')) self.assertFalse(business_path.getArrowCategoryDict(context=context_movement).has_key('source'))
def test_BusinessPathDynamicCategoryAccessProviderReplaceCategory(self):
business_path = self.createTradeModelPath()
createZODBPythonScript(
self.portal.portal_skins.custom,
self.id(),
'movement',
'return []',
)
business_path.setSourceMethodId(self.id())
movement_node = self.portal.organisation_module.newContent(
portal_type='Organisation')
business_path.setSourceValue(movement_node)
context_movement = self.createMovement()
self.assertEqual(
[movement_node.getRelativeUrl()],
business_path.getArrowCategoryDict(
context=context_movement)['source'])
# in replace mode, categories not returned by the scripts are returned as []
# so that it replaces existing values.
business_path.setSourceMethodReplaceCategory(True)
self.assertEqual([], business_path.getArrowCategoryDict(context=context_movement)['source'])
def test_BusinessState_getRemainingTradePhaseList(self): def test_BusinessState_getRemainingTradePhaseList(self):
""" """
This test case is described for what trade_phase is remaining after the This test case is described for what trade_phase is remaining after the
......
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