[Erp5-report] r36624 nicolas.dumazet - in /erp5/trunk/products/ERP5: Tool/ tests/
nobody at svn.erp5.org
nobody at svn.erp5.org
Mon Jun 28 09:20:32 CEST 2010
Author: nicolas.dumazet
Date: Mon Jun 28 09:20:31 2010
New Revision: 36624
URL: http://svn.erp5.org?rev=36624&view=rev
Log:
extend getInventoryAssetPrice to compute asset prices
Fifo, Filo, WeightedAverage, MonthlyWeightedAverage and MovingAverage methods
are available
Modified:
erp5/trunk/products/ERP5/Tool/SimulationTool.py
erp5/trunk/products/ERP5/tests/testInventoryAPI.py
Modified: erp5/trunk/products/ERP5/Tool/SimulationTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Tool/SimulationTool.py?rev=36624&r1=36623&r2=36624&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Tool/SimulationTool.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Tool/SimulationTool.py [utf8] Mon Jun 28 09:20:31 2010
@@ -1209,6 +1209,7 @@ class SimulationTool(BaseTool):
date = inventory_date_line_dict['date']
non_date_value_dict = dict([(k, v) for k, v \
in inventory_date_line_dict.iteritems() if k != 'date'])
+
equal_date_query_list.append(
ComplexQuery(
ComplexQuery(operator='AND',
@@ -1579,24 +1580,59 @@ class SimulationTool(BaseTool):
security.declareProtected(Permissions.AccessContentsInformation,
'getInventoryAssetPrice')
def getInventoryAssetPrice(self, src__=0,
- simulation_period='', **kw):
+ simulation_period='',
+ valuation_method=None,
+ **kw):
"""
Same thing as getInventory but returns an asset
price rather than an inventory.
- """
- method = getattr(self,'get%sInventoryList' % simulation_period)
- kw['ignore_group_by'] = 1
- result = method( src__=src__, inventory_list=0, **kw)
- if src__ :
- return result
- total_result = 0.0
- if len(result) > 0:
+ If valuation method is None, returns the sum of total prices.
+
+ Else it should be a string, in:
+ Filo
+ Fifo
+ WeightedAverage
+ MonthlyWeightedAverage
+ MovingAverage
+ When using a specific valuation method, a resource_uid is expected
+ as well as one of (section_uid or node_uid).
+ """
+ if valuation_method is None:
+ method = getattr(self,'get%sInventoryList' % simulation_period)
+ kw['ignore_group_by'] = 1
+ result = method( src__=src__, inventory_list=0, **kw)
+ if src__ :
+ return result
+
+ if len(result) == 0:
+ return 0.0
+
+ total_result = 0.0
for result_line in result:
if result_line.total_price is not None:
total_result += result_line.total_price
- return total_result
+ return total_result
+
+ if valuation_method not in ('Fifo', 'Filo', 'WeightedAverage',
+ 'MonthlyWeightedAverage', 'MovingAverage'):
+ raise ValueError("Invalid valuation method: %s" % valuation_method)
+
+ assert 'node_uid' in kw or 'section_uid' in kw
+ sql_kw = self._generateSQLKeywordDict(**kw)
+
+ if 'section_uid' in kw:
+ # ignore internal movements
+ sql_kw['where_expression'] += ' AND ' \
+ 'stock.section_uid!=stock.mirror_section_uid'
+
+ result = self.Resource_zGetAssetPrice(
+ valuation_method=valuation_method,
+ **sql_kw)
+
+ if len(result) > 0:
+ return result[-1].total_asset_price
security.declareProtected(Permissions.AccessContentsInformation,
'getCurrentInventoryAssetPrice')
Modified: erp5/trunk/products/ERP5/tests/testInventoryAPI.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testInventoryAPI.py?rev=36624&r1=36623&r2=36624&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testInventoryAPI.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testInventoryAPI.py [utf8] Mon Jun 28 09:20:31 2010
@@ -1038,6 +1038,114 @@ class TestInventoryList(InventoryAPITest
checkInventory(line=3, type='Future', source=1, quantity=-9)
checkInventory(line=3, type='Future', destination=1, quantity=9)
+ def test_inventory_asset_price(self):
+ # examples from http://accountinginfo.com/study/inventory/inventory-120.htm
+ movement_list = [
+ (1, "Beginning Inventory", -700, 10),
+ (3, "Purchase", -100, 12),
+ (8, "Sale", 500, None),
+ (15, "Purchase", -600, 14),
+ (19, "Purchase", -200, 15),
+ (25, "Sale", 400, None),
+ (27, "Sale", 100, None),
+ ]
+ resource = self.getProductModule().newContent(
+ title='My resource',
+ portal_type='Product')
+ for m in movement_list:
+ self._makeMovement(resource_value=resource,
+ source_value=self.node,
+ destination_value=self.mirror_node,
+ start_date=DateTime('2000/1/%d 12:00 UTC' % m[0]),
+ title=m[1],
+ quantity=m[2],
+ price=m[3],
+ )
+
+ self._safeTic()
+ simulation_tool = self.getSimulationTool()
+ def valuate(method):
+ r = simulation_tool.getInventoryAssetPrice(
+ valuation_method=method,
+ resource_uid=resource.getUid(),
+ node_uid=self.node.getUid())
+ return round(r)
+
+
+ self.assertEquals(7895, valuate("MovingAverage"))
+ self.assertEquals(7200, valuate("Filo"))
+ self.assertEquals(8600, valuate("Fifo"))
+
+ def test_weighted_average_asset_price(self):
+ def h(quantity, total_price):
+ """
+ A small helper. Returns a dictionary
+ """
+ d = dict(quantity=quantity,
+ price=float(total_price)/quantity,
+ total_price=total_price)
+ return d
+ # one item per month:
+ # - movement_list: quantity is negative, it's incoming/purchase
+ # - after: quantity, total_price, and expected unit_price
+ # Data was extracted from existing ledger books
+ data = {
+ '2009/11':
+ dict(movement_list=[h(566, 259208),], after=h(566, 259208),),
+ '2009/12':
+ dict(movement_list=[h(600, 291600), h(-1135, 536164), ],
+ after=h(31, 14644)),
+ '2010/01':
+ dict(movement_list=[h(1200, 583200), ], after=h(1231, 597844)),
+ '2010/02':
+ dict(movement_list=[h(200, 97200), h(-1265, 614417), ],
+ after=h(166, 80627)),
+ '2010/03':
+ dict(movement_list=[], after=h(166, 80627)),
+ '2010/04':
+ dict(movement_list=[h(600, 291600), h(-680, 330437), ],
+ after=h(86, 41791)),
+ '2010/05':
+ dict(movement_list=[], after=h(86, 41791)),
+ '2010/06':
+ dict(movement_list=[], after=h(86, 41791)),
+ '2010/07':
+ dict(movement_list=[], after=h(86, 41791)),
+ '2010/08':
+ dict(movement_list=[h(4400, 2032800), h(-4364, 2018170), ],
+ after=h(122, 56420)),
+ '2010/09':
+ dict(movement_list=[], after=h(122, 56420)),
+ '2010/10':
+ dict(movement_list=[], after=h(122, 56420)),
+ '2010/11':
+ dict(movement_list=[h(1400, 646800), h(-1357, 626984), h(4, 1848)],
+ after=h(169, 78084)),
+ }
+
+ resource = self._makeProduct(title="Product for weighted average test")
+ resource_uid = resource.getUid()
+
+ # create all movements
+ for month, value in data.iteritems():
+ for mov in value['movement_list']:
+ d = DateTime('%s/15 15:00 UTC' % month)
+ self._makeMovement(start_date=d, resource_uid=resource_uid, **mov)
+
+ self._safeTic()
+
+ # and check
+ for cur in sorted(data)[1:]:
+ # month+1
+ to_date = DateTime("%s/1" % cur) + 31
+
+ result = self.getSimulationTool().getInventoryAssetPrice(
+ valuation_method="MonthlyWeightedAverage",
+ to_date=to_date,
+ resource_uid=resource.getUid(),
+ node_uid=self.node.getUid())
+ self.assertTrue(result is not None)
+ self.assertEquals(data[cur]['after']['total_price'], round(result))
class TestMovementHistoryList(InventoryAPITestCase):
"""Tests Movement history list methods.
@@ -2460,6 +2568,7 @@ class TestInventoryDocument(InventoryAPI
optimisation__=False,
mirror_uid=self.mirror_node.getUid())])
+
class BaseTestUnitConversion(InventoryAPITestCase):
QUANTITY_UNIT_DICT = {}
METRIC_TYPE_CATEGORY_LIST = ()
More information about the Erp5-report
mailing list