[Erp5-report] r16371 - in /erp5/trunk/products/ERP5: Document/ tests/
nobody at svn.erp5.org
nobody at svn.erp5.org
Fri Sep 14 15:28:09 CEST 2007
Author: jerome
Date: Fri Sep 14 15:28:09 2007
New Revision: 16371
URL: http://svn.erp5.org?rev=16371&view=rev
Log:
Index Balance Transactions in a similar ways as inventories. Only the delta
will be in the stock table. So in this case, only line for profit and loss will
be in the catalog.
Added:
erp5/trunk/products/ERP5/Document/BalanceTransaction.py
erp5/trunk/products/ERP5/Document/BalanceTransactionLine.py
Modified:
erp5/trunk/products/ERP5/tests/testAccounting.py
Added: erp5/trunk/products/ERP5/Document/BalanceTransaction.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BalanceTransaction.py?rev=16371&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/Document/BalanceTransaction.py (added)
+++ erp5/trunk/products/ERP5/Document/BalanceTransaction.py Fri Sep 14 15:28:09 2007
@@ -1,0 +1,399 @@
+##############################################################################
+#
+# Copyright (c) 2007 Nexedi SA and Contributors. All Rights Reserved.
+# Jerome Perrin <jerome at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+from UserDict import UserDict
+
+from AccessControl import ClassSecurityInfo
+from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
+from Products.ERP5.Document.Inventory import Inventory
+from Products.ERP5.Document.AccountingTransaction import AccountingTransaction
+
+
+class InventoryKey(UserDict):
+ """Class to use as a key when defining inventory dicts.
+ """
+ def __init__(self, **kw):
+ self.data = {}
+ self.data.update(kw)
+
+ def clear(self):
+ raise TypeError, 'InventoryKey are immutable'
+
+ def pop(self, keys, *args):
+ raise TypeError, 'InventoryKey are immutable'
+
+ def update(self, dict=None, **kwargs):
+ raise TypeError, 'InventoryKey are immutable'
+
+ def __delitem__(self, key):
+ raise TypeError, 'InventoryKey are immutable'
+
+ def __setitem__(self, key, item):
+ raise TypeError, 'InventoryKey are immutable'
+
+ def setdefault(self, key, failobj=None):
+ if key in self.data:
+ return self.data[key]
+ raise TypeError, 'InventoryKey are immutable'
+
+ def __hash__(self):
+ return hash(tuple(self.items()))
+
+
+class BalanceTransaction(AccountingTransaction, Inventory):
+ """Balance Transaction
+ """
+
+ # CMF Type Definition
+ meta_type = 'ERP5 Balance Transaction'
+ portal_type = 'Balance Transaction'
+ add_permission = Permissions.AddPortalContent
+ isPortalContent = 1
+ isRADContent = 1
+ isDelivery = 1
+
+ #__implements__ = ( Interface.Inventory, )
+
+ # Declarative security
+ security = ClassSecurityInfo()
+ security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+ # Default Properties
+ property_sheets = ( PropertySheet.Base
+ , PropertySheet.XMLObject
+ , PropertySheet.CategoryCore
+ , PropertySheet.DublinCore
+ , PropertySheet.Task
+ , PropertySheet.Arrow
+ , PropertySheet.Movement
+ , PropertySheet.Delivery
+ , PropertySheet.Amount
+ , PropertySheet.Reference
+ , PropertySheet.PaymentCondition
+ )
+
+ def _getGroupByNodeMovementList(self):
+ """Returns movements that implies only grouping by node."""
+ movement_list = []
+ for movement in self.getMovementList():
+ if not (movement.getSourceSection() or
+ movement.getDestinationPayment()):
+ movement_list.append(movement)
+ return movement_list
+
+ def _getGroupByPaymentMovementList(self):
+ """Returns movements that implies grouping by node and payment"""
+ movement_list = []
+ for movement in self.getMovementList():
+ if movement.getDestinationPayment():
+ movement_list.append(movement)
+ return movement_list
+
+ def _getGroupByMirrorSectionMovementList(self):
+ """Returns movements that implies only grouping by node and mirror section"""
+ movement_list = []
+ for movement in self.getMovementList():
+ if movement.getSourceSection():
+ movement_list.append(movement)
+ return movement_list
+
+
+ def _getCurrentStockDict(self):
+ """Looks the current stock by calling getInventoryList, and building a
+ dictionnary of InventoryKey
+ """
+ current_stock = dict()
+ getInventoryList = self.getPortalObject()\
+ .portal_simulation.getInventoryList
+ default_inventory_params = dict(
+ at_date=self.getStartDate(),
+ section_uid=self.getDestinationSectionUid(),
+ simulation_state=('delivered', ))
+
+ # node
+ for movement in self._getGroupByNodeMovementList():
+ node_uid = movement.getDestinationUid()
+ section_uid = movement.getDestinationSectionUid()
+
+ stock_list = current_stock.setdefault(
+ InventoryKey(node_uid=node_uid,
+ section_uid=section_uid), [])
+ for inventory in getInventoryList(
+ node_uid=node_uid,
+ group_by_node=1,
+ group_by_resource=1,
+ **default_inventory_params):
+ stock_list.append(
+ dict(destination_uid=node_uid,
+ destination_section_uid=section_uid,
+ resource_uid=inventory.resource_uid,
+ quantity=inventory.total_quantity,
+ total_price=inventory.total_price, ))
+
+ # mirror section
+ for movement in self._getGroupByMirrorSectionMovementList():
+ node_uid = movement.getDestinationUid()
+ section_uid = movement.getDestinationSectionUid()
+ mirror_section_uid = movement.getSourceSectionUid()
+
+ stock_list = current_stock.setdefault(
+ InventoryKey(node_uid=node_uid,
+ mirror_section_uid=mirror_section_uid,
+ section_uid=section_uid), [])
+ for inventory in getInventoryList(
+ node_uid=node_uid,
+ mirror_section_uid=mirror_section_uid,
+ group_by_node=1,
+ group_by_mirror_section=1,
+ group_by_resource=1,
+ **default_inventory_params):
+ stock_list.append(
+ dict(destination_uid=node_uid,
+ destination_section_uid=section_uid,
+ source_section_uid=mirror_section_uid,
+ resource_uid=inventory.resource_uid,
+ quantity=inventory.total_quantity,
+ total_price=inventory.total_price, ))
+
+ # payment
+ for movement in self._getGroupByPaymentMovementList():
+ node_uid = movement.getDestinationUid()
+ payment_uid = movement.getDestinationPaymentUid()
+ section_uid = movement.getDestinationSectionUid()
+
+ stock_list = current_stock.setdefault(
+ InventoryKey(node_uid=node_uid,
+ section_uid=section_uid,
+ payment_uid=payment_uid), [])
+ for inventory in getInventoryList(
+ node_uid=node_uid,
+ group_by_node=1,
+ group_by_payment=1,
+ group_by_resource=1,
+ **default_inventory_params):
+ stock_list.append(
+ dict(destination_uid=node_uid,
+ destination_section_uid=section_uid,
+ destination_payment_uid=payment_uid,
+ resource_uid=inventory.resource_uid,
+ quantity=inventory.total_quantity,
+ total_price=inventory.total_price, ))
+
+ return current_stock
+
+
+ def _getNewStockDict(self):
+ """Looks the new stock on lines in this inventory, and building a
+ dictionnary of InventoryKey
+ """
+ new_stock = dict()
+ # node
+ for movement in self._getGroupByNodeMovementList():
+ node_uid = movement.getDestinationUid()
+ section_uid = movement.getDestinationSectionUid()
+
+ stock_list = new_stock.setdefault(
+ InventoryKey(node_uid=node_uid,
+ section_uid=section_uid), [])
+ stock_list.append(
+ dict(destination_uid=node_uid,
+ destination_section_uid=section_uid,
+ resource_uid=movement.getResourceUid(),
+ quantity=movement.getQuantity(),
+ total_price=movement\
+ .getDestinationInventoriatedTotalAssetPrice(), ))
+
+ # mirror section
+ for movement in self._getGroupByMirrorSectionMovementList():
+ node_uid = movement.getDestinationUid()
+ section_uid = movement.getDestinationSectionUid()
+ mirror_section_uid = movement.getSourceSectionUid()
+
+ stock_list = new_stock.setdefault(
+ InventoryKey(node_uid=node_uid,
+ mirror_section_uid=mirror_section_uid,
+ section_uid=section_uid), [])
+ stock_list.append(
+ dict(destination_uid=node_uid,
+ destination_section_uid=section_uid,
+ source_section_uid=mirror_section_uid,
+ resource_uid=movement.getResourceUid(),
+ quantity=movement.getQuantity(),
+ total_price=movement\
+ .getDestinationInventoriatedTotalAssetPrice(), ))
+
+ # payment
+ for movement in self._getGroupByPaymentMovementList():
+ node_uid = movement.getDestinationUid()
+ section_uid = movement.getDestinationSectionUid()
+ payment_uid = movement.getDestinationPaymentUid()
+
+ stock_list = new_stock.setdefault(
+ InventoryKey(node_uid=node_uid,
+ payment_uid=payment_uid,
+ section_uid=section_uid), [])
+ stock_list.append(
+ dict(destination_uid=node_uid,
+ destination_section_uid=section_uid,
+ destination_payment_uid=payment_uid,
+ resource_uid=movement.getResourceUid(),
+ quantity=movement.getQuantity(),
+ total_price=movement\
+ .getDestinationInventoriatedTotalAssetPrice(), ))
+
+ return new_stock
+
+
+ def _computeStockDifferenceList(self, current_stock_dict, new_stock_dict):
+ """Compute the difference between the result of _getCurrentStockDict and
+ _getNewStockDict. Returns a list of dictionnaries with similar keys that
+ the ones on inventory brains (node, section, mirror_section ...)
+ """
+ def computeStockDifference(current_stock_list, new_stock_list):
+ # helper function to compute difference between two stock lists.
+ if not current_stock_list:
+ return new_stock_list
+
+ stock_diff_list = current_stock_list[::] # deep copy ?
+
+ for new_stock in new_stock_list:
+ matching_diff = None
+ for diff in stock_diff_list:
+ for prop in [k for k in diff.keys() if k not in ('quantity',
+ 'total_price')]:
+ if diff[prop] != new_stock.get(prop):
+ break
+ else:
+ matching_diff = diff
+
+ # matching_diff are negated later
+ if matching_diff:
+ matching_diff['quantity'] -= new_stock['quantity']
+ # Matching_diff and new_stock must be consistent.
+ # both with total price or none.
+ if matching_diff['total_price'] and new_stock['total_price']:
+ matching_diff['total_price'] -= new_stock['total_price']
+ else:
+ stock_diff_list.append(new_stock)
+
+ # we were doing with reversed calculation, so negate deltas again.
+ # Also we remove stocks that have 0 quantity and price.
+ return [negateStock(s) for s in stock_diff_list
+ if s['quantity'] and s['total_price']]
+
+ def negateStock(stock):
+ negated_stock = stock.copy()
+ negated_stock['quantity'] = -stock['quantity']
+ if stock['total_price']:
+ negated_stock['total_price'] = -stock['total_price']
+ return negated_stock
+
+ delta_list = []
+ for current_stock_key, current_stock_value_list in \
+ current_stock_dict.items():
+ if current_stock_key in new_stock_dict:
+ delta_list.extend(computeStockDifference(
+ current_stock_value_list,
+ new_stock_dict[current_stock_key]))
+ else:
+ delta_list.extend(
+ [negateStock(s) for s in current_stock_value_list])
+
+ # now add every thing in new stock which was not in current stock
+ for new_stock_key, new_stock_value_list in \
+ new_stock_dict.items():
+ if new_stock_key not in current_stock_dict:
+ delta_list.extend(new_stock_value_list)
+
+ return delta_list
+
+
+ def _getTempObjectFactory(self):
+ """Returns the factory method that will create temp object.
+
+ This method must return a function that accepts properties keywords
+ arguments and returns a temp object edited with those properties.
+ """
+ from Products.ERP5Type.Document import newTempBalanceTransactionLine
+
+ def factory(*args, **kw):
+ doc = newTempBalanceTransactionLine(self, self.getId(),
+ uid=self.getUid())
+ destination_total_asset_price = kw.pop('total_price', None)
+ if destination_total_asset_price is not None:
+ kw['destination_total_asset_price'] = destination_total_asset_price
+ doc._edit(*args, **kw)
+ return doc
+
+ return factory
+
+
+ security.declarePrivate('alternateReindexObject')
+ def alternateReindexObject(self, **kw):
+ """This method is called when an inventory object is included in a
+ group of catalogged objects.
+ """
+ return self.immediateReindexObject(**kw)
+
+
+ def immediateReindexObject(self, **kw):
+ """Reindexes the object.
+ This is different indexing that the default Inventory indexing, because
+ we want to take into account that lines in this balance transaction to
+ represent the balance of an account (node) with different parameters,
+ based on the account_type of those accounts:
+ - on standards accounts: it's simply the balance for node, section
+ (and maybe resource, like all of thoses)
+ - on payable / receivable accounts: for node, section and mirror
+ section
+ - on bank accounts: for node, section and payment
+
+ Also this uses total_price (and quantity), and ignores variations and
+ subvariations as it does not exist in accounting.
+ """
+ current_stock_dict = self._getCurrentStockDict()
+ new_stock_dict = self._getNewStockDict()
+ diff_list = self._computeStockDifferenceList(
+ current_stock_dict,
+ new_stock_dict)
+
+ temp_object_factory = self._getTempObjectFactory()
+ stock_object_list = []
+ add_obj = stock_object_list.append
+ for diff in diff_list:
+ add_obj(temp_object_factory(**diff))
+
+ # Catalog this transaction as a standard document
+ object_list = [self]
+ self.portal_catalog.catalogObjectList(object_list)
+
+ # Catalog differences calculated from lines
+ self.portal_catalog.catalogObjectList(stock_object_list,
+ method_id_list=('z_catalog_stock_list',),
+ disable_cache=1, check_uid=0)
+
Added: erp5/trunk/products/ERP5/Document/BalanceTransactionLine.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/BalanceTransactionLine.py?rev=16371&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/Document/BalanceTransactionLine.py (added)
+++ erp5/trunk/products/ERP5/Document/BalanceTransactionLine.py Fri Sep 14 15:28:09 2007
@@ -1,0 +1,58 @@
+##############################################################################
+#
+# Copyright (c) 2007 Nexedi SA and Contributors. All Rights Reserved.
+# Jerome Perrin <jerome at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+from AccessControl import ClassSecurityInfo
+
+from Products.ERP5Type import Permissions, PropertySheet, Interface
+from Products.ERP5.Document.AccountingTransactionLine import \
+ AccountingTransactionLine
+from Products.ERP5.Document.InventoryLine import InventoryLine
+
+
+class BalanceTransactionLine(AccountingTransactionLine, InventoryLine):
+ """A balance transaction line inherits price handling from accounting
+ transaction line, and indexing from inventory line.
+ """
+
+ meta_type = 'ERP5 Balance Transaction Line'
+ portal_type = 'Balance Transaction Line'
+ add_permission = Permissions.AddPortalContent
+ isPortalContent = 1
+ isRADContent = 1
+ isIndexable = 0
+
+ # Declarative security
+ security = ClassSecurityInfo()
+ security.declareObjectProtected(Permissions.AccessContentsInformation)
+
+ reindexObject = InventoryLine.reindexObject
+ recursiveReindexObject = InventoryLine.recursiveReindexObject
+ immediateReindexObject = InventoryLine.immediateReindexObject
+ recursiveImmediateReindexObject = \
+ InventoryLine.recursiveImmediateReindexObject
+
Modified: erp5/trunk/products/ERP5/tests/testAccounting.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testAccounting.py?rev=16371&r1=16370&r2=16371&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testAccounting.py (original)
+++ erp5/trunk/products/ERP5/tests/testAccounting.py Fri Sep 14 15:28:09 2007
@@ -36,7 +36,6 @@
from Products.DCWorkflow.DCWorkflow import ValidationFailed
from AccessControl.SecurityManagement import newSecurityManager
from Products.ERP5Type.tests.Sequence import Sequence, SequenceList
-from Products.ERP5.Document.Delivery import Delivery
from DateTime import DateTime
SOURCE = 'source'
@@ -169,7 +168,7 @@
self.person_module):
for doc in module.objectValues():
doc.validate()
-
+
# and the preference enabled
preference = self.portal.portal_preferences.accounting_zuite_preference
pref.manage_addLocalRoles(self.username, ('Auditor', ))
@@ -223,7 +222,7 @@
def test_createBalanceOnNode(self):
period = self.section.newContent(portal_type='Accounting Period')
period.setStartDate(DateTime(2006, 1, 1))
- period.setStartDate(DateTime(2006, 12, 31))
+ period.setStopDate(DateTime(2006, 12, 31))
transaction1 = self._makeOne(
start_date=DateTime(2006, 1, 1),
@@ -309,7 +308,7 @@
organisation_module = self.organisation_module
period = self.section.newContent(portal_type='Accounting Period')
period.setStartDate(DateTime(2006, 1, 1))
- period.setStartDate(DateTime(2006, 12, 31))
+ period.setStopDate(DateTime(2006, 12, 31))
transaction1 = self._makeOne(
start_date=DateTime(2006, 1, 1),
@@ -403,7 +402,7 @@
organisation_module = self.organisation_module
period = self.section.newContent(portal_type='Accounting Period')
period.setStartDate(DateTime(2006, 1, 1))
- period.setStartDate(DateTime(2006, 12, 31))
+ period.setStopDate(DateTime(2006, 12, 31))
bank1 = self.section.newContent(
id='bank1', reference='bank1',
@@ -529,7 +528,7 @@
organisation_module = self.organisation_module
period = self.section.newContent(portal_type='Accounting Period')
period.setStartDate(DateTime(2006, 1, 1))
- period.setStartDate(DateTime(2006, 12, 31))
+ period.setStopDate(DateTime(2006, 12, 31))
transaction1 = self._makeOne(
start_date=DateTime(2006, 1, 1),
@@ -645,7 +644,7 @@
# open a period for our section
period = self.section.newContent(portal_type='Accounting Period')
period.setStartDate(DateTime(2006, 1, 1))
- period.setStartDate(DateTime(2006, 12, 31))
+ period.setStopDate(DateTime(2006, 12, 31))
self.assertEquals('draft', period.getSimulationState())
self.portal.portal_workflow.doActionFor(period, 'start_action')
self.assertEquals('started', period.getSimulationState())
@@ -702,7 +701,7 @@
"""
period1 = self.section.newContent(portal_type='Accounting Period')
period1.setStartDate(DateTime(2006, 1, 1))
- period1.setStartDate(DateTime(2006, 12, 31))
+ period1.setStopDate(DateTime(2006, 12, 31))
period1.start()
transaction1 = self._makeOne(
@@ -733,17 +732,17 @@
period2 = self.section.newContent(portal_type='Accounting Period')
period2.setStartDate(DateTime(2007, 1, 1))
- period2.setStartDate(DateTime(2007, 12, 31))
+ period2.setStopDate(DateTime(2007, 12, 31))
period2.start()
transaction2 = self._makeOne(
start_date=DateTime(2007, 1, 2),
portal_type='Accounting Transaction',
simulation_state='delivered',
- lines=(dict(destination_value=self.account_module.equity,
- destination_debit=100),
- dict(destination_value=pl_account,
- destination_credit=100)))
+ lines=(dict(source_value=self.account_module.equity,
+ source_debit=100),
+ dict(source_value=pl_account,
+ source_credit=100)))
transaction3 = self._makeOne(
start_date=DateTime(2007, 1, 3),
portal_type='Purchase Invoice Transaction',
@@ -753,7 +752,7 @@
destination_debit=300),
dict(destination_value=self.account_module.payable,
destination_credit=300)))
- period2.stop()
+
period2.AccountingPeriod_createBalanceTransaction(
profit_and_loss_account=pl_account.getRelativeUrl())
balance_transaction_list = [tr for tr in
@@ -798,7 +797,7 @@
"""
period = self.section.newContent(portal_type='Accounting Period')
period.setStartDate(DateTime(2006, 1, 1))
- period.setStartDate(DateTime(2006, 12, 31))
+ period.setStopDate(DateTime(2006, 12, 31))
pl_account = self.portal.account_module.newContent(
portal_type='Account',
account_type='equity',
@@ -824,6 +823,7 @@
portal_type='Balance Transaction')
self.assertEquals(1, len(balance_transaction_list))
balance_transaction = balance_transaction_list[0]
+ balance_transaction.alternateReindexObject()
movement_list = balance_transaction.getMovementList()
self.assertEquals(2, len(movement_list))
@@ -837,6 +837,114 @@
self.assertEquals(1, len(stock_movement_list))
self.assertEquals(500, stock_movement_list[0].getDestinationCredit())
+
+ def test_InventoryIndexingNodeAndMirrorSection(self):
+ # Balance Transactions are indexed as Inventories.
+ transaction1 = self._makeOne(
+ start_date=DateTime(2006, 1, 1),
+ portal_type='Sale Invoice Transaction',
+ destination_section_value=self.organisation_module.client_1,
+ simulation_state='delivered',
+ lines=(dict(source_value=self.account_module.receivable,
+ source_debit=100),
+ dict(source_value=self.account_module.goods_sales,
+ source_credit=100)))
+
+ balance = self.accounting_module.newContent(
+ portal_type='Balance Transaction',
+ destination_section_value=self.section,
+ start_date=DateTime(2006, 12, 31),
+ resource_value=self.currency_module.euro,)
+ balance.newContent(
+ portal_type='Balance Transaction Line',
+ destination_value=self.account_module.receivable,
+ source_section_value=self.organisation_module.client_1,
+ destination_debit=100,)
+ balance.newContent(
+ portal_type='Balance Transaction Line',
+ destination_value=self.account_module.stocks,
+ destination_credit=100,)
+ balance.stop()
+ balance.deliver()
+ balance.immediateReindexObject()
+
+ # now check inventory
+ stool = self.getSimulationTool()
+ # the account 'receivable' has a balance of 100
+ node_uid = self.account_module.receivable.getUid()
+ self.assertEquals(100, stool.getInventory(
+ section_uid=self.section.getUid(),
+ node_uid=node_uid))
+ self.assertEquals(100, stool.getInventory(
+ section_uid=self.section.getUid(),
+ mirror_section_uid=self.organisation_module.client_1.getUid(),
+ node_uid=node_uid))
+ self.assertEquals(100, stool.getInventoryAssetPrice(
+ section_uid=self.section.getUid(),
+ node_uid=node_uid))
+ # and only one movement is returned by getMovementHistoryList
+ self.assertEquals(1, len(stool.getMovementHistoryList(
+ section_uid=self.section.getUid(),
+ node_uid=node_uid)))
+
+ # the account 'goods_sales' has a balance of -100
+ node_uid = self.account_module.goods_sales.getUid()
+ self.assertEquals(-100, stool.getInventory(
+ section_uid=self.section.getUid(),
+ node_uid=node_uid))
+
+ # the account 'stocks' has a balance of -100
+ node_uid = self.account_module.stocks.getUid()
+ self.assertEquals(-100, stool.getInventory(
+ section_uid=self.section.getUid(),
+ node_uid=node_uid))
+
+
+ def test_InventoryIndexingNodeDiffOnNode(self):
+ # Balance Transactions are indexed as Inventories.
+ transaction1 = self._makeOne(
+ start_date=DateTime(2006, 1, 1),
+ portal_type='Accounting Transaction',
+ simulation_state='delivered',
+ lines=(dict(source_value=self.account_module.receivable,
+ source_debit=100),
+ dict(source_value=self.account_module.stocks,
+ source_credit=100)))
+
+ balance = self.accounting_module.newContent(
+ portal_type='Balance Transaction',
+ destination_section_value=self.section,
+ start_date=DateTime(2006, 12, 31),
+ resource_value=self.currency_module.euro,)
+ balance.newContent(
+ portal_type='Balance Transaction Line',
+ destination_value=self.account_module.receivable,
+ destination_debit=150,)
+ balance.newContent(
+ portal_type='Balance Transaction Line',
+ destination_value=self.account_module.stocks,
+ destination_credit=90,)
+ balance.stop()
+ get_transaction().commit()
+ self.tic()
+
+ stool = self.portal.portal_simulation
+ # the account 'receivable' has a balance of 150
+ node_uid = self.account_module.receivable.getUid()
+ self.assertEquals(150, stool.getInventory(
+ section_uid=self.section.getUid(),
+ node_uid=node_uid))
+ # movement history list shows 2 movements, the initial with qty 100, and
+ # the balance with quantity 50
+
+ # the account 'stocks' has a balance of -100
+ node_uid = self.account_module.stocks.getUid()
+ self.assertEquals(-90, stool.getInventory(
+ section_uid=self.section.getUid(),
+ node_uid=node_uid))
+
+
+
class TestAccounting(ERP5TypeTestCase):
"""The first test for Accounting
More information about the Erp5-report
mailing list