[Erp5-report] r37220 jerome - in /erp5/trunk/products/ERP5: Document/ tests/
nobody at svn.erp5.org
nobody at svn.erp5.org
Wed Jul 21 16:44:16 CEST 2010
Author: jerome
Date: Wed Jul 21 16:44:15 2010
New Revision: 37220
URL: http://svn.erp5.org?rev=37220&view=rev
Log:
- Initial implementation of a new way of calulating budget consumptions:
instead of doing one getInventory by budget cell, we do one getInventoryList
by budget line.
- Budget variation now uses the variation defined at the proper level, ie if
this is a line level variation, it uses membership criterion from the line,
if this is budget level, from the budget. if this is a cell level, from the
cell. This means that we no longer have to copy all level categories on the
cell. The UI will have to be updated.
- Test those new features and add some missing tests
Modified:
erp5/trunk/products/ERP5/Document/BudgetLine.py
erp5/trunk/products/ERP5/Document/BudgetModel.py
erp5/trunk/products/ERP5/Document/BudgetVariation.py
erp5/trunk/products/ERP5/Document/CategoryBudgetVariation.py
erp5/trunk/products/ERP5/Document/NodeBudgetVariation.py
erp5/trunk/products/ERP5/tests/testBudget.py
Modified: erp5/trunk/products/ERP5/Document/BudgetLine.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BudgetLine.py?rev=37220&r1=37219&r2=37220&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/BudgetLine.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/BudgetLine.py [utf8] Wed Jul 21 16:44:15 2010
@@ -36,31 +36,75 @@ from Products.ERP5.Variated import Varia
class BudgetLine(Predicate, XMLMatrix, Variated):
+ """ A Line of budget, variated in budget cells.
+ """
+
+ # Default Properties
+ property_sheets = ( PropertySheet.Base
+ , PropertySheet.XMLObject
+ , PropertySheet.SimpleItem
+ , PropertySheet.CategoryCore
+ , PropertySheet.Folder
+ , PropertySheet.Predicate
+ , PropertySheet.SortIndex
+ , PropertySheet.Task
+ , PropertySheet.Arrow
+ , PropertySheet.Budget
+ , PropertySheet.Amount
+ , PropertySheet.VariationRange
+ )
+
+ # CMF Type Definition
+ meta_type='ERP5 Budget Line'
+ portal_type='Budget Line'
+ add_permission = Permissions.AddPortalContent
+
+ # Declarative security
+ security = ClassSecurityInfo()
+ security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getConsumedBudgetDict')
+ def getConsumedBudgetDict(self, **kw):
+ """Returns all the consumptions in a dict where the keys are the cells, and
+ the value is the consumed budget.
+ """
+ return self._getBudgetDict(**kw)
+
+ security.declareProtected(Permissions.AccessContentsInformation,
+ 'getEngagedBudgetDict')
+ def getEngagedBudgetDict(self, **kw):
+ """Returns all the engagements in a dict where the keys are the cells, and
+ the value is the engaged budget.
"""
- BudgetLine a line of budget...
+ kw.setdefault('explanation_simulation_state',
+ self.getPortalReservedInventoryStateList() +
+ self.getPortalCurrentInventoryStateList() +
+ self.getPortalTransitInventoryStateList())
+ return self._getBudgetDict(**kw)
+
+ def _getBudgetDict(self, **kw):
+ """Use getCurrentInventoryList to compute all budget cell consumptions at
+ once, and returns them in a dict.
"""
+ budget = self.getParentValue()
+ budget_model = budget.getSpecialiseValue(portal_type='Budget Model')
+ if budget_model is None:
+ return dict()
+
+ query_dict = budget_model.getInventoryListQueryDict(self)
+ query_dict.update(kw)
+ query_dict.setdefault('ignore_group_by', True)
+
+ sign = self.BudgetLine_getConsumptionSign()
+ budget_dict = dict()
+ for brain in self.getPortalObject().portal_simulation\
+ .getCurrentInventoryList(**query_dict):
+ # 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
+
+ return budget_dict
- # Default Properties
- property_sheets = ( PropertySheet.Base
- , PropertySheet.XMLObject
- , PropertySheet.SimpleItem
- , PropertySheet.CategoryCore
- , PropertySheet.Folder
- , PropertySheet.Predicate
- , PropertySheet.SortIndex
- , PropertySheet.Task
- , PropertySheet.Arrow
- , PropertySheet.Budget
- , PropertySheet.Amount
- , PropertySheet.VariationRange
- , PropertySheet.Assignment
- )
-
- # CMF Type Definition
- meta_type='ERP5 Budget Line'
- portal_type='Budget Line'
- add_permission = Permissions.AddPortalContent
-
- # Declarative security
- security = ClassSecurityInfo()
- security.declareObjectProtected(Permissions.AccessContentsInformation)
Modified: erp5/trunk/products/ERP5/Document/BudgetModel.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BudgetModel.py?rev=37220&r1=37219&r2=37220&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/BudgetModel.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/BudgetModel.py [utf8] Wed Jul 21 16:44:15 2010
@@ -75,7 +75,7 @@ class BudgetModel(Predicate):
return cell_range
def getInventoryQueryDict(self, budget_cell):
- """Returns the query dict to pass to simulation query
+ """Returns the query dict to pass to simulation query for a budget cell
"""
query_dict = dict()
for budget_variation in sorted(self.contentValues(
@@ -83,14 +83,57 @@ class BudgetModel(Predicate):
key=lambda x:x.getIntIndex()):
query_dict.update(
budget_variation.getInventoryQueryDict(budget_cell))
+
+ # include dates from the budget
+ budget = budget_cell.getParentValue().getParentValue()
+ query_dict.setdefault('from_date', budget.getStartDateRangeMin())
+ start_date_range_max = budget.getStartDateRangeMax()
+ if start_date_range_max:
+ query_dict.setdefault('at_date', start_date_range_max.latestTime())
+ return query_dict
+
+ def getInventoryListQueryDict(self, budget_line):
+ """Returns the query dict to pass to simulation query for a budget line
+ """
+ query_dict = dict()
+ 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
+ if 'group_by' in query_dict and 'group_by' in variation_query_dict:
+ variation_query_dict['group_by'].extend(query_dict['group_by'])
+
+ query_dict.update(variation_query_dict)
+
+ # include dates from the budget
+ budget = budget_line.getParentValue()
+ query_dict.setdefault('from_date', budget.getStartDateRangeMin())
+ start_date_range_max = budget.getStartDateRangeMax()
+ if start_date_range_max:
+ query_dict.setdefault('at_date', start_date_range_max.latestTime())
return query_dict
+
+ def _getCellKeyFromInventoryListBrain(self, brain, budget_line):
+ """Compute the cell key from an inventory brain, the cell key can be used
+ to retrieve the budget cell in the corresponding budget line.
+ """
+ cell_key = ()
+ for budget_variation in sorted(self.contentValues(
+ portal_type=self.getPortalBudgetVariationTypeList()),
+ key=lambda x:x.getIntIndex()):
+ key = budget_variation._getCellKeyFromInventoryListBrain(brain,
+ budget_line)
+ if key:
+ cell_key += (key,)
+ return cell_key
def asBudgetPredicate(self):
" "
# XXX predicate for line / cell ?
-
def getBudgetConsumptionMethod(self, budget_cell):
+ # XXX this API might disapear
# XXX return the method, or compute directly ?
budget_consumption_method = None
for budget_variation in sorted(self.contentValues(
Modified: erp5/trunk/products/ERP5/Document/BudgetVariation.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BudgetVariation.py?rev=37220&r1=37219&r2=37220&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/BudgetVariation.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/BudgetVariation.py [utf8] Wed Jul 21 16:44:15 2010
@@ -91,3 +91,74 @@ class BudgetVariation(Predicate):
"""
return {}
+ def getInventoryListQueryDict(self, budget_line):
+ """Returns the query dict to pass to simulation query for a budget line
+ """
+ return {}
+
+ def _getCellKeyFromInventoryListBrain(self, brain, budget_line):
+ """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
+ """
+ if not self.isMemberOf('budget_variation/budget_cell'):
+ return None
+
+ axis = self.getInventoryAxis()
+ if not axis:
+ return None
+ 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())
+ 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
+
+ # 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))
+
Modified: erp5/trunk/products/ERP5/Document/CategoryBudgetVariation.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/CategoryBudgetVariation.py?rev=37220&r1=37219&r2=37220&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/CategoryBudgetVariation.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/CategoryBudgetVariation.py [utf8] Wed Jul 21 16:44:15 2010
@@ -78,7 +78,14 @@ class CategoryBudgetVariation(BudgetVari
base_category = self.getProperty('variation_base_category')
if not base_category:
return dict()
- for criterion_category in budget_cell.getMembershipCriterionCategoryList():
+
+ context = budget_cell
+ if self.isMemberOf('budget_variation/budget'):
+ context = budget_cell.getParentValue().getParentValue()
+ elif self.isMemberOf('budget_variation/budget_line'):
+ context = budget_cell.getParentValue()
+
+ for criterion_category in context.getMembershipCriterionCategoryList():
if '/' not in criterion_category: # safe ...
continue
criterion_base_category, category_url = criterion_category.split('/', 1)
@@ -94,6 +101,39 @@ class CategoryBudgetVariation(BudgetVari
return {axis: criterion_category}
return dict()
+ def getInventoryListQueryDict(self, budget_line):
+ """Returns the query dict to pass to simulation query for a budget line
+ """
+ axis = self.getInventoryAxis()
+ if not axis:
+ return dict()
+ base_category = self.getProperty('variation_base_category')
+ if not base_category:
+ return dict()
+
+ context = budget_line
+ if self.isMemberOf('budget_variation/budget'):
+ context = budget_line.getParentValue()
+
+ query_dict = dict()
+ if axis == 'movement':
+ axis = 'default_strict_%s_uid' % base_category
+ query_dict['group_by'] = [axis]
+ else:
+ query_dict['group_by_%s' % axis] = True
+ if axis in ('node', 'section', 'payment', 'function', 'project',
+ 'mirror_section', 'mirror_node' ):
+ axis = '%s_uid' % axis
+
+ for category in context.getVariationCategoryList(
+ base_category_list=(base_category,)):
+ if axis.endswith('_uid'):
+ category = self.getPortalObject().portal_categories\
+ .getCategoryUid(category)
+ query_dict.setdefault(axis, []).append(category)
+
+ return query_dict
+
def getBudgetVariationRangeCategoryList(self, context):
"""Returns the Variation Range Category List that can be applied to this
budget.
Modified: erp5/trunk/products/ERP5/Document/NodeBudgetVariation.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/NodeBudgetVariation.py?rev=37220&r1=37219&r2=37220&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/NodeBudgetVariation.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/NodeBudgetVariation.py [utf8] Wed Jul 21 16:44:15 2010
@@ -132,15 +132,23 @@ class NodeBudgetVariation(BudgetVariatio
if not base_category:
return dict()
budget_line = budget_cell.getParentValue()
- portal = self.getPortalObject()
- portal_categories = portal.portal_categories
- for criterion_category in budget_cell.getMembershipCriterionCategoryList():
+
+ context = budget_cell
+ if self.isMemberOf('budget_variation/budget'):
+ context = budget_line.getParentValue()
+ elif self.isMemberOf('budget_variation/budget_line'):
+ context = budget_line
+
+ portal_categories = self.getPortalObject().portal_categories
+ for criterion_category in context.getMembershipCriterionCategoryList():
if '/' not in criterion_category: # safe ...
continue
criterion_base_category, node_url = criterion_category.split('/', 1)
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)
axis = '%s_uid' % axis
if node_url == budget_line.getRelativeUrl():
# This is the "All Other" virtual node
@@ -155,6 +163,51 @@ class NodeBudgetVariation(BudgetVariatio
return dict()
+ def getInventoryListQueryDict(self, budget_line):
+ """Returns the query dict to pass to simulation query for a budget line
+ """
+ axis = self.getInventoryAxis()
+ if not axis:
+ return dict()
+ base_category = self.getProperty('variation_base_category')
+ if not base_category:
+ return dict()
+
+ context = budget_line
+ if self.isMemberOf('budget_variation/budget'):
+ context = budget_line.getParentValue()
+
+ portal_categories = self.getPortalObject().portal_categories
+ query_dict = dict()
+ if axis == 'movement':
+ axis = 'default_%s_uid' % base_category
+ 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
+
+ # if we have a virtual "all others" node, we don't set a criterion here.
+ if self.getProperty('include_virtual_other_node'):
+ return query_dict
+
+ for node_url in context.getVariationCategoryList(
+ 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.
+ """
+ key = BudgetVariation._getCellKeyFromInventoryListBrain(
+ self, brain, budget_line)
+ if self.getProperty('include_virtual_other_node'):
+ if key not in [x[1] for x in
+ self.getBudgetVariationRangeCategoryList(budget_line)]:
+ key = '%s/%s' % ( self.getProperty('variation_base_category'),
+ budget_line.getRelativeUrl() )
+ return key
def getBudgetLineVariationRangeCategoryList(self, budget_line):
"""Returns the Variation Range Category List that can be applied to this
Modified: erp5/trunk/products/ERP5/tests/testBudget.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testBudget.py?rev=37220&r1=37219&r2=37220&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testBudget.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testBudget.py [utf8] Wed Jul 21 16:44:15 2010
@@ -28,9 +28,31 @@
import unittest
import transaction
+from DateTime import DateTime
+
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
+from AccessControl import getSecurityManager
class TestBudget(ERP5TypeTestCase):
+
+ def afterSetUp(self):
+ self.validateRules()
+ product_line = self.portal.portal_categories.product_line
+ if '1' not in product_line.objectIds():
+ category = product_line.newContent(portal_type='Category', id='1')
+ category.newContent(portal_type='Category', id='1.1')
+ category.newContent(portal_type='Category', id='1.2')
+ if '2' not in product_line.objectIds():
+ category = product_line.newContent(portal_type='Category', id='2')
+ category.newContent(portal_type='Category', id='2.1')
+ category.newContent(portal_type='Category', id='2.2')
+
+ def beforeTearDown(self):
+ transaction.abort()
+ self.portal.accounting_module.manage_delObjects(
+ list(self.portal.accounting_module.objectIds()))
+ transaction.commit()
+ self.tic()
def getBusinessTemplateList(self):
"""Return the list of required business templates.
@@ -93,21 +115,513 @@ class TestBudget(ERP5TypeTestCase):
self.assertEquals(budget_line.getMembershipCriterionCategoryList(), [])
self.assertEquals(
budget_line.getMembershipCriterionBaseCategoryList(), [])
+
- # TODO: create cells and test variation on cell
-
- # Other TODOs
- # test simple category variation in getInventory
-
- # test that using a category variation on budget level sets membership
- # criterion on budget
+ # simuate a request and call Base_edit, which does all the work of creating
+ # cell and setting cell properties.
+ form = budget_line.BudgetLine_view
+ self.portal.REQUEST.other.update(
+ dict(AUTHENTICATED_USER=getSecurityManager().getUser(),
+
+ field_membership_criterion_base_category_list=
+ form.membership_criterion_base_category_list.get_value('default'),
+ field_mapped_value_property_list=
+ form.mapped_value_property_list.get_value('default'),
+
+ field_matrixbox_quantity_cell_0_0_0="5",
+ field_matrixbox_membership_criterion_category_list_cell_0_0_0=[
+ 'source/account_module/goods_purchase'],
+ ))
+ budget_line.Base_edit(form_id=form.getId())
+
+ self.assertEquals(1, len(budget_line.contentValues()))
+ budget_cell = budget_line.getCell('source/account_module/goods_purchase')
+ self.assertNotEquals(None, budget_cell)
+
+ self.assertEquals(['source/account_module/goods_purchase'],
+ budget_cell.getMembershipCriterionCategoryList())
+ self.assertEquals(5, budget_cell.getQuantity())
+
+ # there is no budget consumption
+ self.assertEquals(0, budget_cell.getConsumedBudget())
+ self.assertEquals(0, budget_cell.getEngagedBudget())
+ self.assertEquals(5, budget_cell.getAvailableBudget())
+ # there is no budget transfer
+ self.assertEquals(5, budget_cell.getCurrentBalance())
+
+
+ def test_category_budget_cell_variation(self):
+ budget_model = self.portal.budget_model_module.newContent(
+ portal_type='Budget Model')
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=1,
+ budget_variation='budget_cell',
+ inventory_axis='node_category',
+ variation_base_category='account_type',)
+ budget = self.portal.budget_module.newContent(
+ portal_type='Budget',
+ specialise_value=budget_model)
+ budget_line = budget.newContent(portal_type='Budget Line')
+ self.assertEquals(['account_type'],
+ budget_line.getVariationBaseCategoryList())
+
+ variation_range_category_list = \
+ budget_line.BudgetLine_getVariationRangeCategoryList()
+ self.assertTrue(['', ''] in variation_range_category_list)
+ self.assertTrue(['Expense', 'account_type/expense'] in variation_range_category_list)
+
+ def test_category_budget_line_variation(self):
+ # test that using a variation on budget line level sets membership
+ # criterion on budget line
+ budget_model = self.portal.budget_model_module.newContent(
+ portal_type='Budget Model')
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=1,
+ budget_variation='budget_line',
+ inventory_axis='section_category',
+ variation_base_category='group',)
+ budget = self.portal.budget_module.newContent(
+ portal_type='Budget',
+ specialise_value=budget_model)
+ budget_line = budget.newContent(portal_type='Budget Line')
+
+ self.assertEquals(['group'],
+ budget_line.getVariationBaseCategoryList())
+
+ variation_range_category_list = \
+ budget_line.BudgetLine_getVariationRangeCategoryList()
+
+ self.assertTrue(['', ''] in variation_range_category_list)
+ self.assertTrue(['Demo Group', 'group/demo_group'] in variation_range_category_list)
+
+ budget_line.edit(variation_category_list=['group/demo_group'])
+ self.assertEquals(['group'],
+ budget_line.getMembershipCriterionBaseCategoryList())
+ self.assertEquals(['group/demo_group'],
+ budget_line.getMembershipCriterionCategoryList())
+
+
+ def test_category_budget_variation(self):
+ budget_model = self.portal.budget_model_module.newContent(
+ portal_type='Budget Model')
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=1,
+ budget_variation='budget',
+ inventory_axis='section_category',
+ variation_base_category='group',)
+ budget = self.portal.budget_module.newContent(
+ portal_type='Budget',
+ specialise_value=budget_model)
+
+ self.assertEquals(['group'],
+ budget.getVariationBaseCategoryList())
+
+ variation_range_category_list = \
+ budget.Budget_getVariationRangeCategoryList()
+
+ self.assertTrue(['', ''] in variation_range_category_list)
+ self.assertTrue(['Demo Group', 'group/demo_group'] in variation_range_category_list)
+
+ # setting this variation on the budget also sets membership
+ budget.edit(variation_category_list=['group/demo_group'])
+ self.assertEquals('demo_group', budget.getGroup())
+ self.assertEquals('Demo Group', budget.getGroupTitle())
+
+ def test_simple_consumption(self):
+ budget_model = self.portal.budget_model_module.newContent(
+ portal_type='Budget Model')
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=1,
+ budget_variation='budget',
+ inventory_axis='section_category',
+ variation_base_category='group',)
+ budget_model.newContent(
+ portal_type='Node Budget Variation',
+ int_index=2,
+ budget_variation='budget_cell',
+ inventory_axis='node',
+ variation_base_category='source',
+ aggregate_value_list=(
+ self.portal.account_module.goods_purchase,
+ self.portal.account_module.fixed_assets,
+ ))
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=3,
+ budget_variation='budget_cell',
+ inventory_axis='node_category',
+ variation_base_category='account_type',)
+
+ budget = self.portal.budget_module.newContent(
+ portal_type='Budget',
+ start_date_range_min=DateTime(2000, 1, 1),
+ start_date_range_max=DateTime(2000, 12, 31),
+ specialise_value=budget_model)
+
+ budget.edit(variation_category_list=['group/demo_group'])
+ budget_line = budget.newContent(portal_type='Budget Line')
+
+ # set the range, this will adjust the matrix
+ budget_line.edit(
+ variation_category_list=(
+ 'source/account_module/goods_purchase',
+ 'source/account_module/fixed_assets',
+ 'account_type/expense',
+ 'account_type/asset', ))
+
+ # simuate a request and call Base_edit, which does all the work of creating
+ # cell and setting cell properties.
+ form = budget_line.BudgetLine_view
+ self.portal.REQUEST.other.update(
+ dict(AUTHENTICATED_USER=getSecurityManager().getUser(),
+
+ field_membership_criterion_base_category_list=
+ form.membership_criterion_base_category_list.get_value('default'),
+ field_mapped_value_property_list=
+ form.mapped_value_property_list.get_value('default'),
+
+ field_matrixbox_quantity_cell_0_0_0="",
+ field_matrixbox_membership_criterion_category_list_cell_0_0_0=[],
+ field_matrixbox_quantity_cell_1_0_0="2",
+ field_matrixbox_membership_criterion_category_list_cell_1_0_0=[
+ 'source/account_module/fixed_assets',
+ 'account_type/asset'],
+ field_matrixbox_quantity_cell_0_1_0="1",
+ field_matrixbox_membership_criterion_category_list_cell_0_1_0=[
+ 'source/account_module/goods_purchase',
+ 'account_type/expense'],
+ field_matrixbox_quantity_cell_1_1_0="",
+ field_matrixbox_membership_criterion_category_list_cell_1_1_0=[],
+ ))
+ budget_line.Base_edit(form_id=form.getId())
+
+ self.assertEquals(2, len(budget_line.contentValues()))
+ budget_cell = budget_line.getCell('source/account_module/goods_purchase',
+ 'account_type/expense')
+ self.assertNotEquals(None, budget_cell)
+ self.assertEquals(
+ dict(from_date=DateTime(2000, 1, 1),
+ at_date=DateTime(2000, 12, 31).latestTime(),
+ node_category='account_type/expense',
+ node_uid=self.portal.account_module.goods_purchase.getUid(),
+ section_category='group/demo_group',),
+ budget_model.getInventoryQueryDict(budget_cell))
+
+ budget_cell = budget_line.getCell('source/account_module/fixed_assets',
+ 'account_type/asset')
+ self.assertNotEquals(None, budget_cell)
+ self.assertEquals(
+ dict(from_date=DateTime(2000, 1, 1),
+ at_date=DateTime(2000, 12, 31).latestTime(),
+ node_category='account_type/asset',
+ node_uid=self.portal.account_module.fixed_assets.getUid(),
+ section_category='group/demo_group',),
+ budget_model.getInventoryQueryDict(budget_cell))
+
+ self.assertEquals(
+ dict(from_date=DateTime(2000, 1, 1),
+ at_date=DateTime(2000, 12, 31).latestTime(),
+ node_category=['account_type/expense', 'account_type/asset'],
+ node_uid=[self.portal.account_module.goods_purchase.getUid(),
+ self.portal.account_module.fixed_assets.getUid()],
+ section_category=['group/demo_group'],
+ group_by_node_category=True,
+ group_by_node=True,
+ group_by_section_category=True,
+ ),
+ budget_model.getInventoryListQueryDict(budget_line))
+
+
+ atransaction = self.portal.accounting_module.newContent(
+ portal_type='Accounting Transaction',
+ resource_value=self.portal.currency_module.euro,
+ source_section_value=self.portal.organisation_module.my_organisation,
+ start_date=DateTime(2000, 1, 2))
+ atransaction.newContent(
+ portal_type='Accounting Transaction Line',
+ source_value=self.portal.account_module.goods_purchase,
+ source_debit=100)
+ atransaction.newContent(
+ portal_type='Accounting Transaction Line',
+ source_value=self.portal.account_module.fixed_assets,
+ source_credit=100)
+ atransaction.stop()
+
+ transaction.commit()
+ self.tic()
+
+ self.assertEquals(
+ {('source/account_module/fixed_assets', 'account_type/asset'): -100.0,
+ ('source/account_module/goods_purchase', 'account_type/expense'): 100.0},
+ budget_line.getConsumedBudgetDict())
+
+ self.assertEquals(
+ {('source/account_module/fixed_assets', 'account_type/asset'): -100.0,
+ ('source/account_module/goods_purchase', 'account_type/expense'): 100.0},
+ budget_line.getEngagedBudgetDict())
+
+ def test_all_other_and_strict_consumption(self):
+ # tests consumptions, by using "all other" virtual node on a node budget
+ # variation, and strict membership on category budget variation
+ budget_model = self.portal.budget_model_module.newContent(
+ portal_type='Budget Model')
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=1,
+ budget_variation='budget',
+ inventory_axis='section_category_strict_membership',
+ variation_base_category='group',)
+ budget_model.newContent(
+ portal_type='Node Budget Variation',
+ int_index=2,
+ budget_variation='budget_cell',
+ inventory_axis='node',
+ variation_base_category='source',
+ aggregate_value_list=(
+ self.portal.account_module.goods_purchase,),
+ include_virtual_other_node=True)
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=3,
+ budget_variation='budget_cell',
+ inventory_axis='node_category_strict_membership',
+ variation_base_category='account_type',)
+
+ budget = self.portal.budget_module.newContent(
+ portal_type='Budget',
+ start_date_range_min=DateTime(2000, 1, 1),
+ start_date_range_max=DateTime(2000, 12, 31),
+ specialise_value=budget_model)
+
+ budget.edit(variation_category_list=['group/demo_group/sub1'])
+ budget_line = budget.newContent(portal_type='Budget Line')
+
+ # set the range, this will adjust the matrix
+ budget_line.edit(
+ variation_category_list=(
+ 'source/account_module/goods_purchase',
+ 'source/%s' % budget_line.getRelativeUrl(), # this is 'all others'
+ 'account_type/expense',
+ 'account_type/asset', ))
+
+ # simuate a request and call Base_edit, which does all the work of creating
+ # cell and setting cell properties.
+ form = budget_line.BudgetLine_view
+ self.portal.REQUEST.other.update(
+ dict(AUTHENTICATED_USER=getSecurityManager().getUser(),
+
+ field_membership_criterion_base_category_list=
+ form.membership_criterion_base_category_list.get_value('default'),
+ field_mapped_value_property_list=
+ form.mapped_value_property_list.get_value('default'),
+
+ field_matrixbox_quantity_cell_0_0_0="",
+ field_matrixbox_membership_criterion_category_list_cell_0_0_0=[],
+ field_matrixbox_quantity_cell_1_0_0="2",
+ field_matrixbox_membership_criterion_category_list_cell_1_0_0=[
+ 'source/%s' % budget_line.getRelativeUrl(),
+ 'account_type/asset'],
+ field_matrixbox_quantity_cell_0_1_0="1",
+ field_matrixbox_membership_criterion_category_list_cell_0_1_0=[
+ 'source/account_module/goods_purchase',
+ 'account_type/expense'],
+ field_matrixbox_quantity_cell_1_1_0="",
+ field_matrixbox_membership_criterion_category_list_cell_1_1_0=[],
+ ))
+ budget_line.Base_edit(form_id=form.getId())
+
+ self.assertEquals(2, len(budget_line.contentValues()))
+
+ self.assertEquals(
+ dict(from_date=DateTime(2000, 1, 1),
+ at_date=DateTime(2000, 12, 31).latestTime(),
+ node_category_strict_membership=['account_type/expense',
+ 'account_type/asset'],
+ section_category_strict_membership=['group/demo_group/sub1'],
+ group_by_node_category_strict_membership=True,
+ group_by_node=True,
+ group_by_section_category_strict_membership=True,
+ ),
+ budget_model.getInventoryListQueryDict(budget_line))
+
+
+ atransaction = self.portal.accounting_module.newContent(
+ portal_type='Accounting Transaction',
+ resource_value=self.portal.currency_module.euro,
+ source_section_value=self.portal.organisation_module.my_organisation,
+ start_date=DateTime(2000, 1, 2))
+ atransaction.newContent(
+ portal_type='Accounting Transaction Line',
+ source_value=self.portal.account_module.goods_purchase,
+ source_debit=100)
+ atransaction.newContent(
+ portal_type='Accounting Transaction Line',
+ source_value=self.portal.account_module.fixed_assets,
+ source_credit=100)
+ atransaction.stop()
+
+ transaction.commit()
+ self.tic()
+
+ self.assertEquals(
+ {('source/%s' % budget_line.getRelativeUrl(), 'account_type/asset'): -100.0,
+ ('source/account_module/goods_purchase', 'account_type/expense'): 100.0},
+ budget_line.getConsumedBudgetDict())
+
+ self.assertEquals(
+ {('source/%s' % budget_line.getRelativeUrl(), 'account_type/asset'): -100.0,
+ ('source/account_module/goods_purchase', 'account_type/expense'): 100.0},
+ budget_line.getEngagedBudgetDict())
+
+
+ def test_consumption_movement_category(self):
+ # test for budget consumption using movement category
+ budget_model = self.portal.budget_model_module.newContent(
+ portal_type='Budget Model')
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=1,
+ budget_variation='budget',
+ inventory_axis='section_category',
+ variation_base_category='group',)
+ budget_model.newContent(
+ portal_type='Node Budget Variation',
+ int_index=2,
+ budget_variation='budget_cell',
+ inventory_axis='node',
+ variation_base_category='source',
+ aggregate_value_list=(
+ self.portal.account_module.goods_purchase,
+ self.portal.account_module.fixed_assets,
+ ))
+ budget_model.newContent(
+ portal_type='Category Budget Variation',
+ int_index=3,
+ budget_variation='budget_cell',
+ inventory_axis='movement',
+ variation_base_category='product_line',)
+
+ budget = self.portal.budget_module.newContent(
+ portal_type='Budget',
+ start_date_range_min=DateTime(2000, 1, 1),
+ start_date_range_max=DateTime(2000, 12, 31),
+ specialise_value=budget_model)
+
+ budget.edit(variation_category_list=['group/demo_group'])
+ budget_line = budget.newContent(portal_type='Budget Line')
+
+ # set the range, this will adjust the matrix
+ budget_line.edit(
+ variation_category_list=(
+ 'source/account_module/goods_purchase',
+ 'source/account_module/fixed_assets',
+ 'product_line/1',
+ 'product_line/1/1.1',
+ 'product_line/1/1.2', ))
+
+ # simuate a request and call Base_edit, which does all the work of creating
+ # cell and setting cell properties.
+ form = budget_line.BudgetLine_view
+ self.portal.REQUEST.other.update(
+ dict(AUTHENTICATED_USER=getSecurityManager().getUser(),
+
+ field_membership_criterion_base_category_list=
+ form.membership_criterion_base_category_list.get_value('default'),
+ field_mapped_value_property_list=
+ form.mapped_value_property_list.get_value('default'),
+
+ # this cell will be a summary cell
+ field_matrixbox_quantity_cell_0_0_0="2",
+ field_matrixbox_membership_criterion_category_list_cell_0_0_0=[
+ 'source/account_module/goods_purchase',
+ 'product_line/1'],
+ field_matrixbox_quantity_cell_1_0_0="",
+ field_matrixbox_membership_criterion_category_list_cell_1_0_0=[],
+ field_matrixbox_quantity_cell_0_1_0="2",
+ field_matrixbox_membership_criterion_category_list_cell_0_1_0=[
+ 'source/account_module/goods_purchase',
+ 'product_line/1/1.1'],
+ field_matrixbox_quantity_cell_1_1_0="",
+ field_matrixbox_membership_criterion_category_list_cell_1_1_0=[],
+ field_matrixbox_quantity_cell_0_2_0="",
+ field_matrixbox_membership_criterion_category_list_cell_0_2_0=[],
+ field_matrixbox_quantity_cell_1_2_0="",
+ field_matrixbox_membership_criterion_category_list_cell_1_2_0=[],
+ ))
+ budget_line.Base_edit(form_id=form.getId())
+
+ self.assertEquals(2, len(budget_line.contentValues()))
+
+ product_line_1 = self.portal.portal_categories.product_line['1']
+ product_line_1_11 = product_line_1['1.1']
+ product_line_1_12 = product_line_1['1.2']
+
+ self.assertEquals(
+ dict(from_date=DateTime(2000, 1, 1),
+ at_date=DateTime(2000, 12, 31).latestTime(),
+ node_uid=[self.portal.account_module.goods_purchase.getUid(),
+ self.portal.account_module.fixed_assets.getUid(),],
+ default_strict_product_line_uid=[product_line_1.getUid(),
+ product_line_1_11.getUid(),
+ product_line_1_12.getUid(),],
+ section_category=['group/demo_group'],
+ group_by=['default_strict_product_line_uid'],
+ group_by_node=True,
+ group_by_section_category=True,
+ ),
+ budget_model.getInventoryListQueryDict(budget_line))
+
+
+ atransaction = self.portal.accounting_module.newContent(
+ portal_type='Accounting Transaction',
+ resource_value=self.portal.currency_module.euro,
+ source_section_value=self.portal.organisation_module.my_organisation,
+ start_date=DateTime(2000, 1, 2))
+ atransaction.newContent(
+ portal_type='Accounting Transaction Line',
+ source_value=self.portal.account_module.goods_purchase,
+ product_line_value=product_line_1_11,
+ source_debit=100)
+ atransaction.newContent(
+ portal_type='Accounting Transaction Line',
+ source_value=self.portal.account_module.fixed_assets,
+ product_line_value=product_line_1_12,
+ source_credit=100)
+ atransaction.stop()
+
+ transaction.commit()
+ self.tic()
+
+ self.assertEquals(
+ {('source/account_module/fixed_assets', 'product_line/1/1.2'): -100.0,
+ ('source/account_module/goods_purchase', 'product_line/1/1.1'): 100.0,
+ # summary line is automatically added (TODO)
+## ('source/account_module/goods_purchase', 'product_line/1'): 100.0
+ },
+ budget_line.getConsumedBudgetDict())
+
+ self.assertEquals(
+ {('source/account_module/fixed_assets', 'product_line/1/1.2'): -100.0,
+ ('source/account_module/goods_purchase', 'product_line/1/1.1'): 100.0,
+ # summary line is automatically added (TODO)
+## ('source/account_module/goods_purchase', 'product_line/1'): 100.0
+ },
+ budget_line.getEngagedBudgetDict())
+
+
+ # Other TODOs:
+
+ # section_category & summary
- # test that using a variation on budget line level sets membership
- # criterion on budget line (and budget cell or not ?)
+ # resource/price currency on budget ?
+ # test virtual all others when cloning an existing budget
- # test that using a category variation on budget level is used in inventory
- # calculation
+ # predicates
def test_suite():
More information about the Erp5-report
mailing list