diff --git a/product/ERP5/Tool/SimulationTool.py b/product/ERP5/Tool/SimulationTool.py
index 5e01f5d543ff05fb426108682ee3d55d20c486a0..aa1400f220da4eed2c5d228b0d3b82e6c1fb5f3e 100644
--- a/product/ERP5/Tool/SimulationTool.py
+++ b/product/ERP5/Tool/SimulationTool.py
@@ -451,7 +451,8 @@ class SimulationTool (BaseTool):
       if kw.get('group_by_mirror_node',0):
         group_by_expression_list.append('%s.mirror_node_uid' % table)
       if len(group_by_expression_list):
-        group_by_expression_list.append('%s.resource_uid' % table) # Always group by resource
+        # Always group by resource
+        group_by_expression_list.append('%s.resource_uid' % table)
         sql_kw['group_by_expression'] = ', '.join(group_by_expression_list)
 
       sql_kw.update(self.portal_catalog.buildSQLQuery(**new_kw))
@@ -463,7 +464,8 @@ class SimulationTool (BaseTool):
                               'getInventory')
     def getInventory(self, src__=0, ignore_variation=0, standardise=0,
                      omit_simulation=0, omit_input=0, omit_output=0,
-                     selection_domain=None, selection_report=None, **kw):
+                     selection_domain=None, selection_report=None,
+                     precision=None, **kw):
       """
       Returns an inventory of a single or multiple resources on a single or
       multiple nodes as a single float value
@@ -513,8 +515,8 @@ class SimulationTool (BaseTool):
       section_filter  - only take rows in stock table which section_uid
                         matches section_filter
 
-      mirror_section_filter - only take rows in stock table which mirror_section_uid
-                              matches mirror_section_filter
+      mirror_section_filter - only take rows in stock table which
+                              mirror_section_uid matches mirror_section_filter
 
       variation_text -  only take rows in stock table with specified
                         variation_text.
@@ -568,6 +570,8 @@ class SimulationTool (BaseTool):
       group_by_sub_variation - (useless on getInventory, but useful on
                         getInventoryList)
 
+      precision - the precision used to round quantities and prices.
+
       **kw           -  if we want extended selection with more keywords (but
                         bad performance) check what we can do with
                         buildSqlQuery
@@ -591,7 +595,7 @@ class SimulationTool (BaseTool):
           standardise=standardise, omit_simulation=omit_simulation,
           omit_input=omit_input, omit_output=omit_output,
           selection_domain=selection_domain, selection_report=selection_report,
-          **sql_kw)
+          precision=precision, **sql_kw)
       if src__:
         return result
 
@@ -640,7 +644,8 @@ class SimulationTool (BaseTool):
                               'getInventoryList')
     def getInventoryList(self, src__=0, ignore_variation=0, standardise=0,
                          omit_simulation=0, omit_input=0, omit_output=0,
-                         selection_domain=None, selection_report=None, **kw):
+                         selection_domain=None, selection_report=None,
+                         precision=None, **kw):
       """
         Returns a list of inventories for a single or multiple
         resources on a single or multiple nodes, grouped by resource,
@@ -656,7 +661,8 @@ class SimulationTool (BaseTool):
                     standardise=standardise, omit_simulation=omit_simulation,
                     omit_input=omit_input, omit_output=omit_output,
                     selection_domain=selection_domain,
-                    selection_report=selection_report, **sql_kw)
+                    selection_report=selection_report, precision=precision,
+                    **sql_kw)
 
     security.declareProtected(Permissions.AccessContentsInformation,
                               'getCurrentInventoryList')
@@ -694,7 +700,8 @@ class SimulationTool (BaseTool):
                               'getInventoryStat')
     def getInventoryStat(self, src__=0, ignore_variation=0, standardise=0,
                          omit_simulation=0, omit_input=0, omit_output=0,
-                         selection_domain=None, selection_report=None, **kw):
+                         selection_domain=None, selection_report=None,
+                         precision=None, **kw):
       """
       getInventoryStat is the pending to getInventoryList in order to
       provide statistics on getInventoryList lines in ListBox such as:
@@ -708,7 +715,8 @@ class SimulationTool (BaseTool):
           standardise=standardise, omit_simulation=omit_simulation,
           omit_input=omit_input, omit_output=omit_output,
           selection_domain=selection_domain,
-          selection_report=selection_report, **sql_kw)
+          selection_report=selection_report,
+          precision=precision, **sql_kw)
       return result
 
     security.declareProtected(Permissions.AccessContentsInformation,
@@ -786,16 +794,10 @@ class SimulationTool (BaseTool):
     def getInventoryAssetPrice(self, src__=0, ignore_variation=0,
                                standardise=0, omit_simulation=0, omit_input=0,
                                omit_output=0, selection_domain=None,
-                               selection_report=None, **kw):
+                               selection_report=None, precision=None, **kw):
       """
       Same thing as getInventory but returns an asset
       price rather than an inventory.
-
-      TODO:
-        - Make sure getInventoryAssetPrice API can 
-	  support precision defition (ie. calculate the 
-	  sum of rounded values)
-
       """
       sql_kw = self._generateSQLKeywordDict(**kw)
       result = self.Resource_zGetInventory(
@@ -803,7 +805,7 @@ class SimulationTool (BaseTool):
           standardise=standardise, omit_simulation=omit_simulation,
           omit_input=omit_input, omit_output=omit_output,
           selection_domain=selection_domain, selection_report=selection_report,
-          **sql_kw)
+          precision=precision, **sql_kw)
       if src__ :
         return result
 
@@ -853,7 +855,7 @@ class SimulationTool (BaseTool):
     def getInventoryHistoryList(self, src__=0, ignore_variation=0,
                                 standardise=0, omit_simulation=0, omit_input=0,
                                 omit_output=0, selection_domain=None,
-                                selection_report=None, **kw):
+                                selection_report=None, precision=None, **kw):
       """
       Returns a time based serie of inventory values
       for a single or a group of resource, node, section, etc. This is useful
@@ -869,7 +871,8 @@ class SimulationTool (BaseTool):
                       standardise=standardise, omit_simulation=omit_simulation,
                       omit_input=omit_input, omit_output=omit_output,
                       selection_domain=selection_domain,
-                      selection_report=selection_report, **sql_kw)
+                      selection_report=selection_report, precision=precision,
+                      **sql_kw)
 
     security.declareProtected(Permissions.AccessContentsInformation,
                               'getInventoryHistoryChart')
@@ -877,7 +880,7 @@ class SimulationTool (BaseTool):
                                  standardise=0, omit_simulation=0,
                                  omit_input=0, omit_output=0,
                                  selection_domain=None,
-                                 selection_report=None, **kw):
+                                 selection_report=None, precision=None, **kw):
       """
       getInventoryHistoryChart is the pensing to getInventoryHistoryList
       to ease the rendering of time based graphs which show the evolution
@@ -892,7 +895,8 @@ class SimulationTool (BaseTool):
                     standardise=standardise, omit_simulation=omit_simulation,
                     omit_input=omit_input, omit_output=omit_output,
                     selection_domain=selection_domain,
-                    selection_report=selection_report, **sql_kw)
+                    selection_report=selection_report, precision=precision,
+                    **sql_kw)
 
     security.declareProtected(Permissions.AccessContentsInformation,
                               'getMovementHistoryList')
@@ -901,7 +905,7 @@ class SimulationTool (BaseTool):
                                omit_input=0, omit_output=0,
                                selection_domain=None, selection_report=None,
                                initial_running_total_quantity=0,
-                               initial_running_total_price=0,
+                               initial_running_total_price=0, precision=None,
                                **kw):
       """Returns a list of movements which modify the inventory
       for a single or a group of resource, node, section, etc.
@@ -921,14 +925,14 @@ class SimulationTool (BaseTool):
                                   initial_running_total_quantity,
                          initial_running_total_price=
                                   initial_running_total_price,
-                         **sql_kw)
+                         precision=precision, **sql_kw)
 
     security.declareProtected(Permissions.AccessContentsInformation,
                               'getMovementHistoryStat')
     def getMovementHistoryStat(self, src__=0, ignore_variation=0,
                                standardise=0, omit_simulation=0, omit_input=0,
                                omit_output=0, selection_domain=None,
-                               selection_report=None, **kw):
+                               selection_report=None, precision=None, **kw):
       """
       getMovementHistoryStat is the pending to getMovementHistoryList
       for ListBox stat
@@ -938,7 +942,7 @@ class SimulationTool (BaseTool):
           ignore_variation=ignore_variation, standardise=standardise,
           omit_simulation=omit_simulation, omit_input=omit_input,
           omit_output=omit_output, selection_domain=selection_domain,
-          selection_report=selection_report, **sql_kw)
+          selection_report=selection_report, precision=precision, **sql_kw)
 
     security.declareProtected(Permissions.AccessContentsInformation, 'getNextNegativeInventoryDate')
     def getNextNegativeInventoryDate(self, src__=0,
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventory.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventory.xml
index c5aaca1d023524a901199eeaba7550b853c98a26..65d9c4c34721e9282928edf25ec50a4c33f78e80 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventory.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventory.xml
@@ -101,6 +101,12 @@
                                   </dictionary>
                                 </value>
                             </item>
+                            <item>
+                                <key> <string>precision</string> </key>
+                                <value>
+                                  <dictionary/>
+                                </value>
+                            </item>
                             <item>
                                 <key> <string>section_filtered</string> </key>
                                 <value>
@@ -138,20 +144,21 @@
                         <key> <string>_keys</string> </key>
                         <value>
                           <list>
-                            <string>from_table_list</string>
-                            <string>where_expression</string>
-                            <string>order_by_expression</string>
-                            <string>selection_domain</string>
-                            <string>selection_report</string>
-                            <string>ignore_variation</string>
-                            <string>standardize</string>
-                            <string>omit_simulation</string>
-                            <string>omit_input</string>
-                            <string>omit_output</string>
-                            <string>section_filtered</string>
-                            <string>input_simulation_state</string>
-                            <string>output_simulation_state</string>
-                            <string>group_by_expression</string>
+<string>from_table_list</string>
+<string>where_expression</string>
+<string>order_by_expression</string>
+<string>selection_domain</string>
+<string>selection_report</string>
+<string>ignore_variation</string>
+<string>standardize</string>
+<string>omit_simulation</string>
+<string>omit_input</string>
+<string>omit_output</string>
+<string>section_filtered</string>
+<string>input_simulation_state</string>
+<string>output_simulation_state</string>
+<string>group_by_expression</string>
+<string>precision</string>
                           </list>
                         </value>
                     </item>
@@ -181,7 +188,8 @@ omit_output\r\n
 section_filtered\r\n
 input_simulation_state:list\r\n
 output_simulation_state:list\r\n
-group_by_expression</string> </value>
+group_by_expression\r\n
+precision</string> </value>
         </item>
         <item>
             <key> <string>cache_time_</string> </key>
@@ -222,9 +230,15 @@ group_by_expression</string> </value>
             <value> <string encoding="cdata"><![CDATA[
 
 SELECT\n
-  SUM(ROUND(stock.quantity,2)) AS inventory,\n
-  SUM(ROUND(stock.quantity,2)) AS total_quantity,\n
-  SUM(ROUND(stock.total_price,2)) AS total_price,\n
+<dtml-if expr="precision is not None">\n
+  SUM(ROUND(stock.quantity, <dtml-var precision>)) AS inventory,\n
+  SUM(ROUND(stock.quantity, <dtml-var precision>)) AS total_quantity,\n
+  SUM(ROUND(stock.total_price, <dtml-var precision>)) AS total_price,\n
+<dtml-else>\n
+  SUM(stock.quantity) AS inventory,\n
+  SUM(stock.quantity) AS total_quantity,\n
+  SUM(stock.total_price) AS total_price,\n
+</dtml-if>\n
   COUNT(DISTINCT node.title) AS node_title,\n
   COUNT(DISTINCT node.relative_url) AS node_relative_url,\n
   COUNT(DISTINCT section.title) AS section_title,\n
@@ -353,9 +367,15 @@ ORDER BY\n
                         <value> <string encoding="cdata"><![CDATA[
 
 SELECT\n
-  SUM(ROUND(stock.quantity,2)) AS inventory,\n
-  SUM(ROUND(stock.quantity,2)) AS total_quantity,\n
-  SUM(ROUND(stock.total_price,2)) AS total_price,\n
+<dtml-if expr="precision is not None">\n
+  SUM(ROUND(stock.quantity, <dtml-var precision>)) AS inventory,\n
+  SUM(ROUND(stock.quantity, <dtml-var precision>)) AS total_quantity,\n
+  SUM(ROUND(stock.total_price, <dtml-var precision>)) AS total_price,\n
+<dtml-else>\n
+  SUM(stock.quantity) AS inventory,\n
+  SUM(stock.quantity) AS total_quantity,\n
+  SUM(stock.total_price) AS total_price,\n
+</dtml-if>\n
   COUNT(DISTINCT node.title) AS node_title,\n
   COUNT(DISTINCT node.relative_url) AS node_relative_url,\n
   COUNT(DISTINCT section.title) AS section_title,\n
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetMovementHistoryList.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetMovementHistoryList.xml
index 75ee11a8a0d325dc6edef59ef6287e323f4b56db..fda172ea9fe4bb04dbb63c305d8709193c6f273e 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetMovementHistoryList.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetMovementHistoryList.xml
@@ -113,6 +113,12 @@
                                   </dictionary>
                                 </value>
                             </item>
+                            <item>
+                                <key> <string>precision</string> </key>
+                                <value>
+                                  <dictionary/>
+                                </value>
+                            </item>
                             <item>
                                 <key> <string>section_filtered</string> </key>
                                 <value>
@@ -150,22 +156,23 @@
                         <key> <string>_keys</string> </key>
                         <value>
                           <list>
-                            <string>from_table_list</string>
-                            <string>where_expression</string>
-                            <string>order_by_expression</string>
-                            <string>group_by_expression</string>
-                            <string>selection_domain</string>
-                            <string>selection_report</string>
-                            <string>ignore_variation</string>
-                            <string>standardize</string>
-                            <string>omit_simulation</string>
-                            <string>omit_input</string>
-                            <string>omit_output</string>
-                            <string>section_filtered</string>
-                            <string>initial_running_total_quantity</string>
-                            <string>initial_running_total_price</string>
-                            <string>input_simulation_state</string>
-                            <string>output_simulation_state</string>
+<string>from_table_list</string>
+<string>where_expression</string>
+<string>order_by_expression</string>
+<string>group_by_expression</string>
+<string>selection_domain</string>
+<string>selection_report</string>
+<string>ignore_variation</string>
+<string>standardize</string>
+<string>omit_simulation</string>
+<string>omit_input</string>
+<string>omit_output</string>
+<string>section_filtered</string>
+<string>initial_running_total_quantity</string>
+<string>initial_running_total_price</string>
+<string>input_simulation_state</string>
+<string>output_simulation_state</string>
+<string>precision</string>
                           </list>
                         </value>
                     </item>
@@ -606,7 +613,8 @@ section_filtered\r\n
 initial_running_total_quantity\r\n
 initial_running_total_price\r\n
 input_simulation_state:list\r\n
-output_simulation_state:list</string> </value>
+output_simulation_state:list\r\n
+precision</string> </value>
         </item>
         <item>
             <key> <string>cache_time_</string> </key>
@@ -662,8 +670,13 @@ SELECT\n
   catalog.uid as uid,\n
   catalog.relative_url as relative_url,\n
   stock.date AS date,\n
+<dtml-if expr="precision is not None">\n
+  ROUND(stock.quantity, <dtml-var precision>) AS total_quantity,\n
+  ROUND(stock.total_price, <dtml-var precision>) AS total_price,\n
+<dtml-else>\n
   stock.quantity AS total_quantity,\n
   stock.total_price AS total_price,\n
+</dtml-if>\n
   stock.variation_text AS variation_text,\n
   stock.simulation_state AS simulation_state,\n
   stock.mirror_section_uid AS mirror_section_uid,\n
@@ -814,8 +827,13 @@ SELECT\n
   catalog.uid as uid,\n
   catalog.relative_url as relative_url,\n
   stock.date AS date,\n
+<dtml-if expr="precision is not None">\n
+  ROUND(stock.quantity, <dtml-var precision>) AS total_quantity,\n
+  ROUND(stock.total_price, <dtml-var precision>) AS total_price,\n
+<dtml-else>\n
   stock.quantity AS total_quantity,\n
   stock.total_price AS total_price,\n
+</dtml-if>\n
   stock.variation_text AS variation_text,\n
   stock.simulation_state AS simulation_state,\n
   stock.mirror_section_uid AS mirror_section_uid,\n
diff --git a/product/ERP5/bootstrap/erp5_core/bt/revision b/product/ERP5/bootstrap/erp5_core/bt/revision
index 396054452291e2e07fcd9f33cd76ea228a88aa3a..c5a644422fb8f683632c43a9973c6f9bf3d5a12e 100644
--- a/product/ERP5/bootstrap/erp5_core/bt/revision
+++ b/product/ERP5/bootstrap/erp5_core/bt/revision
@@ -1 +1 @@
-220
\ No newline at end of file
+221
\ No newline at end of file
diff --git a/product/ERP5/tests/testInventoryAPI.py b/product/ERP5/tests/testInventoryAPI.py
index 7a362ae2da49ca8019749ea9cbce5732e06fd93a..adf08788448bf20fa0ee7ec7f75c581af6901eea 100644
--- a/product/ERP5/tests/testInventoryAPI.py
+++ b/product/ERP5/tests/testInventoryAPI.py
@@ -73,7 +73,7 @@ class InventoryAPITestCase(ERP5TypeTestCase):
     self.portal = self.getPortal()
     if not hasattr(self.portal, 'testing_folder'):
       self.portal.newContent(portal_type='Folder',
-                                              id='testing_folder')
+                            id='testing_folder')
     self.folder = self.portal.testing_folder
     
     self.section = self._makeOrganisation(title='Section')
@@ -472,6 +472,31 @@ class TestInventory(InventoryAPITestCase):
     self.assertEquals(getInventory(
                         section_uid=self.section.getUid()), 100)
   
+  def testPrecision(self):
+    # getInventory supports a precision= argument to specify the precision to
+    # round
+    getInventory = self.getSimulationTool().getInventory
+    getInventoryAssetPrice = self.getSimulationTool().getInventoryAssetPrice
+    self._makeMovement( quantity=0.1234, price=1 )
+    self.assertAlmostEquals(0.123,
+                getInventory(precision=3, node_uid=self.node.getUid()),
+                places=3)
+    self.assertAlmostEquals(0.123,
+             getInventoryAssetPrice(precision=3, node_uid=self.node.getUid()),
+             places=3)
+  
+  def testPrecisionAndFloatRoundingIssues(self):
+    # sum([0.1] * 10) != 1.0 but this is not a problem here
+    getInventory = self.getSimulationTool().getInventory
+    getInventoryAssetPrice = self.getSimulationTool().getInventoryAssetPrice
+    self._makeMovement( quantity=1, price=1 )
+    for i in range(10):
+      self._makeMovement( quantity=-0.1, price=1 )
+    self.assertEquals(0, getInventory(precision=2, node_uid=self.node.getUid()))
+    self.assertEquals(0, getInventoryAssetPrice(precision=2,
+                                                node_uid=self.node.getUid()))
+    
+
 class TestInventoryList(InventoryAPITestCase):
   """Tests getInventoryList methods.
   """
@@ -927,6 +952,44 @@ class TestMovementHistoryList(InventoryAPITestCase):
                             node_uid=self.node.getUid(),)
     self.assertEquals(2, len(mvt_history_list))
     self.assertEquals(0, sum([r.total_quantity for r in mvt_history_list]))
+ 
+  def testPrecision(self):
+    # getMovementHistoryList supports a precision= argument to specify the
+    # precision to round
+    getMovementHistoryList = self.getSimulationTool().getMovementHistoryList
+    self._makeMovement( quantity=0.1234, price=1 )
+    mvt_history_list = getMovementHistoryList(
+                            precision=2,
+                            node_uid=self.node.getUid())
+    self.assertEquals(1, len(mvt_history_list))
+    self.assertEquals(0.12, mvt_history_list[0].running_total_quantity)
+    self.assertEquals(0.12, mvt_history_list[0].running_total_price)
+    self.assertEquals(0.12, mvt_history_list[0].total_quantity)
+    self.assertEquals(0.12, mvt_history_list[0].total_price)
+    
+    mvt_history_list = getMovementHistoryList(
+                            precision=3,
+                            node_uid=self.node.getUid())
+    self.assertEquals(1, len(mvt_history_list))
+    self.assertEquals(0.123, mvt_history_list[0].running_total_quantity)
+    self.assertEquals(0.123, mvt_history_list[0].running_total_price)
+    self.assertEquals(0.123, mvt_history_list[0].total_quantity)
+    self.assertEquals(0.123, mvt_history_list[0].total_price)
+
+  def testPrecisionAndFloatRoundingIssues(self):
+    # sum([0.1] * 10) != 1.0 but this is not a problem here
+    getMovementHistoryList = self.getSimulationTool().getMovementHistoryList
+    date = DateTime()
+    self._makeMovement( quantity=1, price=1, start_date=date )
+    for i in range(10):
+      self._makeMovement( quantity=-0.1, price=1, start_date=date+i )
+    mvt_history_list = getMovementHistoryList(
+                            precision=2,
+                            node_uid=self.node.getUid(),
+                            sort_on=[['stock.date', 'ASC']])
+    self.assertEquals(11, len(mvt_history_list))
+    self.assertEquals(0, mvt_history_list[-1].running_total_quantity)
+    self.assertEquals(0, mvt_history_list[-1].running_total_price)
     
 class TestInventoryStat(InventoryAPITestCase):
   """Tests Inventory Stat methods.