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):
query_dict.setdefault('ignore_group_by', True)
sign = self.BudgetLine_getConsumptionSign()
cell_key_cache = dict()
budget_dict = dict()
for brain in self.getPortalObject().portal_simulation\
.getCurrentInventoryList(**query_dict):
cell_key = budget_model._getCellKeyFromInventoryListBrain(brain, self,
cell_key_cache=cell_key_cache)
# XXX total_quantity or total_price ??
previous_value = budget_dict.get(
budget_model._getCellKeyFromInventoryListBrain(brain, self), 0)
budget_dict[budget_model._getCellKeyFromInventoryListBrain(brain, self)] = \
previous_value + brain.total_price * sign
previous_value = budget_dict.get(cell_key, 0)
budget_dict[cell_key] = previous_value + brain.total_price * sign
return budget_dict
......@@ -99,10 +99,16 @@ class BudgetModel(Predicate):
for budget_variation in sorted(self.contentValues(
portal_type=self.getPortalBudgetVariationTypeList()),
key=lambda x:x.getIntIndex()):
variation_query_dict = budget_variation.getInventoryListQueryDict(budget_line)
# Merge group_by argument. All other arguments should not conflict
variation_query_dict = budget_variation.getInventoryListQueryDict(
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:
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)
......@@ -114,7 +120,8 @@ class BudgetModel(Predicate):
query_dict.setdefault('at_date', start_date_range_max.latestTime())
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
to retrieve the budget cell in the corresponding budget line.
"""
......@@ -122,8 +129,8 @@ class BudgetModel(Predicate):
for budget_variation in sorted(self.contentValues(
portal_type=self.getPortalBudgetVariationTypeList()),
key=lambda x:x.getIntIndex()):
key = budget_variation._getCellKeyFromInventoryListBrain(brain,
budget_line)
key = budget_variation._getCellKeyFromInventoryListBrain(
brain, budget_line, cell_key_cache=cell_key_cache)
if key:
cell_key += (key,)
return cell_key
......
......@@ -96,10 +96,12 @@ class BudgetVariation(Predicate):
"""
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.
The cell key can be used to retrieve the budget cell in the corresponding
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'):
return None
......@@ -110,55 +112,30 @@ class BudgetVariation(Predicate):
base_category = self.getProperty('variation_base_category')
if not base_category:
return None
movement = brain.getObject()
# axis 'movement' is simply a category membership on movements
if axis == 'movement':
return movement.getDefaultAcquiredCategoryMembership(base_category,
base=True)
# is it a source brain or destination brain ?
is_source_brain = True
if (brain.node_uid != brain.mirror_node_uid):
is_source_brain = (brain.node_uid == movement.getSourceUid())
elif (brain.section_uid != brain.mirror_section_uid):
is_source_brain = (brain.section_uid == movement.getSourceSectionUid())
elif brain.total_quantity:
is_source_brain = (brain.total_quantity == movement.getQuantity())
getObject = self.getPortalObject().portal_catalog.getObject
def getUrlFromUidNoCache(uid):
relative_url = getObject(uid).getRelativeUrl()
if relative_url.startswith('%s/' % base_category):
return relative_url
return '%s/%s' % (base_category, relative_url)
if cell_key_cache is not None:
def getUrlFromUidWithCache(uid):
try:
return cell_key_cache[uid]
except KeyError:
relative_url = getUrlFromUidNoCache(uid)
cell_key_cache[uid] = relative_url
return relative_url
getUrlFromUid = getUrlFromUidWithCache
else:
raise NotImplementedError('Could not guess brain side')
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
getUrlFromUid = getUrlFromUidNoCache
# otherwise we just return the node
if is_source_brain:
if axis == 'node':
return '%s/%s' % (base_category, movement.getSource())
return '%s/%s' % (base_category,
movement.getProperty('source_%s' % axis))
if axis == 'node':
return '%s/%s' % (base_category, movement.getDestination())
return '%s/%s' % (base_category,
movement.getProperty('destination_%s' % axis))
if axis == 'movement':
return getUrlFromUid(getattr(brain, 'default_%s_uid' % base_category))
elif axis == 'movement_strict_membership':
return getUrlFromUid(getattr(brain,
'default_strict_%s_uid' % base_category))
return getUrlFromUid(getattr(brain, '%s_uid' % axis))
......@@ -95,6 +95,8 @@ class CategoryBudgetVariation(BudgetVariation):
# Different possible inventory axis here
if axis == 'movement':
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',
'mirror_section', 'mirror_node' ):
return {'%s_uid' % axis: category_uid}
......@@ -117,8 +119,13 @@ class CategoryBudgetVariation(BudgetVariation):
query_dict = dict()
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
query_dict['group_by'] = [axis]
query_dict['select_list'] = [axis]
else:
query_dict['group_by_%s' % axis] = True
if axis in ('node', 'section', 'payment', 'function', 'project',
......@@ -126,7 +133,7 @@ class CategoryBudgetVariation(BudgetVariation):
axis = '%s_uid' % axis
for category in context.getVariationCategoryList(
base_category_list=(base_category,)):
base_category_list=(base_category,)):
if axis.endswith('_uid'):
category = self.getPortalObject().portal_categories\
.getCategoryUid(category)
......
......@@ -147,8 +147,11 @@ class NodeBudgetVariation(BudgetVariation):
if criterion_base_category == base_category:
if axis == 'movement':
axis = 'default_%s' % base_category
# TODO: This is not correct if axis is a category (such as
# section_category)
if axis == 'movement_strict_membership':
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
if node_url == budget_line.getRelativeUrl():
# This is the "All Other" virtual node
......@@ -181,7 +184,12 @@ class NodeBudgetVariation(BudgetVariation):
query_dict = dict()
if axis == 'movement':
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
# TODO: This is not correct if axis is a category (such as
# section_category)
axis = '%s_uid' % axis
......@@ -191,17 +199,19 @@ class NodeBudgetVariation(BudgetVariation):
return query_dict
for node_url in context.getVariationCategoryList(
base_category_list=(base_category,)):
base_category_list=(base_category,)):
query_dict.setdefault(axis, []).append(
portal_categories.getCategoryValue(node_url,
base_category=base_category).getUid())
return query_dict
def _getCellKeyFromInventoryListBrain(self, brain, budget_line):
"""Compute key from inventory brain, with support for "all others" virtual node.
def _getCellKeyFromInventoryListBrain(self, brain, budget_line,
cell_key_cache=None):
"""Compute key from inventory brain, with support for "all others" virtual
node.
"""
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 key not in [x[1] for x in
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