Commit f01c030e authored by Georgios Dagkakis's avatar Georgios Dagkakis

SimulationTool: try more flexible definition of join_column for selection_domain

Changes also in erp5_core:
- Resource_zGetInventoryList and Resource_zGetMovementHistoryList
to provide support for receiving the join_column as arg
- Add a generic Base_getJoinColumnForSelectionDomain mapping

Finally, in add two tests to testInventoryAPI to check queries
with selection_domain for getInventoryList and getMovementHistoryList
parent 0eed2ec0
...@@ -59,6 +59,7 @@ from warnings import warn ...@@ -59,6 +59,7 @@ from warnings import warn
from cPickle import loads, dumps from cPickle import loads, dumps
from copy import deepcopy from copy import deepcopy
from sys import exc_info from sys import exc_info
from Products.ERP5Form.Selection import DomainSelection
MYSQL_MIN_DATETIME_RESOLUTION = 1/86400. MYSQL_MIN_DATETIME_RESOLUTION = 1/86400.
...@@ -1187,6 +1188,12 @@ class SimulationTool(BaseTool): ...@@ -1187,6 +1188,12 @@ class SimulationTool(BaseTool):
new_group_by_dict['group_by_resource'] = 1 new_group_by_dict['group_by_resource'] = 1
return new_group_by_dict return new_group_by_dict
security.declarePrivate('_getJoinColumnForSelectionDomain')
def _getJoinColumnForSelectionDomain(self, selection_domain_dict):
if not selection_domain_dict:
return
return self.getPortalObject().Base_getJoinColumnForSelectionDomain(selection_domain_dict.keys()[0])
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getInventoryList') 'getInventoryList')
def getInventoryList(self, src__=0, optimisation__=True, def getInventoryList(self, src__=0, optimisation__=True,
...@@ -1268,6 +1275,8 @@ class SimulationTool(BaseTool): ...@@ -1268,6 +1275,8 @@ class SimulationTool(BaseTool):
sql_source_list = [] sql_source_list = []
# If no group at all, give a default sort group by # If no group at all, give a default sort group by
kw.update(self._getDefaultGroupByParameters(**kw)) kw.update(self._getDefaultGroupByParameters(**kw))
if isinstance(selection_domain, DomainSelection):
selection_domain = selection_domain.asDomainDict()
base_inventory_kw = { base_inventory_kw = {
'stock_table_id': default_stock_table, 'stock_table_id': default_stock_table,
'src__': src__, 'src__': src__,
...@@ -1276,6 +1285,7 @@ class SimulationTool(BaseTool): ...@@ -1276,6 +1285,7 @@ class SimulationTool(BaseTool):
'omit_simulation': omit_simulation, 'omit_simulation': omit_simulation,
'only_accountable': only_accountable, 'only_accountable': only_accountable,
'selection_domain': selection_domain, 'selection_domain': selection_domain,
'join_column': self._getJoinColumnForSelectionDomain(selection_domain),
'selection_report': selection_report, 'selection_report': selection_report,
'precision': precision, 'precision': precision,
'inventory_list': inventory_list, 'inventory_list': inventory_list,
...@@ -1972,6 +1982,8 @@ class SimulationTool(BaseTool): ...@@ -1972,6 +1982,8 @@ class SimulationTool(BaseTool):
for x in extra_column_set if not x.endswith('__score__')) for x in extra_column_set if not x.endswith('__score__'))
sql_kw = self._generateSQLKeywordDict(**kw) sql_kw = self._generateSQLKeywordDict(**kw)
if isinstance(selection_domain, DomainSelection):
selection_domain = selection_domain.asDomainDict()
return self.Resource_zGetMovementHistoryList( return self.Resource_zGetMovementHistoryList(
src__=src__, ignore_variation=ignore_variation, src__=src__, ignore_variation=ignore_variation,
...@@ -1982,6 +1994,7 @@ class SimulationTool(BaseTool): ...@@ -1982,6 +1994,7 @@ class SimulationTool(BaseTool):
omit_asset_increase=omit_asset_increase, omit_asset_increase=omit_asset_increase,
omit_asset_decrease=omit_asset_decrease, omit_asset_decrease=omit_asset_decrease,
selection_domain=selection_domain, selection_domain=selection_domain,
join_column=self._getJoinColumnForSelectionDomain(selection_domain),
selection_report=selection_report, selection_report=selection_report,
initial_running_total_quantity= initial_running_total_quantity=
initial_running_total_quantity, initial_running_total_quantity,
......
'''
This script is called by Simulation Tool in order to obtain the
join_column for a getInventoryList or getMovementHistoryList query.
In the past this supported only node_uid, so keep this as default value
for backwards compatibility. Script can be customized for projects.
XXX, Still it is not flexible, i.e. it does not support the case of e.g.
have a domain on site category sometime used as node_category
and sometimes as mirror_node_category or section_category.
'''
return {
'ledger': 'ledger_uid',
}.get(selection_key, 'node_uid')
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</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>_params</string> </key>
<value> <string>selection_key</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getJoinColumnForSelectionDomain</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -103,7 +103,8 @@ WHERE ...@@ -103,7 +103,8 @@ WHERE
AND <dtml-var stock_table_id>.is_accountable AND <dtml-var stock_table_id>.is_accountable
</dtml-if> </dtml-if>
<dtml-if selection_domain> <dtml-if selection_domain>
AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_domain, category_table_alias='domain_category', join_table=stock_table_id, join_column='node_uid')"> AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_domain, category_table_alias='domain_category', join_table=stock_table_id, join_column=join_column)">
</dtml-if> </dtml-if>
<dtml-if selection_report> <dtml-if selection_report>
AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_report, category_table_alias='report_category', strict_membership=1)"> AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_report, category_table_alias='report_category', strict_membership=1)">
......
...@@ -22,29 +22,30 @@ ...@@ -22,29 +22,30 @@
</item> </item>
<item> <item>
<key> <string>arguments_src</string> </key> <key> <string>arguments_src</string> </key>
<value> <string>from_table_list:list\r\n <value> <string>from_table_list:list\n
from_expression\r\n from_expression\n
where_expression\r\n where_expression\n
order_by_expression\r\n order_by_expression\n
group_by_expression\r\n group_by_expression\n
selection_domain\r\n selection_domain\n
select_expression\r\n join_column\n
selection_report\r\n select_expression\n
ignore_variation\r\n selection_report\n
standardize\r\n ignore_variation\n
omit_simulation\r\n standardize\n
only_accountable\r\n omit_simulation\n
omit_input\r\n only_accountable\n
omit_output\r\n omit_input\n
input_simulation_state:list\r\n omit_output\n
output_simulation_state:list\r\n input_simulation_state:list\n
precision\r\n output_simulation_state:list\n
inventory_list\r\n precision\n
statistic\r\n inventory_list\n
convert_quantity_result\r\n statistic\n
quantity_unit_uid\r\n convert_quantity_result\n
stock_table_id=stock\r\n quantity_unit_uid\n
transformed_uid\r\n stock_table_id=stock\n
transformed_uid\n
transformed_variation_text</string> </value> transformed_variation_text</string> </value>
</item> </item>
<item> <item>
......
...@@ -133,7 +133,7 @@ WHERE ...@@ -133,7 +133,7 @@ WHERE
</dtml-if> </dtml-if>
<dtml-if selection_domain> <dtml-if selection_domain>
AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_domain, category_table_alias='domain_category', join_table='stock', join_column='node_uid')"> AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_domain, category_table_alias='domain_category', join_table='stock', join_column=join_column)">
</dtml-if> </dtml-if>
<dtml-if selection_report> <dtml-if selection_report>
AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_report, category_table_alias='report_category', strict_membership=1)"> AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_report, category_table_alias='report_category', strict_membership=1)">
......
...@@ -417,27 +417,28 @@ ...@@ -417,27 +417,28 @@
</item> </item>
<item> <item>
<key> <string>arguments_src</string> </key> <key> <string>arguments_src</string> </key>
<value> <string>from_expression\r\n <value> <string>from_expression\n
from_table_list:list\r\n from_table_list:list\n
select_expression\r\n select_expression\n
where_expression\r\n where_expression\n
order_by_expression\r\n order_by_expression\n
group_by_expression\r\n group_by_expression\n
limit_expression\r\n limit_expression\n
selection_domain\r\n selection_domain\n
selection_report\r\n join_column\n
ignore_variation\r\n selection_report\n
standardize\r\n ignore_variation\n
omit_simulation\r\n standardize\n
only_accountable\r\n omit_simulation\n
omit_input\r\n only_accountable\n
omit_output\r\n omit_input\n
omit_asset_increase\r\n omit_output\n
omit_asset_decrease\r\n omit_asset_increase\n
initial_running_total_quantity\r\n omit_asset_decrease\n
initial_running_total_price\r\n initial_running_total_quantity\n
input_simulation_state:list\r\n initial_running_total_price\n
output_simulation_state:list\r\n input_simulation_state:list\n
output_simulation_state:list\n
precision</string> </value> precision</string> </value>
</item> </item>
<item> <item>
......
...@@ -188,7 +188,7 @@ class InventoryAPITestCase(ERP5TypeTestCase): ...@@ -188,7 +188,7 @@ class InventoryAPITestCase(ERP5TypeTestCase):
'erp5_dummy_movement', 'erp5_simulation', 'erp5_dummy_movement', 'erp5_simulation',
'erp5_trade', 'erp5_apparel', 'erp5_project', 'erp5_trade', 'erp5_apparel', 'erp5_project',
'erp5_configurator_standard_trade_template', 'erp5_configurator_standard_trade_template',
'erp5_simulation_test', 'erp5_stock_cache') 'erp5_simulation_test', 'erp5_stock_cache', )
# TODO: move this to a base class {{{ # TODO: move this to a base class {{{
@reindex @reindex
...@@ -1571,6 +1571,49 @@ class TestInventoryList(InventoryAPITestCase): ...@@ -1571,6 +1571,49 @@ class TestInventoryList(InventoryAPITestCase):
self.assertTrue(result is not None) self.assertTrue(result is not None)
self.assertEqual(internal_data[cur]['after']['total_price'], round(result)) self.assertEqual(internal_data[cur]['after']['total_price'], round(result))
def testGetInventoryListWithSelectionDomain(self):
'''
check getInventoryList queries with selection_domain
'''
getInventoryList = self.getSimulationTool().getInventoryList
ledger_accounting_category = self.portal.portal_categories.ledger.accounting
self.node.setGroup('level1')
movement1 = self._makeMovement(
ledger_value=ledger_accounting_category.general,
destination_value=None,
quantity=2,
)
movement2 = self._makeMovement(
ledger_value=ledger_accounting_category.detailed,
destination_value=None,
source_value=self.node,
quantity=3,
)
# query without selection. Result should contain both movements
result_no_selection = getInventoryList()
self.assertEquals(len(result_no_selection), 2)
self.assertEquals(
sum([x.total_quantity for x in result_no_selection]),
-5.0
)
# query using ledger in the selection_domain (so ledger_uid).
# Check only the corresponding movement is found
result_ledger_accounting_general = getInventoryList(
selection_domain={'ledger': ('portal_categories', 'ledger/accounting/general')})
self.assertEquals(len(result_ledger_accounting_general), 1)
self.assertEquals(result_ledger_accounting_general[0].total_quantity, -2.0)
result_ledger_accounting_detailed = getInventoryList(
selection_domain={'ledger': ('portal_categories', 'ledger/accounting/detailed')})
self.assertEquals(len(result_ledger_accounting_detailed), 1)
self.assertEquals(result_ledger_accounting_detailed[0].total_quantity, -3.0)
# query using group in the selection_domain (so node_uid).
# Check only the corresponding movement is found
result_group1 = getInventoryList(
selection_domain={'group': ('portal_categories', 'group/level1')})
self.assertEquals(len(result_group1), 1)
self.assertEquals(result_group1[0].total_quantity, -3.0)
class TestMovementHistoryList(InventoryAPITestCase): class TestMovementHistoryList(InventoryAPITestCase):
"""Tests Movement history list methods. """Tests Movement history list methods.
...@@ -2471,6 +2514,50 @@ class TestMovementHistoryList(InventoryAPITestCase): ...@@ -2471,6 +2514,50 @@ class TestMovementHistoryList(InventoryAPITestCase):
self.assertEqual(7, mvt_history_list[1].total_price) self.assertEqual(7, mvt_history_list[1].total_price)
self.assertEqual(12, mvt_history_list[1].running_total_price) self.assertEqual(12, mvt_history_list[1].running_total_price)
def testGetMovementHistoryListWithSelectionDomain(self):
'''
check getMovementHistoryList queries with selection_domain
'''
getMovementHistoryList = self.getSimulationTool().getMovementHistoryList
ledger_accounting_category = self.portal.portal_categories.ledger.accounting
self.node.setGroup('level1')
movement1 = self._makeMovement(
ledger_value=ledger_accounting_category.general,
destination_value=None,
quantity=2,
)
movement2 = self._makeMovement(
ledger_value=ledger_accounting_category.detailed,
destination_value=None,
source_value=self.node,
quantity=3,
)
# query without selection. Result should contain both movements
result_no_selection = getMovementHistoryList()
self.assertEquals(len(result_no_selection), 2)
self.assertEquals(
sum([x.total_quantity for x in result_no_selection]),
-5.0
)
# query using ledger in the selection_domain (so ledger_uid).
# Check only the corresponding movement is found
result_ledger_accounting_general = getMovementHistoryList(
selection_domain={'ledger': ('portal_categories', 'ledger/accounting/general')})
self.assertEquals(len(result_ledger_accounting_general), 1)
self.assertEquals(result_ledger_accounting_general[0].total_quantity, -2.0)
result_ledger_accounting_detailed = getMovementHistoryList(
selection_domain={'ledger': ('portal_categories', 'ledger/accounting/detailed')})
self.assertEquals(len(result_ledger_accounting_detailed), 1)
self.assertEquals(result_ledger_accounting_detailed[0].total_quantity, -3.0)
# query using group in the selection_domain (so node_uid).
# Check only the corresponding movement is found
result_group1 = getMovementHistoryList(
selection_domain={'group': ('portal_categories', 'group/level1')})
self.assertEquals(len(result_group1), 1)
self.assertEquals(result_group1[0].total_quantity, -3.0)
class TestNextNegativeInventoryDate(InventoryAPITestCase): class TestNextNegativeInventoryDate(InventoryAPITestCase):
"""Tests getInventory methods. """Tests getInventory methods.
......
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