Commit 476ec3f7 authored by Jérome Perrin's avatar Jérome Perrin

- use selected uids in getInventoryList as cell keys, this makes the "inventory

  list" way of calculating consumption working properly with summary cells
- cache cell keys lookups
- support movement_strict_membership inventory axis
- add tests



git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@37282 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent af636246
...@@ -116,14 +116,15 @@ class BudgetLine(Predicate, XMLMatrix, Variated): ...@@ -116,14 +116,15 @@ class BudgetLine(Predicate, XMLMatrix, Variated):
query_dict.setdefault('ignore_group_by', True) query_dict.setdefault('ignore_group_by', True)
sign = self.BudgetLine_getConsumptionSign() sign = self.BudgetLine_getConsumptionSign()
cell_key_cache = dict()
budget_dict = dict() budget_dict = dict()
for brain in self.getPortalObject().portal_simulation\ for brain in self.getPortalObject().portal_simulation\
.getCurrentInventoryList(**query_dict): .getCurrentInventoryList(**query_dict):
cell_key = budget_model._getCellKeyFromInventoryListBrain(brain, self,
cell_key_cache=cell_key_cache)
# XXX total_quantity or total_price ?? # XXX total_quantity or total_price ??
previous_value = budget_dict.get( previous_value = budget_dict.get(cell_key, 0)
budget_model._getCellKeyFromInventoryListBrain(brain, self), 0) budget_dict[cell_key] = previous_value + brain.total_price * sign
budget_dict[budget_model._getCellKeyFromInventoryListBrain(brain, self)] = \
previous_value + brain.total_price * sign
return budget_dict return budget_dict
...@@ -99,10 +99,16 @@ class BudgetModel(Predicate): ...@@ -99,10 +99,16 @@ class BudgetModel(Predicate):
for budget_variation in sorted(self.contentValues( for budget_variation in sorted(self.contentValues(
portal_type=self.getPortalBudgetVariationTypeList()), portal_type=self.getPortalBudgetVariationTypeList()),
key=lambda x:x.getIntIndex()): key=lambda x:x.getIntIndex()):
variation_query_dict = budget_variation.getInventoryListQueryDict(budget_line) variation_query_dict = budget_variation.getInventoryListQueryDict(
# Merge group_by argument. All other arguments should not conflict budget_line)
# Merge group_by and select_list arguments.
# Other arguments should not conflict
if 'group_by' in query_dict and 'group_by' in variation_query_dict: if 'group_by' in query_dict and 'group_by' in variation_query_dict:
variation_query_dict['group_by'].extend(query_dict['group_by']) variation_query_dict['group_by'].extend(query_dict['group_by'])
if 'select_list' in query_dict \
and 'select_list' in variation_query_dict:
variation_query_dict['select_list'].extend(
query_dict['select_list'])
query_dict.update(variation_query_dict) query_dict.update(variation_query_dict)
...@@ -114,7 +120,8 @@ class BudgetModel(Predicate): ...@@ -114,7 +120,8 @@ class BudgetModel(Predicate):
query_dict.setdefault('at_date', start_date_range_max.latestTime()) query_dict.setdefault('at_date', start_date_range_max.latestTime())
return query_dict return query_dict
def _getCellKeyFromInventoryListBrain(self, brain, budget_line): def _getCellKeyFromInventoryListBrain(self, brain, budget_line,
cell_key_cache=None):
"""Compute the cell key from an inventory brain, the cell key can be used """Compute the cell key from an inventory brain, the cell key can be used
to retrieve the budget cell in the corresponding budget line. to retrieve the budget cell in the corresponding budget line.
""" """
...@@ -122,8 +129,8 @@ class BudgetModel(Predicate): ...@@ -122,8 +129,8 @@ class BudgetModel(Predicate):
for budget_variation in sorted(self.contentValues( for budget_variation in sorted(self.contentValues(
portal_type=self.getPortalBudgetVariationTypeList()), portal_type=self.getPortalBudgetVariationTypeList()),
key=lambda x:x.getIntIndex()): key=lambda x:x.getIntIndex()):
key = budget_variation._getCellKeyFromInventoryListBrain(brain, key = budget_variation._getCellKeyFromInventoryListBrain(
budget_line) brain, budget_line, cell_key_cache=cell_key_cache)
if key: if key:
cell_key += (key,) cell_key += (key,)
return cell_key return cell_key
......
...@@ -96,10 +96,12 @@ class BudgetVariation(Predicate): ...@@ -96,10 +96,12 @@ class BudgetVariation(Predicate):
""" """
return {} return {}
def _getCellKeyFromInventoryListBrain(self, brain, budget_line): def _getCellKeyFromInventoryListBrain(self, brain, budget_line,
cell_key_cache=None):
"""Compute the cell key from an inventory brain. """Compute the cell key from an inventory brain.
The cell key can be used to retrieve the budget cell in the corresponding The cell key can be used to retrieve the budget cell in the corresponding
budget line using budget_line.getCell budget line using budget_line.getCell
A dictionnary can be passed as "cell_key_cache" to cache catalog lookups
""" """
if not self.isMemberOf('budget_variation/budget_cell'): if not self.isMemberOf('budget_variation/budget_cell'):
return None return None
...@@ -110,55 +112,30 @@ class BudgetVariation(Predicate): ...@@ -110,55 +112,30 @@ class BudgetVariation(Predicate):
base_category = self.getProperty('variation_base_category') base_category = self.getProperty('variation_base_category')
if not base_category: if not base_category:
return None return None
movement = brain.getObject() getObject = self.getPortalObject().portal_catalog.getObject
# axis 'movement' is simply a category membership on movements def getUrlFromUidNoCache(uid):
if axis == 'movement': relative_url = getObject(uid).getRelativeUrl()
return movement.getDefaultAcquiredCategoryMembership(base_category, if relative_url.startswith('%s/' % base_category):
base=True) return relative_url
return '%s/%s' % (base_category, relative_url)
# is it a source brain or destination brain ?
is_source_brain = True if cell_key_cache is not None:
if (brain.node_uid != brain.mirror_node_uid): def getUrlFromUidWithCache(uid):
is_source_brain = (brain.node_uid == movement.getSourceUid()) try:
elif (brain.section_uid != brain.mirror_section_uid): return cell_key_cache[uid]
is_source_brain = (brain.section_uid == movement.getSourceSectionUid()) except KeyError:
elif brain.total_quantity: relative_url = getUrlFromUidNoCache(uid)
is_source_brain = (brain.total_quantity == movement.getQuantity()) cell_key_cache[uid] = relative_url
return relative_url
getUrlFromUid = getUrlFromUidWithCache
else: else:
raise NotImplementedError('Could not guess brain side') getUrlFromUid = getUrlFromUidNoCache
if axis.endswith('_category') or\
axis.endswith('_category_strict_membership'):
# if the axis is category, we get the node and then returns the category
# from that node
if axis.endswith('_category'):
axis = axis[:-len('_category')]
if axis.endswith('_category_strict_membership'):
axis = axis[:-len('_category_strict_membership')]
if is_source_brain:
if axis == 'node':
node = movement.getSourceValue()
else:
node = movement.getProperty('source_%s_value' % axis)
else:
if axis == 'node':
node = movement.getDestinationValue()
else:
node = movement.getProperty('destination_%s_value' % axis)
if node is not None:
return node.getDefaultAcquiredCategoryMembership(base_category,
base=True)
return None
# otherwise we just return the node if axis == 'movement':
if is_source_brain: return getUrlFromUid(getattr(brain, 'default_%s_uid' % base_category))
if axis == 'node': elif axis == 'movement_strict_membership':
return '%s/%s' % (base_category, movement.getSource()) return getUrlFromUid(getattr(brain,
return '%s/%s' % (base_category, 'default_strict_%s_uid' % base_category))
movement.getProperty('source_%s' % axis)) return getUrlFromUid(getattr(brain, '%s_uid' % axis))
if axis == 'node':
return '%s/%s' % (base_category, movement.getDestination())
return '%s/%s' % (base_category,
movement.getProperty('destination_%s' % axis))
...@@ -95,6 +95,8 @@ class CategoryBudgetVariation(BudgetVariation): ...@@ -95,6 +95,8 @@ class CategoryBudgetVariation(BudgetVariation):
# Different possible inventory axis here # Different possible inventory axis here
if axis == 'movement': if axis == 'movement':
return {'default_%s_uid' % base_category: category_uid} return {'default_%s_uid' % base_category: category_uid}
if axis == 'movement_strict_membership':
return {'default_strict_%s_uid' % base_category: category_uid}
if axis in ('node', 'section', 'payment', 'function', 'project', if axis in ('node', 'section', 'payment', 'function', 'project',
'mirror_section', 'mirror_node' ): 'mirror_section', 'mirror_node' ):
return {'%s_uid' % axis: category_uid} return {'%s_uid' % axis: category_uid}
...@@ -117,8 +119,13 @@ class CategoryBudgetVariation(BudgetVariation): ...@@ -117,8 +119,13 @@ class CategoryBudgetVariation(BudgetVariation):
query_dict = dict() query_dict = dict()
if axis == 'movement': if axis == 'movement':
axis = 'default_%s_uid' % base_category
query_dict['group_by'] = [axis]
query_dict['select_list'] = [axis]
elif axis == 'movement_strict_membership':
axis = 'default_strict_%s_uid' % base_category axis = 'default_strict_%s_uid' % base_category
query_dict['group_by'] = [axis] query_dict['group_by'] = [axis]
query_dict['select_list'] = [axis]
else: else:
query_dict['group_by_%s' % axis] = True query_dict['group_by_%s' % axis] = True
if axis in ('node', 'section', 'payment', 'function', 'project', if axis in ('node', 'section', 'payment', 'function', 'project',
...@@ -126,7 +133,7 @@ class CategoryBudgetVariation(BudgetVariation): ...@@ -126,7 +133,7 @@ class CategoryBudgetVariation(BudgetVariation):
axis = '%s_uid' % axis axis = '%s_uid' % axis
for category in context.getVariationCategoryList( for category in context.getVariationCategoryList(
base_category_list=(base_category,)): base_category_list=(base_category,)):
if axis.endswith('_uid'): if axis.endswith('_uid'):
category = self.getPortalObject().portal_categories\ category = self.getPortalObject().portal_categories\
.getCategoryUid(category) .getCategoryUid(category)
......
...@@ -147,8 +147,11 @@ class NodeBudgetVariation(BudgetVariation): ...@@ -147,8 +147,11 @@ class NodeBudgetVariation(BudgetVariation):
if criterion_base_category == base_category: if criterion_base_category == base_category:
if axis == 'movement': if axis == 'movement':
axis = 'default_%s' % base_category axis = 'default_%s' % base_category
# TODO: This is not correct if axis is a category (such as if axis == 'movement_strict_membership':
# section_category) axis = 'default_strict_%s' % base_category
# TODO: This is not correct if axis is a category such as
# section_category, because getInventoryList for now does not support
# parameters such as section_category_uid
axis = '%s_uid' % axis axis = '%s_uid' % axis
if node_url == budget_line.getRelativeUrl(): if node_url == budget_line.getRelativeUrl():
# This is the "All Other" virtual node # This is the "All Other" virtual node
...@@ -181,7 +184,12 @@ class NodeBudgetVariation(BudgetVariation): ...@@ -181,7 +184,12 @@ class NodeBudgetVariation(BudgetVariation):
query_dict = dict() query_dict = dict()
if axis == 'movement': if axis == 'movement':
axis = 'default_%s_uid' % base_category axis = 'default_%s_uid' % base_category
query_dict['select_list'] = [axis]
if axis == 'movement_strict_membership':
axis = 'default_strict_%s_uid' % base_category
query_dict['select_list'] = [axis]
query_dict['group_by_%s' % axis] = True query_dict['group_by_%s' % axis] = True
# TODO: This is not correct if axis is a category (such as # TODO: This is not correct if axis is a category (such as
# section_category) # section_category)
axis = '%s_uid' % axis axis = '%s_uid' % axis
...@@ -191,17 +199,19 @@ class NodeBudgetVariation(BudgetVariation): ...@@ -191,17 +199,19 @@ class NodeBudgetVariation(BudgetVariation):
return query_dict return query_dict
for node_url in context.getVariationCategoryList( for node_url in context.getVariationCategoryList(
base_category_list=(base_category,)): base_category_list=(base_category,)):
query_dict.setdefault(axis, []).append( query_dict.setdefault(axis, []).append(
portal_categories.getCategoryValue(node_url, portal_categories.getCategoryValue(node_url,
base_category=base_category).getUid()) base_category=base_category).getUid())
return query_dict return query_dict
def _getCellKeyFromInventoryListBrain(self, brain, budget_line): def _getCellKeyFromInventoryListBrain(self, brain, budget_line,
"""Compute key from inventory brain, with support for "all others" virtual node. cell_key_cache=None):
"""Compute key from inventory brain, with support for "all others" virtual
node.
""" """
key = BudgetVariation._getCellKeyFromInventoryListBrain( key = BudgetVariation._getCellKeyFromInventoryListBrain(
self, brain, budget_line) self, brain, budget_line, cell_key_cache=cell_key_cache)
if self.getProperty('include_virtual_other_node'): if self.getProperty('include_virtual_other_node'):
if key not in [x[1] for x in if key not in [x[1] for x in
self.getBudgetVariationRangeCategoryList(budget_line)]: self.getBudgetVariationRangeCategoryList(budget_line)]:
......
This diff is collapsed.
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