[Erp5-report] r31858 nicolas.dumazet - in /erp5/trunk/products/ERP5: Document/ Tool/ bootst...

nobody at svn.erp5.org nobody at svn.erp5.org
Thu Jan 21 08:07:15 CET 2010


Author: nicolas.dumazet
Date: Thu Jan 21 08:07:14 2010
New Revision: 31858

URL: http://svn.erp5.org?rev=31858&view=rev
Log:
improve Quantity Unit Conversions (1/2)


* Deprecate usage of "quantity" float field in quantity_unit category
* Introduce Quantity Unit Conversion Module instead for this behavior:
     Quantity Unit Conversion Definitions can be used to define site-wide
     quantity_units
* Let Resources define their own children Definitions:
     - adds a new tab in Product view
     - the definitions defined at a Resource level override the "global"
       definitions made in the Units Module

* Definitions are indexed in a special catalog table, similarly to Measures.
* Add an interaction workflow to take care of two reindexation needs:
   - when a local (resource-level) Definition is modified/created, the Product
     itself needs to be reindexed. This step is quite similar to
     measure_interaction_workflow
   - when a global (site-wide) Definition is modified, all Products need
     reindexing.

* SimulationTool API was cleaned up and unified.
   - getConvertedInventoryList is deprecated
   - quantity_unit and metric_type parameters are added to getInventory

* testResource is updated to use Unit Definitions instead of quantity fields
  of quantity_unit's

Added:
    erp5/trunk/products/ERP5/Document/QuantityUnitConversionDefinition.py
    erp5/trunk/products/ERP5/Document/QuantityUnitConversionGroup.py
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.catalog_keys.xml
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.xml
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.catalog_keys.xml
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.xml
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.catalog_keys.xml
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.xml
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.catalog_keys.xml
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.xml
Modified:
    erp5/trunk/products/ERP5/Document/Measure.py
    erp5/trunk/products/ERP5/Document/Resource.py
    erp5/trunk/products/ERP5/Tool/SimulationTool.py
    erp5/trunk/products/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventoryList.xml
    erp5/trunk/products/ERP5/bootstrap/erp5_core/bt/revision
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/revision
    erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_catalog_method_id_list
    erp5/trunk/products/ERP5/tests/testInventoryAPI.py
    erp5/trunk/products/ERP5/tests/testResource.py

Modified: erp5/trunk/products/ERP5/Document/Measure.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/Measure.py?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/Measure.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/Measure.py [utf8] Thu Jan 21 08:07:14 2010
@@ -31,12 +31,6 @@
 from Products.ERP5Type.Permissions import AccessContentsInformation
 from Products.ERP5Type.XMLMatrix import XMLMatrix
 from Products.ERP5.Variated import Variated
-
-
-def getQuantity(quantity_unit_value):
-  quantity = quantity_unit_value.getProperty('quantity')
-  if quantity is not None:
-    return float(quantity)
 
 
 class Measure(XMLMatrix):
@@ -139,7 +133,7 @@
     metric_type = self.getMetricType()
     if quantity_unit is not None and metric_type and \
         quantity_unit.getParentId() == metric_type.split('/', 1)[0]:
-      return getQuantity(quantity_unit)
+      return self.getQuantityUnitDefinitionRatio(quantity_unit)
 
   security.declareProtected(AccessContentsInformation, 'getConvertedQuantity')
   def getConvertedQuantity(self, variation_list=()):
@@ -168,19 +162,27 @@
   #  Cataloging.
 
   security.declareProtected(AccessContentsInformation, 'asCatalogRowList')
-  def asCatalogRowList(self):
+  def asCatalogRowList(self, quantity_unit_definition_dict):
     """
     Returns the list of rows to insert in the measure table of the catalog.
     Called by Resource.getMeasureRowList.
     """
-    quantity_unit = self.getConvertedQuantityUnit()
-    if not quantity_unit:
-      return ()
+    quantity_unit = self.getQuantityUnitValue()
+    metric_type = self.getMetricType()
+    if quantity_unit is None or not metric_type or \
+        quantity_unit.getParentId() != metric_type.split('/', 1)[0]:
+      return ()
+    quantity_unit_uid = quantity_unit.getUid()
+
     uid = self.getUid()
     resource = self.getResourceValue()
     resource_uid = resource.getUid()
     metric_type_uid = self.getMetricTypeUid()
     quantity = self.getQuantity()
+    try:
+      quantity_unit = quantity_unit_definition_dict[quantity_unit_uid][1]
+    except KeyError:
+      return ()
 
     # The only purpose of the defining a default measure explicitly is to
     # set a specific metric_type for the management unit.
@@ -196,8 +198,12 @@
       # so we simply return 1 row.
       if quantity is not None:
         quantity *= quantity_unit
-        if (not default or quantity ==
-            getQuantity(resource.getQuantityUnitValue())):
+        management_unit_uid = resource.getQuantityUnitUid()
+        management_unit_quantity = None
+        if management_unit_uid is not None:
+          management_unit_quantity = quantity_unit_definition_dict\
+                                        [management_unit_uid][1]
+        if (not default or quantity == management_unit_quantity):
           return (uid, resource_uid, '^', metric_type_uid, quantity),
       return ()
 

Added: erp5/trunk/products/ERP5/Document/QuantityUnitConversionDefinition.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/QuantityUnitConversionDefinition.py?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/Document/QuantityUnitConversionDefinition.py (added)
+++ erp5/trunk/products/ERP5/Document/QuantityUnitConversionDefinition.py [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,68 @@
+##############################################################################
+#
+# Copyright (c) 2008 Nexedi SARL and Contributors. All Rights Reserved.
+#
+# 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
+from Products.ERP5Type.Permissions import AccessContentsInformation
+from Products.ERP5Type.XMLObject import XMLObject
+
+
+class QuantityUnitConversionDefinition(XMLObject):
+  """
+    Quantity Unit Conversion Definition
+  """
+
+  meta_type = 'ERP5 Quantity Unit Conversion Definition'
+  portal_type = 'Quantity Unit Conversion Definition'
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(AccessContentsInformation)
+
+  # Declarative properties
+  property_sheets = ( PropertySheet.Base
+                    , PropertySheet.XMLObject
+                    , PropertySheet.CategoryCore
+                    , PropertySheet.Amount
+                    )
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'getTitle')
+  def getTitle(self):
+    """
+      Set a title that includes the Quantity Unit
+    """
+    default_title = self._baseGetTitle()
+
+    quantity_unit = self.getQuantityUnitValue()
+    if quantity_unit is not None:
+      # only the last part is relevant
+      return "%s Definition" % quantity_unit.getTitle()
+
+    return default_title
+

Added: erp5/trunk/products/ERP5/Document/QuantityUnitConversionGroup.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/QuantityUnitConversionGroup.py?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/Document/QuantityUnitConversionGroup.py (added)
+++ erp5/trunk/products/ERP5/Document/QuantityUnitConversionGroup.py [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,67 @@
+##############################################################################
+#
+# Copyright (c) 2008 Nexedi SARL and Contributors. All Rights Reserved.
+#
+# 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
+from Products.ERP5Type.Permissions import AccessContentsInformation
+from Products.ERP5Type.XMLObject import XMLObject
+
+
+class QuantityUnitConversionGroup(XMLObject):
+  """
+    Quantity Unit Conversion Group defined per-product.
+  """
+
+  meta_type = 'ERP5 Quantity Unit Conversion Group'
+  portal_type = 'Quantity Unit Conversion Group'
+
+  # Declarative security
+  security = ClassSecurityInfo()
+  security.declareObjectProtected(AccessContentsInformation)
+
+  # Declarative properties
+  property_sheets = ( PropertySheet.Base
+                    , PropertySheet.XMLObject
+                    , PropertySheet.CategoryCore
+                    , PropertySheet.Amount
+                    )
+
+  security.declareProtected(Permissions.AccessContentsInformation,
+                            'getTitle')
+  def getTitle(self):
+    """
+      Set a title that includes the Quantity Unit
+    """
+    default_title = self._baseGetTitle()
+
+    quantity_unit = self.getQuantityUnitValue()
+    if quantity_unit is not None:
+      return "%s Conversion Group" % quantity_unit.getParentValue().getTitle()
+
+    return default_title
+

Modified: erp5/trunk/products/ERP5/Document/Resource.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/Resource.py?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/Resource.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/Resource.py [utf8] Thu Jan 21 08:07:14 2010
@@ -794,12 +794,12 @@
       if management_unit == quantity_unit:
         return 1.0
       traverse = self.portal_categories['quantity_unit'].unrestrictedTraverse
-      quantity = float(traverse(quantity_unit).getProperty('quantity'))
+      quantity = self.getQuantityUnitDefinitionRatio(traverse(quantity_unit))
       if quantity_unit.split('/', 1)[0] != management_unit.split('/', 1)[0]:
         measure = self.getDefaultMeasure(quantity_unit)
         quantity /= measure.getConvertedQuantity(variation_list)
       else:
-        quantity /= float(traverse(management_unit).getProperty('quantity'))
+        quantity /= self.getQuantityUnitDefinitionRatio(traverse(management_unit))
       return quantity
 
     # Unit conversion
@@ -852,6 +852,88 @@
         if len(result) == 1:
           return result[0]
 
+    def _getGlobalQuantityUnitDefinitionDict(self):
+      # XXX this info could be cached, as it is the same for all Resources
+      result = {}
+      module = self.getPortalObject().quantity_unit_conversion_module
+      for definition_list in module.objectValues(portal_type= \
+          'Quantity Unit Conversion Group'):
+        standard_quantity_unit_uid = definition_list.getQuantityUnitUid()
+        if standard_quantity_unit_uid is None:
+          continue
+
+        result[standard_quantity_unit_uid] = (None, 1.0)
+        for definition in definition_list.objectValues(portal_type= \
+            'Quantity Unit Conversion Definition'):
+          unit_uid = definition.getQuantityUnitUid()
+          if unit_uid is None:
+            continue
+          quantity = definition.getQuantity()
+          if not quantity:
+            continue
+          result[unit_uid] = (definition.getUid(), quantity)
+
+      return result
+
+    def _getQuantityUnitDefinitionDict(self):
+      """
+      Returns a dictionary representing the Unit Definitions that hold
+      for the current resource.
+        Keys: quantity_unit categories uids.
+        Values: tuple (unit_definition_uid, quantity)
+          * unit_definition_uid can be None if the quantity_unit is defined
+            as a standard_quantity_unit (no Unit Conversion Definition defines
+            it, its definition comes from a Unit Conversion Group)
+          * quantity is a float, an amount, expressed in the
+            standard_quantity_unit for the base category of the quantity_unit.
+            For example, if mass/g is the global standard quantity_unit, all
+            definitions for mass/* will be expressed in grams.
+      """
+      global_definition_dict = self._getGlobalQuantityUnitDefinitionDict()
+
+      result = global_definition_dict.copy()
+      for definition_list in self.objectValues(portal_type= \
+          'Quantity Unit Conversion Group'):
+        standard_quantity_unit_uid = definition_list.getQuantityUnitUid()
+        if standard_quantity_unit_uid is None:
+          continue
+
+        reference_ratio = global_definition_dict[standard_quantity_unit_uid][1]
+        for definition in definition_list.objectValues(portal_type= \
+            'Quantity Unit Conversion Definition'):
+          unit_uid = definition.getQuantityUnitUid()
+          if unit_uid is None:
+            continue
+          quantity = definition.getQuantity()
+          if not quantity:
+            continue
+          result[unit_uid] = (definition.getUid(), quantity*reference_ratio)
+
+      return result
+
+    security.declareProtected(Permissions.AccessContentsInformation,
+                              'getQuantityUnitConversionDefinitionRowList')
+    def getQuantityUnitConversionDefinitionRowList(self):
+      """
+      Returns a list rows to insert in the quantity_unit_conversion table.
+      Used by z_catalog_quantity_unit_conversion_list.
+      """
+      # XXX If one wanted to add variation-specific Unit Conversion Definitions
+      #  he could use an approach very similar to the one used for Measure.
+      #  Just add a variation VARCHAR column in quantity_unit_conversion table
+      #  (defaulting as "^"). The column would contain the REGEX describing the
+      #  variation, exactly as Measure.
+      #  Resource_zGetInventoryList would then need expansion to match the
+      #  product variation vs the quantity_unit_conversion REGEX.
+
+      uid = self.getUid()
+      row_list = []
+      for unit_uid, value in self._getQuantityUnitDefinitionDict().iteritems():
+        definition_uid, quantity = value
+        row_list.append((definition_uid, uid, unit_uid, quantity))
+
+      return row_list
+
     security.declareProtected(Permissions.AccessContentsInformation,
                               'getMeasureRowList')
     def getMeasureRowList(self):
@@ -862,6 +944,8 @@
       quantity_unit_value = self.getQuantityUnitValue()
       if quantity_unit_value is None:
         return ()
+
+      quantity_unit_definition_dict = self._getQuantityUnitDefinitionDict()
 
       metric_type_map = {} # duplicate metric_type are not valid
 
@@ -875,7 +959,7 @@
       insert_list = []
       for measure in metric_type_map.itervalues():
         if measure is not None:
-          insert_list += measure.asCatalogRowList()
+          insert_list += measure.asCatalogRowList(quantity_unit_definition_dict)
 
       quantity_unit = quantity_unit_value.getCategoryRelativeUrl()
       if self.getDefaultMeasure(quantity_unit) is None:
@@ -884,7 +968,9 @@
             # At this point, we know there is no default measure and we must add
             # a row for the management unit, with the resource's uid as uid, and
             # a generic metric_type.
-            quantity = quantity_unit_value.getProperty('quantity')
+            quantity_unit_uid = quantity_unit_value.getUid()
+            quantity = quantity_unit_definition_dict[quantity_unit_uid][1]
+
             metric_type_uid = self.getPortalObject().portal_categories \
                                   .getCategoryUid(metric_type, 'metric_type')
             if quantity and metric_type_uid:
@@ -892,3 +978,28 @@
               insert_list += (uid, uid, '^', metric_type_uid, float(quantity)),
 
       return insert_list
+
+    def getQuantityUnitDefinitionRatio(self, quantity_unit_value):
+      """
+      get the ratio used to define the quantity unit quantity_unit_value.
+      If the Resource has a local Quantity Unit conversion Definition,
+      return the ratio from that Definition.
+      If not, fetch a Definition in the Global Module.
+      """
+      portal = self.getPortalObject()
+      quantity_unit_uid = quantity_unit_value.getUid()
+
+      ratio = None
+
+      deprecated_quantity = quantity_unit_value.getProperty('quantity')
+      if deprecated_quantity is not None:
+        warn('quantity field of quantity_unit categories is deprecated.' \
+           ' Please use Quantity Unit Conversion Definitions instead and' \
+           ' reset the value of this field.', DeprecationWarning)
+
+        ratio = float(deprecated_quantity)
+
+      query = self.ResourceModule_zGetQuantityUnitDefinitionRatio(
+                            quantity_unit_uid=quantity_unit_uid,
+                            resource_uid=self.getUid())
+      return query[0].quantity

Modified: erp5/trunk/products/ERP5/Tool/SimulationTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Tool/SimulationTool.py?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Tool/SimulationTool.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Tool/SimulationTool.py [utf8] Thu Jan 21 08:07:14 2010
@@ -53,6 +53,8 @@
 
 from Shared.DC.ZRDB.Results import Results
 from Products.ERP5Type.Utils import mergeZRDBResults
+
+from warnings import warn
 
 class SimulationTool(BaseTool):
     """
@@ -868,6 +870,10 @@
 
       precision - the precision used to round quantities and prices.
 
+      metric_type   - convert the results to a specific metric_type
+
+      quantity_unit - display results using this specific quantity unit
+
       **kw           -  if we want extended selection with more keywords (but
                         bad performance) check what we can do with
                         buildSQLQuery
@@ -893,9 +899,14 @@
       if len(result) > 0:
         if len(result) != 1:
           raise ValueError, 'Sorry we must have only one'
-        inventory = result[0].total_quantity
-        if inventory is not None:
-          total_result = inventory
+        result = result[0]
+
+        if hasattr(result, "converted_quantity"):
+          total_result = result.converted_quantity
+        else:
+          inventory = result.total_quantity
+          if inventory is not None:
+            total_result = inventory
 
       return total_result
 
@@ -983,7 +994,7 @@
                          selection_domain=None, selection_report=None,
                          statistic=0, inventory_list=1, 
                          precision=None, connection_id=None,
-                         quantity_unit=None, **kw):
+                         **kw):
       """
         Returns a list of inventories for a single or multiple
         resources on a single or multiple nodes, grouped by resource,
@@ -1018,6 +1029,34 @@
            on individual nodes/categories/payments.
          - 
       """
+      getCategory = self.getPortalObject().portal_categories.getCategoryUid
+
+      result_column_id_dict = {}
+
+      quantity_unit = kw.pop('quantity_unit', None)
+      quantity_unit_uid = None
+      if quantity_unit is not None:
+
+        if isinstance(quantity_unit, str):
+          quantity_unit_uid = getCategory(quantity_unit, 'quantity_unit')
+          if quantity_unit_uid is not None:
+            result_column_id_dict['converted_quantity'] = None
+        elif isinstance(quantity_unit, int) or isinstance(quantity_unit, float):
+          # quantity_unit used to be a numerical parameter..
+          raise ValueError('Numeric values for quantity_unit are not supported')
+
+
+      convert_quantity_result = False
+      metric_type = kw.pop('metric_type', None)
+      if metric_type is not None:
+        metric_type_uid = getCategory(metric_type, 'metric_type')
+
+        if metric_type_uid is not None:
+          convert_quantity_result = True
+          kw['metric_type_uid'] = Query(
+                                    metric_type_uid=metric_type_uid,
+                                    table_alias_list=(("measure", "measure"),))
+
       if src__:
         sql_source_list = []
       # If no group at all, give a default sort group by
@@ -1181,7 +1220,9 @@
                 selection_domain=selection_domain,
                 selection_report=selection_report, precision=precision,
                 inventory_list=inventory_list,
-                statistic=statistic, quantity_unit=quantity_unit,
+                statistic=statistic,
+                quantity_unit_uid=quantity_unit_uid,
+                convert_quantity_result=convert_quantity_result,
                 **inventory_stock_sql_kw)
               # Get delta inventory
               delta_inventory_line_list = self.Resource_zGetInventoryList(
@@ -1191,7 +1232,9 @@
                 selection_domain=selection_domain,
                 selection_report=selection_report, precision=precision,
                 inventory_list=inventory_list,
-                statistic=statistic, quantity_unit=quantity_unit,
+                statistic=statistic,
+                quantity_unit_uid=quantity_unit_uid,
+                convert_quantity_result=convert_quantity_result,
                 **stock_sql_kw)
               # Match & add initial and delta inventories
               if src__:
@@ -1217,12 +1260,9 @@
                       No group by criterion, regroup everything.
                     """
                     return 'dummy_key'
-                result_column_id_dict = {}
                 result_column_id_dict['inventory'] = None
                 result_column_id_dict['total_quantity'] = None
                 result_column_id_dict['total_price'] = None
-                if quantity_unit:
-                    result_column_id_dict['converted_quantity'] = None
                 def addLineValues(line_a=None, line_b=None):
                   """
                     Addition columns of 2 lines and return a line with same
@@ -1308,7 +1348,9 @@
                     selection_domain=selection_domain,
                     selection_report=selection_report, precision=precision,
                     inventory_list=inventory_list, connection_id=connection_id,
-                    statistic=statistic, quantity_unit=quantity_unit,
+                    statistic=statistic,
+                    quantity_unit_uid=quantity_unit_uid,
+                    convert_quantity_result=convert_quantity_result,
                     **stock_sql_kw)
         if src__:
           sql_source_list.append(result)
@@ -1318,28 +1360,22 @@
 
     security.declareProtected(Permissions.AccessContentsInformation,
                               'getConvertedInventoryList')
-    def getConvertedInventoryList(self, metric_type, quantity_unit=1,
-                                  simulation_period='', **kw):
+    def getConvertedInventoryList(self, simulation_period='', **kw):
       """
       Return list of inventory with a 'converted_quantity' additional column,
       which contains the sum of measurements for the specified metric type,
       expressed in the 'quantity_unit' unit.
 
-      metric_type   - category relative url
-      quantity_unit - int, float or category relative url
-      """
-      getCategory = self.getPortalObject().portal_categories.getCategoryValue
-
-      kw['metric_type_uid'] = Query(
-        metric_type_uid=getCategory(metric_type, 'metric_type').getUid(),
-        table_alias_list=(("measure", "measure"),))
-
-      if isinstance(quantity_unit, str):
-        quantity_unit = float(getCategory(quantity_unit, 'quantity_unit')
-                              .getProperty('quantity'))
+      metric_type   - category
+      quantity_unit - category
+      """
+
+      warn('getConvertedInventoryList is Deprecated, use ' \
+           'getInventory instead.', DeprecationWarning)
 
       method = getattr(self,'get%sInventoryList' % simulation_period)
-      return method(quantity_unit=quantity_unit, **kw)
+
+      return method(**kw)
 
     security.declareProtected(Permissions.AccessContentsInformation,
                               'getAllInventoryList')

Modified: erp5/trunk/products/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventoryList.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventoryList.xml?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventoryList.xml [utf8] (original)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Resource_zGetInventoryList.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -32,6 +32,12 @@
                         <value>
                           <dictionary>
                             <item>
+                                <key> <string>convert_quantity_result</string> </key>
+                                <value>
+                                  <dictionary/>
+                                </value>
+                            </item>
+                            <item>
                                 <key> <string>from_table_list</string> </key>
                                 <value>
                                   <dictionary>
@@ -113,7 +119,7 @@
                                 </value>
                             </item>
                             <item>
-                                <key> <string>quantity_unit</string> </key>
+                                <key> <string>quantity_unit_uid</string> </key>
                                 <value>
                                   <dictionary/>
                                 </value>
@@ -189,7 +195,8 @@
                             <string>precision</string>
                             <string>inventory_list</string>
                             <string>statistic</string>
-                            <string>quantity_unit</string>
+                            <string>convert_quantity_result</string>
+                            <string>quantity_unit_uid</string>
                             <string>stock_table_id</string>
                           </list>
                         </value>
@@ -224,7 +231,8 @@
 precision\r\n
 inventory_list\r\n
 statistic\r\n
-quantity_unit\r\n
+convert_quantity_result\r\n
+quantity_unit_uid\r\n
 stock_table_id=stock</string> </value>
         </item>
         <item>
@@ -269,18 +277,20 @@
 <dtml-if expr="precision is not None">\n
   SUM(ROUND(<dtml-var stock_table_id>.quantity, <dtml-var precision>)) AS inventory,\n
   SUM(ROUND(<dtml-var stock_table_id>.quantity, <dtml-var precision>)) AS total_quantity,\n
-<dtml-if quantity_unit>\n
-  SUM(ROUND(<dtml-var stock_table_id>.quantity * measure.quantity, <dtml-var precision>))\n
-  / <dtml-sqlvar quantity_unit type=float> AS converted_quantity,\n
-</dtml-if>\n
+  <dtml-if convert_quantity_result>\n
+    SUM(ROUND(<dtml-var stock_table_id>.quantity * measure.quantity \n
+      <dtml-if quantity_unit_uid> / quantity_unit_conversion.quantity</dtml-if>, <dtml-var precision>))\n
+    AS converted_quantity,\n
+  </dtml-if>\n
   SUM(ROUND(<dtml-var stock_table_id>.total_price, <dtml-var precision>)) AS total_price\n
 <dtml-else>\n
   SUM(<dtml-var stock_table_id>.quantity) AS inventory,\n
   SUM(<dtml-var stock_table_id>.quantity) AS total_quantity,\n
-<dtml-if quantity_unit>\n
-  ROUND(SUM(<dtml-var stock_table_id>.quantity * measure.quantity)\n
-        / <dtml-sqlvar quantity_unit type=float>, 12) AS converted_quantity,\n
-</dtml-if>\n
+  <dtml-if convert_quantity_result>\n
+    ROUND(SUM(<dtml-var stock_table_id>.quantity * measure.quantity\n
+      <dtml-if quantity_unit_uid> / quantity_unit_conversion.quantity</dtml-if>), 12)\n
+    AS converted_quantity,\n
+  </dtml-if>\n
   SUM(<dtml-var stock_table_id>.total_price) AS total_price\n
 </dtml-if>\n
 <dtml-if inventory_list>\n
@@ -324,6 +334,11 @@
   catalog, <dtml-var stock_table_id>\n
   <dtml-if section_filtered> INNER <dtml-else> LEFT </dtml-if>  \n
        JOIN catalog AS section ON (section.uid = <dtml-var stock_table_id>.section_uid)\n
+<dtml-if quantity_unit_uid>\n
+  LEFT JOIN quantity_unit_conversion ON \n
+    (quantity_unit_conversion.resource_uid = <dtml-var stock_table_id>.resource_uid\n
+    AND quantity_unit_conversion.quantity_unit_uid = <dtml-sqlvar quantity_unit_uid type=int>)\n
+</dtml-if>\n
 <dtml-in prefix="table" expr="from_table_list"> \n
   <dtml-if expr="table_key not in (\'catalog\', stock_table_id)">\n
   , <dtml-var table_item> AS <dtml-var table_key>\n
@@ -353,7 +368,7 @@
   AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_report, strict_membership=1)">\n
 </dtml-if>\n
 \n
-<dtml-if quantity_unit>\n
+<dtml-if convert_quantity_result>\n
   AND concat(<dtml-var stock_table_id>.variation_text,\'\\n\') REGEXP measure.variation\n
 </dtml-if>\n
 \n
@@ -410,18 +425,20 @@
 <dtml-if expr="precision is not None">\n
   SUM(ROUND(<dtml-var stock_table_id>.quantity, <dtml-var precision>)) AS inventory,\n
   SUM(ROUND(<dtml-var stock_table_id>.quantity, <dtml-var precision>)) AS total_quantity,\n
-<dtml-if quantity_unit>\n
-  SUM(ROUND(<dtml-var stock_table_id>.quantity * measure.quantity, <dtml-var precision>))\n
-  / <dtml-sqlvar quantity_unit type=float> AS converted_quantity,\n
-</dtml-if>\n
+  <dtml-if convert_quantity_result>\n
+    SUM(ROUND(<dtml-var stock_table_id>.quantity * measure.quantity \n
+      <dtml-if quantity_unit_uid> / quantity_unit_conversion.quantity</dtml-if>, <dtml-var precision>))\n
+    AS converted_quantity,\n
+  </dtml-if>\n
   SUM(ROUND(<dtml-var stock_table_id>.total_price, <dtml-var precision>)) AS total_price\n
 <dtml-else>\n
   SUM(<dtml-var stock_table_id>.quantity) AS inventory,\n
   SUM(<dtml-var stock_table_id>.quantity) AS total_quantity,\n
-<dtml-if quantity_unit>\n
-  ROUND(SUM(<dtml-var stock_table_id>.quantity * measure.quantity)\n
-        / <dtml-sqlvar quantity_unit type=float>, 12) AS converted_quantity,\n
-</dtml-if>\n
+  <dtml-if convert_quantity_result>\n
+    ROUND(SUM(<dtml-var stock_table_id>.quantity * measure.quantity\n
+      <dtml-if quantity_unit_uid> / quantity_unit_conversion.quantity</dtml-if>), 12)\n
+    AS converted_quantity,\n
+  </dtml-if>\n
   SUM(<dtml-var stock_table_id>.total_price) AS total_price\n
 </dtml-if>\n
 <dtml-if inventory_list>\n
@@ -465,6 +482,11 @@
   catalog, <dtml-var stock_table_id>\n
   <dtml-if section_filtered> INNER <dtml-else> LEFT </dtml-if>  \n
        JOIN catalog AS section ON (section.uid = <dtml-var stock_table_id>.section_uid)\n
+<dtml-if quantity_unit_uid>\n
+  LEFT JOIN quantity_unit_conversion ON \n
+    (quantity_unit_conversion.resource_uid = <dtml-var stock_table_id>.resource_uid\n
+    AND quantity_unit_conversion.quantity_unit_uid = <dtml-sqlvar quantity_unit_uid type=int>)\n
+</dtml-if>\n
 <dtml-in prefix="table" expr="from_table_list"> \n
   <dtml-if expr="table_key not in (\'catalog\', stock_table_id)">\n
   , <dtml-var table_item> AS <dtml-var table_key>\n
@@ -494,7 +516,7 @@
   AND <dtml-var "portal_selections.buildSQLExpressionFromDomainSelection(selection_report, strict_membership=1)">\n
 </dtml-if>\n
 \n
-<dtml-if quantity_unit>\n
+<dtml-if convert_quantity_result>\n
   AND concat(<dtml-var stock_table_id>.variation_text,\'\\n\') REGEXP measure.variation\n
 </dtml-if>\n
 \n

Modified: erp5/trunk/products/ERP5/bootstrap/erp5_core/bt/revision
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_core/bt/revision?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_core/bt/revision [utf8] (original)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_core/bt/revision [utf8] Thu Jan 21 08:07:14 2010
@@ -1,1 +1,1 @@
-1435
+1436

Added: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.catalog_keys.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.catalog_keys.xml?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.catalog_keys.xml (added)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.catalog_keys.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,5 @@
+<catalog_method>
+ <item key="sql_clear_catalog" type="int">
+  <value>1</value>
+ </item>
+</catalog_method>

Added: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.xml?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.xml (added)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_drop_quantity_unit_conversion.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,103 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <tuple>
+        <global name="SQL" module="Products.ZSQLMethods.SQL"/>
+        <tuple/>
+      </tuple>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_arg</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="Args" module="Shared.DC.ZRDB.Aqueduct"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_data</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>_keys</string> </key>
+                        <value>
+                          <list/>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>arguments_src</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>connection_id</string> </key>
+            <value> <string>erp5_sql_connection</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>z0_drop_quantity_unit_conversion</string> </value>
+        </item>
+        <item>
+            <key> <string>src</string> </key>
+            <value> <string>DROP TABLE IF EXISTS quantity_unit_conversion</string> </value>
+        </item>
+        <item>
+            <key> <string>template</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="__newobj__" module="copy_reg"/>
+                </klass>
+                <tuple>
+                  <global name="SQL" module="Shared.DC.ZRDB.DA"/>
+                </tuple>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>__name__</string> </key>
+                        <value> <string encoding="cdata"><![CDATA[
+
+<string>
+
+]]></string> </value>
+                    </item>
+                    <item>
+                        <key> <string>_vars</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>globals</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>raw</string> </key>
+                        <value> <string>DROP TABLE IF EXISTS quantity_unit_conversion</string> </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>

Added: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.catalog_keys.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.catalog_keys.xml?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.catalog_keys.xml (added)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.catalog_keys.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,5 @@
+<catalog_method>
+ <item key="sql_uncatalog_object" type="int">
+  <value>1</value>
+ </item>
+</catalog_method>

Added: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.xml?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.xml (added)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,122 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <tuple>
+        <global name="SQL" module="Products.ZSQLMethods.SQL"/>
+        <tuple/>
+      </tuple>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_arg</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="Args" module="Shared.DC.ZRDB.Aqueduct"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_data</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>uid</string> </key>
+                                <value>
+                                  <dictionary/>
+                                </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>_keys</string> </key>
+                        <value>
+                          <list>
+                            <string>uid</string>
+                          </list>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>arguments_src</string> </key>
+            <value> <string>uid</string> </value>
+        </item>
+        <item>
+            <key> <string>connection_id</string> </key>
+            <value> <string>erp5_sql_connection</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>z0_uncatalog_quantity_unit_conversion</string> </value>
+        </item>
+        <item>
+            <key> <string>src</string> </key>
+            <value> <string encoding="cdata"><![CDATA[
+
+DELETE FROM quantity_unit_conversion\n
+WHERE <dtml-sqltest uid op=eq type=int>
+
+]]></string> </value>
+        </item>
+        <item>
+            <key> <string>template</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="__newobj__" module="copy_reg"/>
+                </klass>
+                <tuple>
+                  <global name="SQL" module="Shared.DC.ZRDB.DA"/>
+                </tuple>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>__name__</string> </key>
+                        <value> <string encoding="cdata"><![CDATA[
+
+<string>
+
+]]></string> </value>
+                    </item>
+                    <item>
+                        <key> <string>_vars</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>globals</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>raw</string> </key>
+                        <value> <string encoding="cdata"><![CDATA[
+
+DELETE FROM quantity_unit_conversion\n
+WHERE <dtml-sqltest uid op=eq type=int>
+
+]]></string> </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>

Added: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.catalog_keys.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.catalog_keys.xml?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.catalog_keys.xml (added)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.catalog_keys.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,5 @@
+<catalog_method>
+ <item key="sql_catalog_object_list" type="int">
+  <value>1</value>
+ </item>
+</catalog_method>

Added: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.xml?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.xml (added)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,203 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <tuple>
+        <global name="SQL" module="Products.ZSQLMethods.SQL"/>
+        <tuple/>
+      </tuple>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_arg</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="Args" module="Shared.DC.ZRDB.Aqueduct"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_data</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>getQuantityUnitConversionDefinitionRowList</string> </key>
+                                <value>
+                                  <dictionary/>
+                                </value>
+                            </item>
+                            <item>
+                                <key> <string>uid</string> </key>
+                                <value>
+                                  <dictionary/>
+                                </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>_keys</string> </key>
+                        <value>
+                          <list>
+                            <string>uid</string>
+                            <string>getQuantityUnitConversionDefinitionRowList</string>
+                          </list>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>arguments_src</string> </key>
+            <value> <string>uid\r\n
+getQuantityUnitConversionDefinitionRowList\r\n
+</string> </value>
+        </item>
+        <item>
+            <key> <string>connection_id</string> </key>
+            <value> <string>erp5_sql_connection</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>z_catalog_quantity_unit_conversion_list</string> </value>
+        </item>
+        <item>
+            <key> <string>src</string> </key>
+            <value> <string encoding="cdata"><![CDATA[
+
+<dtml-let quantity_unit_conversion_dict="{}" value_list="[]">\n
+  <dtml-in getQuantityUnitConversionDefinitionRowList\n
+ prefix="loop">\n
+    <dtml-if loop_item>\n
+      <dtml-comment>\n
+       Make sure that we get no duplicates, and also aggregate the uids of the modified resources for deletion\n
+      </dtml-comment>\n
+      <dtml-in loop_item prefix="inner">\n
+        <dtml-call expr="quantity_unit_conversion_dict.setdefault(inner_item[1], {}).setdefault(inner_item[2], inner_item)">\n
+      </dtml-in>\n
+    </dtml-if>\n
+  </dtml-in>\n
+\n
+<dtml-if quantity_unit_conversion_dict>\n
+DELETE FROM `quantity_unit_conversion` WHERE\n
+  <dtml-sqltest "quantity_unit_conversion_dict.keys()" column="resource_uid" type="int" multiple>;\n
+\n
+\n
+  <dtml-var sql_delimiter>\n
+\n
+<dtml-in "quantity_unit_conversion_dict.values()" prefix="loop">\n
+  <dtml-call "value_list.extend(loop_item.values())">\n
+</dtml-in>\n
+\n
+INSERT INTO `quantity_unit_conversion`\n
+VALUES\n
+    <dtml-in "value_list" prefix="loop">\n
+(\n
+  <dtml-sqlvar expr="loop_item[0]" type="int" optional>,\n
+  <dtml-sqlvar expr="loop_item[1]" type="int">,\n
+  <dtml-sqlvar expr="loop_item[2]" type="int">,\n
+  <dtml-sqlvar expr="loop_item[3]" type="float">\n
+)\n
+<dtml-unless sequence-end>,</dtml-unless>\n
+    </dtml-in>\n
+</dtml-if>\n
+\n
+</dtml-let>
+
+]]></string> </value>
+        </item>
+        <item>
+            <key> <string>template</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="__newobj__" module="copy_reg"/>
+                </klass>
+                <tuple>
+                  <global name="SQL" module="Shared.DC.ZRDB.DA"/>
+                </tuple>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>__name__</string> </key>
+                        <value> <string encoding="cdata"><![CDATA[
+
+<string>
+
+]]></string> </value>
+                    </item>
+                    <item>
+                        <key> <string>_vars</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>globals</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>raw</string> </key>
+                        <value> <string encoding="cdata"><![CDATA[
+
+<dtml-let quantity_unit_conversion_dict="{}" value_list="[]">\n
+  <dtml-in getQuantityUnitConversionDefinitionRowList\n
+ prefix="loop">\n
+    <dtml-if loop_item>\n
+      <dtml-comment>\n
+       Make sure that we get no duplicates, and also aggregate the uids of the modified resources for deletion\n
+      </dtml-comment>\n
+      <dtml-in loop_item prefix="inner">\n
+        <dtml-call expr="quantity_unit_conversion_dict.setdefault(inner_item[1], {}).setdefault(inner_item[2], inner_item)">\n
+      </dtml-in>\n
+    </dtml-if>\n
+  </dtml-in>\n
+\n
+<dtml-if quantity_unit_conversion_dict>\n
+DELETE FROM `quantity_unit_conversion` WHERE\n
+  <dtml-sqltest "quantity_unit_conversion_dict.keys()" column="resource_uid" type="int" multiple>;\n
+\n
+\n
+  <dtml-var sql_delimiter>\n
+\n
+<dtml-in "quantity_unit_conversion_dict.values()" prefix="loop">\n
+  <dtml-call "value_list.extend(loop_item.values())">\n
+</dtml-in>\n
+\n
+INSERT INTO `quantity_unit_conversion`\n
+VALUES\n
+    <dtml-in "value_list" prefix="loop">\n
+(\n
+  <dtml-sqlvar expr="loop_item[0]" type="int" optional>,\n
+  <dtml-sqlvar expr="loop_item[1]" type="int">,\n
+  <dtml-sqlvar expr="loop_item[2]" type="int">,\n
+  <dtml-sqlvar expr="loop_item[3]" type="float">\n
+)\n
+<dtml-unless sequence-end>,</dtml-unless>\n
+    </dtml-in>\n
+</dtml-if>\n
+\n
+</dtml-let>
+
+]]></string> </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>

Added: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.catalog_keys.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.catalog_keys.xml?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.catalog_keys.xml (added)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.catalog_keys.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,5 @@
+<catalog_method>
+ <item key="sql_clear_catalog" type="int">
+  <value>1</value>
+ </item>
+</catalog_method>

Added: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.xml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.xml?rev=31858&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.xml (added)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/z_create_quantity_unit_conversion.xml [utf8] Thu Jan 21 08:07:14 2010
@@ -1,0 +1,125 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <tuple>
+        <global name="SQL" module="Products.ZSQLMethods.SQL"/>
+        <tuple/>
+      </tuple>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_arg</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="Args" module="Shared.DC.ZRDB.Aqueduct"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_data</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>_keys</string> </key>
+                        <value>
+                          <list/>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>_col</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>arguments_src</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>connection_id</string> </key>
+            <value> <string>erp5_sql_connection</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>z_create_quantity_unit_conversion</string> </value>
+        </item>
+        <item>
+            <key> <string>src</string> </key>
+            <value> <string>CREATE TABLE `quantity_unit_conversion` (\n
+  `uid` BIGINT UNSIGNED,\n
+  `resource_uid` BIGINT UNSIGNED NOT NULL,\n
+  `quantity_unit_uid` BIGINT UNSIGNED NOT NULL,\n
+  `quantity` REAL NOT NULL,\n
+  PRIMARY KEY (`resource_uid`, `quantity_unit_uid`),\n
+  KEY (`uid`)\n
+) TYPE=InnoDB;\n
+</string> </value>
+        </item>
+        <item>
+            <key> <string>template</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="__newobj__" module="copy_reg"/>
+                </klass>
+                <tuple>
+                  <global name="SQL" module="Shared.DC.ZRDB.DA"/>
+                </tuple>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>__name__</string> </key>
+                        <value> <string encoding="cdata"><![CDATA[
+
+<string>
+
+]]></string> </value>
+                    </item>
+                    <item>
+                        <key> <string>_vars</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>globals</string> </key>
+                        <value>
+                          <dictionary/>
+                        </value>
+                    </item>
+                    <item>
+                        <key> <string>raw</string> </key>
+                        <value> <string>CREATE TABLE `quantity_unit_conversion` (\n
+  `uid` BIGINT UNSIGNED,\n
+  `resource_uid` BIGINT UNSIGNED NOT NULL,\n
+  `quantity_unit_uid` BIGINT UNSIGNED NOT NULL,\n
+  `quantity` REAL NOT NULL,\n
+  PRIMARY KEY (`resource_uid`, `quantity_unit_uid`),\n
+  KEY (`uid`)\n
+) TYPE=InnoDB;\n
+</string> </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>

Modified: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/revision
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/revision?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/revision [utf8] (original)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/revision [utf8] Thu Jan 21 08:07:14 2010
@@ -1,1 +1,1 @@
-167
+168

Modified: erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_catalog_method_id_list
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_catalog_method_id_list?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_catalog_method_id_list [utf8] (original)
+++ erp5/trunk/products/ERP5/bootstrap/erp5_mysql_innodb_catalog/bt/template_catalog_method_id_list [utf8] Thu Jan 21 08:07:14 2010
@@ -12,6 +12,7 @@
 erp5_mysql_innodb/z0_drop_portal_ids
 erp5_mysql_innodb/z0_drop_predicate
 erp5_mysql_innodb/z0_drop_predicate_category
+erp5_mysql_innodb/z0_drop_quantity_unit_conversion
 erp5_mysql_innodb/z0_drop_record
 erp5_mysql_innodb/z0_drop_roles_and_users
 erp5_mysql_innodb/z0_drop_stock
@@ -27,6 +28,7 @@
 erp5_mysql_innodb/z0_uncatalog_movement
 erp5_mysql_innodb/z0_uncatalog_predicate
 erp5_mysql_innodb/z0_uncatalog_predicate_category
+erp5_mysql_innodb/z0_uncatalog_quantity_unit_conversion
 erp5_mysql_innodb/z0_uncatalog_stock
 erp5_mysql_innodb/z0_uncatalog_versioning
 erp5_mysql_innodb/z_SubCatalogQuery
@@ -44,6 +46,7 @@
 erp5_mysql_innodb/z_catalog_paths
 erp5_mysql_innodb/z_catalog_predicate_category_list
 erp5_mysql_innodb/z_catalog_predicate_list
+erp5_mysql_innodb/z_catalog_quantity_unit_conversion_list
 erp5_mysql_innodb/z_catalog_roles_and_users_list
 erp5_mysql_innodb/z_catalog_stock_list
 erp5_mysql_innodb/z_catalog_translation_list
@@ -63,6 +66,7 @@
 erp5_mysql_innodb/z_create_portal_ids
 erp5_mysql_innodb/z_create_predicate
 erp5_mysql_innodb/z_create_predicate_category
+erp5_mysql_innodb/z_create_quantity_unit_conversion
 erp5_mysql_innodb/z_create_record
 erp5_mysql_innodb/z_create_roles_and_users
 erp5_mysql_innodb/z_create_stock

Modified: erp5/trunk/products/ERP5/tests/testInventoryAPI.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testInventoryAPI.py?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testInventoryAPI.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testInventoryAPI.py [utf8] Thu Jan 21 08:07:14 2010
@@ -2377,24 +2377,81 @@
                   [x.path for x in self.resource.getInventoryList(
                                          optimisation__=False,
                                          mirror_uid=self.mirror_node.getUid())])
-    
-class TestUnitConversion(InventoryAPITestCase):
-  QUANTITY_UNIT_CATEGORIES = {
-    'unit': {'unit': 1, 'a_few': None},
-    'length': {'m': 1, 'in': .0254},
-    'mass': {'kg': 1, 't': 1000, 'g': .001},
+
+class BaseTestUnitConversion(InventoryAPITestCase):
+  QUANTITY_UNIT_DICT = {}
+  METRIC_TYPE_CATEGORY_LIST = ()
+
+  def setUpUnitDefinition(self):
+
+    unit_module = self.portal.quantity_unit_conversion_module
+    for base, t in self.QUANTITY_UNIT_DICT.iteritems():
+      standard, definition_dict = t
+
+      group = unit_module._getOb(base, None)
+      if group is None:
+        group = unit_module.newContent(
+                 id=base,
+                 portal_type='Quantity Unit Conversion Group',
+                 quantity_unit="%s/%s" % (base, standard),
+                 immediate_reindex=1 )
+
+      for unit, amount in definition_dict.iteritems():
+        if group._getOb(unit, None) is None:
+          group.newContent(
+             id=unit,
+             portal_type="Quantity Unit Conversion Definition",
+             quantity_unit="%s/%s" % (base, unit),
+             quantity=amount,
+             immediate_reindex=1)
+
+  def afterSetUp(self):
+    InventoryAPITestCase.afterSetUp(self)
+
+    self.setUpUnitDefinition()
+
+  def makeMovement(self, quantity, resource, *variation, **kw):
+    m = self._makeMovement(quantity=quantity, resource_value=resource,
+      source_value=self.node, destination_value=self.mirror_node, **kw)
+    if variation:
+      m.setVariationCategoryList(variation)
+      self._safeTic()
+
+  def convertedSimulation(self, metric_type, **kw):
+    return self.getSimulationTool().getInventory(
+      metric_type=metric_type, node_uid=self.node.getUid(),
+      **kw)
+
+  def getNeededCategoryList(self):
+    category_list = ['metric_type/' + c for c in self.METRIC_TYPE_CATEGORY_LIST]
+    for base, t in self.QUANTITY_UNIT_DICT.iteritems():
+      standard, definition_dict = t
+
+      quantity = 'quantity_unit/%s/' % base
+      category_list.append(quantity + standard)
+      category_list.extend(quantity + unit for unit in definition_dict)
+    category_list += InventoryAPITestCase.getNeededCategoryList(self)
+    return category_list
+
+class TestUnitConversion(BaseTestUnitConversion):
+  QUANTITY_UNIT_DICT = {
+    # base: (reference, dict_of_others)
+    'unit':   ('unit', dict(a_few=None)),
+    'length': ('m',    {'in': .0254}),
+    'mass':   ('kg',   dict(t=1000, g=.001)),
   }
-  METRIC_TYPE_CATEGORIES = (
+  METRIC_TYPE_CATEGORY_LIST = (
     'unit',
     'unit/0',
     'unit/1',
     'unit/2',
+    'unit/lot',
     'mass/net',
     'mass/nutr/lipid',
   )
 
   def afterSetUp(self):
-    InventoryAPITestCase.afterSetUp(self)
+    BaseTestUnitConversion.afterSetUp(self)
 
     self.resource.setQuantityUnitList(('unit/unit', 'length/in'))
     self.other_resource.setQuantityUnit('mass/g')
@@ -2433,54 +2490,176 @@
 
     self._safeTic()
 
-  def getNeededCategoryList(self):
-    category_list = ['metric_type/' + c for c in self.METRIC_TYPE_CATEGORIES]
-    for level1, level2 in self.QUANTITY_UNIT_CATEGORIES.iteritems():
-      quantity = 'quantity_unit/%s/' % level1
-      category_list.extend(quantity + unit for unit in level2)
-    category_list += InventoryAPITestCase.getNeededCategoryList(self)
-    return category_list
-
-  def createCategories(self):
-    InventoryAPITestCase.createCategories(self)
-    quantity_unit = self.getCategoryTool().quantity_unit
-    for quantity_id, unit_dict in self.QUANTITY_UNIT_CATEGORIES.iteritems():
-      quantity_value = quantity_unit[quantity_id]
-      for unit_id, unit_scale in unit_dict.iteritems():
-        if unit_scale is not None:
-          quantity_value[unit_id].setProperty('quantity', unit_scale)
-
   def testConvertedInventoryList(self):
-    def makeMovement(quantity, resource, *variation, **kw):
-      m = self._makeMovement(quantity=quantity, resource_value=resource,
-        source_value=self.node, destination_value=self.mirror_node, **kw)
-      if variation:
-        m.setVariationCategoryList(variation)
-        self._safeTic()
-
-    makeMovement(2, self.resource, 'colour/green', 'size/big')
-    makeMovement(789, self.other_resource)
-    makeMovement(-13, self.resource, 'colour/red', 'size/small',
+    self.makeMovement(2, self.resource, 'colour/green', 'size/big')
+    self.makeMovement(789, self.other_resource)
+    self.makeMovement(-13, self.resource, 'colour/red', 'size/small',
                  'industrial_phase/phase1', 'industrial_phase/phase2')
 
-    def simulation(metric_type, **kw):
-      return self.getSimulationTool().getConvertedInventoryList(
-        metric_type=metric_type, node_uid=self.node.getUid(),
-        ignore_group_by=1, inventory_list=0, **kw)[0].converted_quantity
 
     for i in range(3):
-      self.assertEquals(None, simulation('unit/%i' % i))
-
-    self.assertEquals(None, simulation('unit', simulation_period='Current'))
-    self.assertEquals(11, simulation('unit'))
-
-    self.assertEquals(11 * 123 - 789,
-                      simulation('mass/net', quantity_unit=.001))
+      self.assertEquals(None, self.convertedSimulation('unit/%i' % i))
+
+    self.assertEquals(None,
+                      self.convertedSimulation('unit',
+                                               simulation_period='Current'))
+    self.assertEquals(11, self.convertedSimulation('unit'))
+
+    self.assertEquals(11 * .123 - .789, self.convertedSimulation('mass/net'))
     self.assertEquals((11 * 123 - 789) / 1e6,
-                      simulation('mass/net', quantity_unit='mass/t'))
-
-    self.assertEquals(13 * .056 - 2 * .043, simulation('mass/nutr/lipid'))
-
+                      self.convertedSimulation('mass/net',
+                                               quantity_unit='mass/t'))
+
+    self.assertEquals(13 * .056 - 2 * .043,
+                      self.convertedSimulation('mass/nutr/lipid'))
+
+class TestUnitConversionDefinition(BaseTestUnitConversion):
+  QUANTITY_UNIT_DICT = {
+    # base: (reference, dict_of_others)
+    'unit':   ('unit', dict(lot=1000, pack=6)),
+  }
+  METRIC_TYPE_CATEGORY_LIST = (
+    'unit',
+  )
+
+  def afterSetUp(self):
+    BaseTestUnitConversion.afterSetUp(self)
+
+    # Aliases for readability
+    self.resource_bylot = self.resource
+    self.resource_bylot_overriding = self.other_resource
+
+    # And a third resource
+    self.resource_byunit = self.getProductModule().newContent(
+                                  title='Resource counted By Unit',
+                                  portal_type='Product')
+
+    self.resource_bypack = self.getProductModule().newContent(
+                                  title='Resource counted By Pack',
+                                  portal_type='Product')
+
+    self.resource_bylot.setQuantityUnit('unit/lot')
+    self.resource_bypack.setQuantityUnit('unit/pack')
+    self.resource_bylot_overriding.setQuantityUnit('unit/lot')
+    self.resource_byunit.setQuantityUnit('unit/unit')
+
+
+    self._safeTic()
+
+    base_unit = self.resource_bylot_overriding.newContent(
+                  portal_type='Quantity Unit Conversion Group',
+                  quantity_unit='unit/unit',
+                  immediate_reindex=1)
+
+
+    unit = base_unit.newContent(
+            portal_type='Quantity Unit Conversion Definition',
+            quantity_unit='unit/lot',
+            quantity=50,
+            immediate_reindex=1)
+
+    self._safeTic()
+
+  def testAggregatedReports(self):
+    self.makeMovement(-10, self.resource_bylot)
+    self.makeMovement(-1, self.resource_bypack)
+    self.makeMovement(2, self.resource_bylot_overriding)
+    self.makeMovement(500, self.resource_byunit)
+
+    # Always displayed as quantity*unit_ratio
+    self.assertEquals(10*1000 + 1*6 - 2*50 - 500*1,
+                      self.convertedSimulation('unit'))
+    self.assertEquals(10*1000 + 1*6 - 2*50 - 500*1,
+                      self.convertedSimulation('unit',
+                                               quantity_unit='unit/unit'))
+    self.assertEquals(10*1 + 1*(6*0.001) - 2*1 - 500*(1./1000),
+                      self.convertedSimulation('unit',
+                                               quantity_unit='unit/lot'))
+    # amounts are rounded on the 12th digit.
+    self.assertEquals(round(10*(1000./6) + 1*1 - 2*(50./6) - 500*(1./6), 12),
+                      self.convertedSimulation('unit',
+                                               quantity_unit='unit/pack'))
+
+  def testResourceConvertQuantity(self):
+    # First, test without local Unit Definitions
+    for resource in (self.resource_bylot,
+                     self.resource_bypack,
+                     self.resource_byunit):
+      # not_reference -> reference quantity
+      self.assertEquals(1000,
+                        resource.convertQuantity(1,
+                                                 "unit/lot",
+                                                 "unit/unit"))
+      # reference -> not_reference
+      self.assertEquals(1,
+                        resource.convertQuantity(1000,
+                                                 "unit/unit",
+                                                 "unit/lot"))
+      # not_reference -> not_reference
+      self.assertEquals(1*1000./6,
+                        resource.convertQuantity(1,
+                                                 "unit/lot",
+                                                 "unit/pack"))
+      self.assertEquals(1*6./1000,
+                        resource.convertQuantity(1,
+                                                 "unit/pack",
+                                                 "unit/lot"))
+
+    # then with local Unit definition
+    self.assertEquals(1*50,
+                      self.resource_bylot_overriding\
+                          .convertQuantity(1, "unit/lot", "unit/unit"))
+    self.assertEquals(1./50,
+                      self.resource_bylot_overriding\
+                          .convertQuantity(1, "unit/unit", "unit/lot"))
+    self.assertEquals(1*50./6,
+                      self.resource_bylot_overriding\
+                          .convertQuantity(1, "unit/lot", "unit/pack"))
+    self.assertEquals(1*6./50,
+                      self.resource_bylot_overriding\
+                          .convertQuantity(1, "unit/pack", "unit/lot"))
+
+  def testResourceConvertQuantityAfterGlobalChange(self):
+    """
+    after a change in a Global unit definition, definitions should get
+    reindexed.
+    """
+    # Before the global change, global definition reads 1000
+    self.assertEquals(1000,
+                      self.resource_bylot.convertQuantity(1,
+                                                           "unit/lot",
+                                                           "unit/unit"))
+    # which does not affect resources overriding the definition
+    self.assertEquals(1*50,
+                      self.resource_bylot_overriding\
+                          .convertQuantity(1, "unit/lot", "unit/unit"))
+
+    portal = self.getPortalObject()
+
+    lot_uid = portal.portal_categories.quantity_unit.unit.lot.getUid()
+    query = portal.portal_catalog(quantity_unit_uid=lot_uid,
+                                                  grand_parent_portal_type= \
+                                                    "Quantity Unit Conversion" \
+                                                    " Module",
+                                                  portal_type= \
+                                                    "Quantity Unit Conversion" \
+                                                    " Definition")
+    self.assertEquals(1, len(query))
+    query[0].getObject().setQuantity(500)
+
+    # this change triggers Resource reindexations. Wait for 'em!
+    transaction.commit()
+    self.tic()
+
+    # SQL tables should have been updated:
+    self.assertEquals(500,
+                      self.resource_bylot.convertQuantity(1,
+                                                           "unit/lot",
+                                                           "unit/unit"))
+    # without affecting resources that override the definition
+    self.assertEquals(1*50,
+                      self.resource_bylot_overriding\
+                          .convertQuantity(1, "unit/lot", "unit/unit"))
 
 def test_suite():
   suite = unittest.TestSuite()
@@ -2492,6 +2671,7 @@
   suite.addTest(unittest.makeSuite(TestTrackingList))
   suite.addTest(unittest.makeSuite(TestInventoryDocument))
   suite.addTest(unittest.makeSuite(TestUnitConversion))
+  suite.addTest(unittest.makeSuite(TestUnitConversionDefinition))
   return suite
 
 # vim: foldmethod=marker

Modified: erp5/trunk/products/ERP5/tests/testResource.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testResource.py?rev=31858&r1=31857&r2=31858&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testResource.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testResource.py [utf8] Thu Jan 21 08:07:14 2010
@@ -163,14 +163,26 @@
     if self.quantity_unit_gram is None:
       self.quantity_unit_gram = quantity_unit_weight.newContent(
                                       portal_type='Category',
-                                      quantity=0.001,
                                       id='gram')
     self.quantity_unit_kilo = quantity_unit_weight._getOb('kilo', None)
     if self.quantity_unit_kilo is None:
       self.quantity_unit_kilo = quantity_unit_weight.newContent(
                                       portal_type='Category',
-                                      quantity=1,
                                       id='kilo')
+
+    unit_conversion_module = self.portal.quantity_unit_conversion_module
+    weight_group = unit_conversion_module._getOb('weight', None)
+    if weight_group is None:
+      weight_group = unit_conversion_module.newContent(id='weight',
+                                  portal_type='Quantity Unit Conversion Group',
+                                  quantity_unit='weight/kilo')
+
+    gram_definition = weight_group._getOb('gram', None)
+    if gram_definition is None:
+      gram_definition = weight_group.newContent(id='gram',
+                              portal_type='Quantity Unit Conversion Definition',
+                              quantity_unit='weight/gram',
+                              quantity=0.001)
 
 
   def stepCreateResource(self, sequence=None, sequence_list=None, **kw):




More information about the Erp5-report mailing list