From 8ceef6bd2b1b64d8308e65d611c79e8c777f82fb Mon Sep 17 00:00:00 2001
From: Julien Muchembled <jm@nexedi.com>
Date: Fri, 15 Oct 2010 17:45:38 +0000
Subject: [PATCH] Make testLegacyProductionOrder work with new amount generator

git-svn-id: https://svn.erp5.org/repos/public/erp5/sandbox/amount_generator@39253 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 .../DocumentTemplateItem/Transformation.py    | 309 ----------------
 .../TransformedResource.py                    | 334 ------------------
 .../bt/template_document_id_list              |   4 +-
 product/ERP5/Document/AssortedResource.py     |  15 +-
 product/ERP5/Document/SupplyLink.py           |  11 +-
 product/ERP5/Document/TransformedResource.py  |  63 ++--
 .../SQLCatalog_catalogTransformation.xml      |   5 +-
 product/ERP5/mixin/amount_generator.py        |  16 +-
 .../ERP5Legacy/Document/TransformationRule.py |  23 +-
 .../tests/testLegacyProductionOrder.py        |   3 +-
 10 files changed, 65 insertions(+), 718 deletions(-)
 delete mode 100644 bt5/erp5_simulation_legacy/DocumentTemplateItem/Transformation.py
 delete mode 100644 bt5/erp5_simulation_legacy/DocumentTemplateItem/TransformedResource.py

diff --git a/bt5/erp5_simulation_legacy/DocumentTemplateItem/Transformation.py b/bt5/erp5_simulation_legacy/DocumentTemplateItem/Transformation.py
deleted file mode 100644
index b328e680fd..0000000000
--- a/bt5/erp5_simulation_legacy/DocumentTemplateItem/Transformation.py
+++ /dev/null
@@ -1,309 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (c) 2002 Coramy SAS and Contributors. All Rights Reserved.
-#                    Thierry_Faucher <Thierry_Faucher@coramy.com>
-# Copyright (c) 2004-2009 Nexedi SA and Contributors. All Rights Reserved.
-#                    Romain Courteaud <romain@nexedi.com>
-#                    Łukasz Nowak <luke@nexedi.com>
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#
-##############################################################################
-
-import zope.interface
-
-from warnings import warn
-from AccessControl import ClassSecurityInfo
-
-from Products.ERP5Type import Permissions, PropertySheet, interfaces
-from Products.ERP5Type.XMLObject import XMLObject
-
-from Products.ERP5.Variated import Variated
-
-from Products.ERP5.Document.Predicate import Predicate
-
-from Products.CMFCategory.Renderer import Renderer
-from Products.ERP5.AggregatedAmountList import AggregatedAmountList
-
-from zLOG import LOG, WARNING
-
-class Transformation(XMLObject, Predicate, Variated):
-    """
-      Build of material - contains a list of transformed resources
-
-      Use of default_resource... (to define the variation range,
-      to ...)
-
-      XXX Transformation works only for a maximum of 3 variation base category...
-      Matrixbox must be rewritten for a clean implementation of n base category
-
-    """
-    meta_type = 'ERP5 Transformation'
-    portal_type = 'Transformation'
-
-    # Declarative security
-    security = ClassSecurityInfo()
-    security.declareObjectProtected(Permissions.AccessContentsInformation)
-
-    # Declarative properties
-    property_sheets = ( PropertySheet.Base
-                      , PropertySheet.XMLObject
-                      , PropertySheet.CategoryCore
-                      , PropertySheet.DublinCore
-                      , PropertySheet.VariationRange
-                      , PropertySheet.Predicate
-                      , PropertySheet.Comment
-                      , PropertySheet.Reference
-                      , PropertySheet.Version
-                      #, PropertySheet.Resource
-                      , PropertySheet.TransformedResource
-                      , PropertySheet.Path
-                      , PropertySheet.Transformation
-                      )
-
-    # Declarative interfaces
-    zope.interface.implements(interfaces.IVariated, 
-                              interfaces.IAmountGenerator
-                              )
-
-
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              'updateVariationCategoryList')
-    def updateVariationCategoryList(self):
-      """
-        Check if variation category list of the resource has changed and update
-        transformation and transformation line
-      """
-      self.setVariationBaseCategoryList(self.getVariationBaseCategoryList())
-      transformation_line_list = self.contentValues()
-      for transformation_line in transformation_line_list:
-        transformation_line.updateVariationCategoryList()
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              'getVariationRangeBaseCategoryList')
-    def getVariationRangeBaseCategoryList(self):
-      """
-        Returns possible variation base_category ids of the
-        default resource which can be used as variation axis
-        in the transformation.
-      """
-      resource = self.getResourceValue()
-      if resource is not None:
-        result = resource.getVariationBaseCategoryList()
-      else:
-        # XXX result = self.getBaseCategoryIds()
-        # Why calling this method ?
-        # Get a global variable which define a list of variation base category
-        result = self.getPortalVariationBaseCategoryList()
-      return result
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              'getVariationRangeBaseCategoryItemList')
-    def getVariationRangeBaseCategoryItemList(self, display_id='getTitleOrId', **kw):
-        """
-          Returns possible variations of the transformation
-          as a list of tuples (id, title). This is mostly
-          useful in ERP5Form instances to generate selection
-          menus.
-        """
-        return self.portal_categories.getItemList(
-                              self.getVariationRangeBaseCategoryList(),
-                              display_id=display_id, **kw)
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              'getVariationRangeCategoryItemList')
-    def getVariationRangeCategoryItemList(self, base_category_list=(),
-                                          omit_individual_variation=0,
-                                          display_base_category=1, **kw):
-        """
-          Returns possible variation category values for the
-          transformation according to the default resource.
-          Possible category values are provided as a list of
-          tuples (id, title). This is mostly
-          useful in ERP5Form instances to generate selection
-          menus.
-          User may want to define generic transformation without
-          any defined resource.
-        """
-        if base_category_list is ():
-          base_category_list = self.getVariationBaseCategoryList()
-
-        resource = self.getResourceValue()
-        if resource is not None:
-          result = resource.getVariationCategoryItemList(
-                        base_category_list=base_category_list,
-                        omit_individual_variation=omit_individual_variation,
-                        display_base_category=display_base_category,**kw)
-        else:
-          # No resource is define on transformation. 
-          # We want to display content of base categories
-          result = self.portal_categories.getCategoryChildTitleItemList(
-                         base_category_list, base=1, display_none_category=0)
-        return result
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              'setVariationBaseCategoryList')
-    def setVariationBaseCategoryList(self, value):
-      """
-        Define the possible base categories and reindex object
-      """
-      self._setVariationBaseCategoryList(value)
-      self.reindexObject()
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              'getVariationCategoryItemList')
-    def getVariationCategoryItemList(self, base_category_list=(), base=1,
-                                     display_id='title',
-                                     current_category=None,
-                                     **kw):
-      """
-        Returns the list of possible variations
-        XXX Copied and modified from Variated
-        Result is left display.
-      """
-      variation_category_item_list = []
-      if base_category_list == ():
-        base_category_list = self.getVariationBaseCategoryList()
-
-      category_renderer = Renderer(
-                             is_right_display=0,
-                             display_none_category=0, base=base,
-                             current_category=current_category,
-                             display_id='logical_path', **kw)
-
-      for base_category in base_category_list:
-        variation_category_list = self.getVariationCategoryList(
-                                            base_category_list=[base_category])
-
-        category_list = []
-        object_list = []
-        for variation_category in variation_category_list:
-          resource = self.portal_categories.resolveCategory(variation_category)
-          if resource.getPortalType() == 'Category':
-            category_list.append(resource)
-          else:
-            object_list.append(resource)
-
-        variation_category_item_list.extend(category_renderer.\
-                                              render(category_list))
-
-        variation_category_item_list.extend(Renderer(
-                               is_right_display=0,
-                               base_category=base_category,
-                               display_none_category=0, base=base,
-                               current_category=current_category,
-                               display_id=display_id,**kw).\
-                                                 render(object_list))
-      return variation_category_item_list
-
-    def updateAggregatedAmountList(self, context, **kw):
-      raise NotImplementedError, 'need?'
-
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              'getAggregatedAmountList')
-    def getAggregatedAmountList(self, context=None, REQUEST=None,
-                                trade_phase_list=None,
-                                # obsolete, use trade_phase_list instead
-                                ind_phase_url_list=None,
-                                rejected_resource_uid_list=None,
-                                **kw):
-      """
-        getAggregatedAmountList returns an AggregatedAmountList which
-        can be used either to do some calculation (ex. price, BOM)
-        or to display a detailed view of a transformation.
-      """
-      if isinstance(context, list):
-          context = context[0]
-      if context is None:
-        warn("Calling Transformation.getAggregatedAmountList without context " \
-             "is wrong. Context should be an Amount defining the resource to " \
-             "produce", DeprecationWarning)
-        from Products.ERP5Type.Document import newTempAmount
-        context = newTempAmount(self, "deprecated_usage")
-        context.setResourceValue(self.getResourceValue())
-        context.setQuantity(1.0)
-
-
-      # A list of functions taking a transformation_line as sole argument
-      # and returning True iif the line should be kept in the result
-      filter_list = []
-
-      # Get only lines related to a precise trade_phase
-      if trade_phase_list is not None:
-        def trade_phase_filter(line):
-          return line.getTradePhase() in trade_phase_list
-
-        filter_list.append(trade_phase_filter)
-
-      # Get only lines related to a precise industrial_phase
-      if ind_phase_url_list is not None:
-        LOG("Transformation", WARNING, "ind_phase_list is obsolete")
-        def industrial_phase_filter(line):
-          ind_ph = line.getIndustrialPhaseValue()
-          if ind_ph is not None:
-            return ind_ph.getRelativeUrl() in ind_phase_url_list
-          return False
-
-        filter_list.append(industrial_phase_filter)
-
-      # Filter lines with resource we do not want to see
-      if rejected_resource_uid_list is not None:
-        def rejected_uid_filter(line):
-          return line.getResourceUid() not in rejected_resource_uid_list
-
-        filter_list.append(rejected_uid_filter)
-
-      def line_is_included(line):
-        # XXX > 2.5 : all(f(line) for f in filter_list)
-        for filterr in filter_list:
-          if not filterr(line):
-            return False
-        return True
-
-      # First we need to get the list of transformations which this
-      # transformation depends on
-      # At this moment, we only consider 1 dependency
-      template_transformation_list = self.getSpecialiseValueList()
-
-      # Browse all involved transformations and create one line per
-      # line of transformation
-      # Currently, we do not consider abstractions, we just add
-      # whatever we find in all transformations
-      result = AggregatedAmountList()
-      for transformation in ([self] + template_transformation_list):
-        for transformation_line in transformation.objectValues():
-          # Browse each transformed or assorted resource of the current
-          # transformation
-          if line_is_included(transformation_line):
-            try:
-              line_result = transformation_line.getAggregatedAmountList(context)
-            except KeyError:
-              # KeyError is raised by TransformedResource.getAggregatedAmountList
-              # in case of misconfiguration of a Cell.
-              # Just ignore the line
-              pass
-            else:
-              result.extend(line_result)
-
-      return result
diff --git a/bt5/erp5_simulation_legacy/DocumentTemplateItem/TransformedResource.py b/bt5/erp5_simulation_legacy/DocumentTemplateItem/TransformedResource.py
deleted file mode 100644
index d3991ab213..0000000000
--- a/bt5/erp5_simulation_legacy/DocumentTemplateItem/TransformedResource.py
+++ /dev/null
@@ -1,334 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (c) 2002, 2004 Nexedi SARL and Contributors. All Rights Reserved.
-#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
-#                    Romain Courteaud <romain@nexedi.com>
-#
-# WARNING: This program as such is intended to be used by professional
-# programmers who take the whole responsability of assessing all potential
-# consequences resulting from its eventual inadequacies and bugs
-# End users who are looking for a ready-to-use solution with commercial
-# garantees and support are strongly adviced to contract a Free Software
-# Service Company
-#
-# This program is Free Software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#
-##############################################################################
-import zope.interface
-
-from warnings import warn
-from AccessControl import ClassSecurityInfo
-
-from Products.ERP5Type import Permissions, PropertySheet, interfaces
-from Products.ERP5Type.XMLObject import XMLObject
-from Products.ERP5Type.XMLMatrix import XMLMatrix
-
-from Products.ERP5.Document.Amount import Amount
-from Products.ERP5.AggregatedAmountList import AggregatedAmountList
-
-from Products.ERP5.Document.Predicate import Predicate
-
-class TransformedResource(Predicate, XMLObject, XMLMatrix, Amount):
-    """
-        TransformedResource defines which
-        resource is being transformed
-
-        - variation
-        - quantity
-
-        Maybe defined by mapped values inside the transformed resource
-
-      XXX Transformation works only for a miximum of 3 variation base category...
-      Matrixbox must be rewrite for a clean implementation of n base category
-
-
-    """
-
-    meta_type = 'ERP5 Transformed Resource'
-    portal_type = 'Transformed Resource'
-
-    # Declarative security
-    security = ClassSecurityInfo()
-    security.declareObjectProtected(Permissions.AccessContentsInformation)
-
-    # Declarative properties
-    property_sheets = ( PropertySheet.Base
-                      , PropertySheet.SimpleItem
-                      , PropertySheet.CategoryCore
-                      , PropertySheet.Amount
-                      , PropertySheet.Reference
-                      , PropertySheet.TransformedResource
-                      )
-
-    # Declarative interfaces
-    zope.interface.implements(interfaces.IAmountGenerator,)
-
-    ### Variation matrix definition
-    #
-    security.declareProtected(Permissions.AccessContentsInformation, 
-                              'updateVariationCategoryList')
-    def updateVariationCategoryList(self):
-      """
-        Check if variation category list of the resource changed and 
-        update transformed resource by doing a set cell range
-      """
-      self.setQVariationBaseCategoryList(self.getQVariationBaseCategoryList())
-      self.setVVariationBaseCategoryList(self.getVVariationBaseCategoryList())
-
-    security.declareProtected(Permissions.ModifyPortalContent, 
-                              '_setQVariationBaseCategoryList')
-    def _setQVariationBaseCategoryList(self, value):
-      """
-        Defines the possible base categories which Quantity value (Q)
-        variate on
-      """
-      self._baseSetQVariationBaseCategoryList(value)
-      self._updateCellRange('quantity')
-
-    security.declareProtected(Permissions.ModifyPortalContent, 
-                              'setQVariationBaseCategoryList')
-    def setQVariationBaseCategoryList(self, value):
-      """
-        Defines the possible base categories which Quantity value (Q)
-        variate on and reindex the object
-      """
-      self._setQVariationBaseCategoryList(value)
-      self.reindexObject()
-
-    security.declareProtected(Permissions.ModifyPortalContent, 
-                              '_setVVariationBaseCategoryList')
-    def _setVVariationBaseCategoryList(self, value):
-      """
-        Defines the possible base categories which Variation value (V)
-        variate on
-      """
-      self._baseSetVVariationBaseCategoryList(value)
-      self._updateCellRange('variation')
-
-    security.declareProtected(Permissions.ModifyPortalContent, 
-                              'setVVariationBaseCategoryList')
-    def setVVariationBaseCategoryList(self, value):
-      """
-        Defines the possible base categories which Variation value (V)
-        variate on and reindex the object
-      """
-      self._setVVariationBaseCategoryList(value)
-      self.reindexObject()
-
-    def updateAggregatedAmountList(self, context, **kw):
-      raise NotImplementedError('TODO')
-
-    security.declareProtected(Permissions.AccessContentsInformation, 
-                              'getAggregatedAmountList')
-    def getAggregatedAmountList(self, context, REQUEST=None, **kw):
-      """
-        Get all interesting amount value and return AggregatedAmountList
-      """
-      # Create the result object
-      aggregated_amount_list = AggregatedAmountList()
-      test_result = self.test(context)
-      if test_result:
-        # The line must match the context
-        # If no predicate is defined on line, the result of the test 
-        # must be true
-        # Create temporary object to store amount
-        parent = self.getParentValue()
-        # Be careful: this id must be unique, and change when the context is
-        # changing. Failure to do so exposes to possible erroneous cache hits
-        # for physical path based caching.
-        tmp_id = '_'.join((parent.getId(), self.getId(), context.getId()))
-        tmp_amount = parent.newContent(id=tmp_id,
-                        temp_object=1, portal_type=self.getPortalType())
-        # Create error string
-        error_string = ''
-        # Add resource relation
-        resource = self.getDefaultResourceValue()
-        if resource is not None:
-          tmp_amount.setResourceValue(resource)
-        else:
-          error_string += 'No resource defined on %s' % self.getRelativeUrl()
-        # First, we set initial values for quantity and variation
-        # Currently, we only consider discrete variations
-        # Continuous variations will be implemented in a future version 
-        # of ERP5
-        # Set quantity unit
-        quantity_unit = self.getQuantityUnit()
-        if quantity_unit is not None:
-          tmp_amount.setQuantityUnitValue(quantity_unit)
-        # Set efficiency
-        efficiency =  self.getEfficiency()
-        if efficiency is None or efficiency is '' or efficiency == 0.0:
-          efficiency = 1.0
-        else:
-          efficiency = float(efficiency)
-### current get quantity comportment exemple ###
-# We define on transformation line:
-#   default_quantity = q
-#   quantity matrix
-#     |   Child | Child/32 | Child/34 | Men | Women |
-#     |   a     |          |   b      | c   |       |
-# Result from getAggregatedAmountList:
-#               context   |    quantity
-#              _________________________
-#               Child     |       a
-#               Child/32  |       a      => acquired from Child
-#               Child/34  |       a or b => we do not know which cell will be choosed
-#               Child/36  |       a      => acquired from Child 
-#               Men       |       c
-#               Women     |       Error  => no cell found
-#               noContext |       Error  => cell exist, but no context given
-
-### comportment that JPS want ?? ###
-# We define on transformation line:
-#   default_quantity = q
-#   quantity matrix
-#     |   Child | Child/32 | Child/34 | Men | Women |
-#     |   a     |          |   b      | c   |       |
-# Result from getAggregatedAmountList:
-#               context   |    quantity
-#              _________________________
-#               Child     |       a
-#               Child/32  |       a      => acquired from Child
-#               Child/34  |       a or b => we do not know which cell will be choosed
-#               Child/36  |       Error  => no such key in matrixbox cell range
-#               Men       |       c
-#               Women     |       Error  => no cell found
-#               noContext |       Error  => cell exist, but no context given
-
-# futur cool get quantity comportment exemple 
-# We define on transformation line:
-#   default_quantity = q
-#   quantity matrix
-#     |   Child | Child/32 | Child/34 | Men | Women |
-#     |   a     |          |   b      | c   |       |
-# Result from getAggregatedAmountList:
-#               context   |    quantity
-#              _________________________
-#               Child     |       a
-#               Child/32  |       a      => acquired from Child
-#               Child/34  |       b      =>   test method must return a priority to choose between Child and Child/34
-#               Child/36  |       Error  => no such key in matrixbox cell range
-#               Men       |       c
-#               Women     |       q      =>   acquired from default quantity
-#               noContext |       q      =>   acquired from default quantity
-
-        # get Quantity
-        quantity_defined_by = None
-        quantity = None
-        # We will browse the mapped values and determine which apply
-        cell_key_list = self.getCellKeyList(base_id='quantity')
-        if cell_key_list not in [(),[]]:
-          if context is None:
-            raise KeyError, \
-                  "No context defined on TransformedResource '%s'" % \
-                      (self.getRelativeUrl(), )
-          for key in cell_key_list:
-            if self.hasCell(base_id='quantity', *key):
-              mapped_value = self.getCell(base_id='quantity', *key)
-              if mapped_value.test(context):
-                if 'quantity' in mapped_value.getMappedValuePropertyList():
-                  quantity = mapped_value.getProperty('quantity')
-                  quantity_defined_by = mapped_value.getRelativeUrl()
-          if quantity in [None,'']:
-            raise KeyError, \
-                  "No cell quantity matching on TransformedResource '%s' for "\
-                  "current context" % ( self.getRelativeUrl() ,   )
-        else:
-          quantity = self.getQuantity()
-          quantity_defined_by = self.getRelativeUrl()
-        if quantity in [None,'']:
-          raise KeyError, \
-                "No quantity defined on TransformedResource '%s' for "\
-                "current context" % (self.getRelativeUrl(), )
-        # If we have to do this, then there is a problem....
-        # We'd better have better API for this, 
-        # like an update function in the mapped_value
-        try:
-          quantity = float(quantity)
-        except ValueError:
-          error_string += 'Quantity is not a float.'
-
-        # If IAmount specifies that 4 resources are needed, all quantities
-        # need to be multiplicated by 4...
-        context_quantity = None
-        quantity_getter = getattr(context, "getQuantity", None)
-        if quantity_getter is not None:
-          _marker = object()
-          context_quantity = quantity_getter(_marker)
-          if context_quantity is _marker:
-            # XXX Backwards compatibility:
-            # previously, quantity property of the Amount was completely
-            # ignored, and was assumed to be 1.0 . Re-enact this old
-            # behavior (quantity default value is 0.0) to avoid breakages
-            warn("No quantity was defined on the Amount passed to " \
-                 "getAggregatedAmountList, 1.0 was assumed", DeprecationWarning)
-            context_quantity = 1.0
-        else:
-          raise KeyError("No quantity defined on context")
-        quantity *= float(context_quantity)
-
-        # Get the variation category list
-        variation_category_list_defined_by = None
-        variation_category_list = None
-        # We will browse the mapped values and determine which apply
-        cell_key_list = self.getCellKeyList( base_id = 'variation')
-        if cell_key_list not in [(),[]]:
-          if context is None:
-            raise KeyError, \
-                  "No context defined on TransformedResource '%s'" % \
-                      (self.getRelativeUrl(), )
-          for key in cell_key_list:
-            if self.hasCell(base_id='variation', *key):
-              mapped_value = self.getCell(base_id='variation', *key)
-              if mapped_value.test(context):
-                vcl = mapped_value.getCategoryList()
-                if vcl != []:
-                  variation_category_list = vcl
-                  variation_category_list_defined_by = \
-                      mapped_value.getRelativeUrl()
-          if variation_category_list in [None,'',[], ()]:
-            if quantity == 0:
-              return aggregated_amount_list
-            else:
-              raise KeyError, \
-                    "No cell variation matching on TransformedResource '%s' "\
-                    "for current context" % (self.getRelativeUrl(), )
-        else:
-          variation_category_list = self._getVariationCategoryList()
-          variation_category_list_defined_by = self.getRelativeUrl()
-        if hasattr(self,"getTradePhase"):
-          # After installing BPM, trade_phase category to be exists
-          trade_phase = self.getTradePhase()
-        else:
-          trade_phase = None
-        # Store values in Amount
-        tmp_amount._edit(
-          # Properties define on transformation line
-          title=self.getTitle(),
-          description=self.getDescription(),
-          efficiency=efficiency,
-          quantity=quantity,
-          # This fields only store some informations for debugging if necessary
-          quantity_defined_by=quantity_defined_by,
-          variation_category_list_defined_by=variation_category_list_defined_by,
-          trade_phase=trade_phase,
-          error_string=error_string
-        )
-        tmp_amount.setVariationCategoryList(variation_category_list)
-        # Variation property dict
-        tmp_amount.setVariationPropertyDict(self.getVariationPropertyDict())
-        aggregated_amount_list.append(tmp_amount)
-      return aggregated_amount_list
diff --git a/bt5/erp5_simulation_legacy/bt/template_document_id_list b/bt5/erp5_simulation_legacy/bt/template_document_id_list
index e3331613d0..25df69c417 100644
--- a/bt5/erp5_simulation_legacy/bt/template_document_id_list
+++ b/bt5/erp5_simulation_legacy/bt/template_document_id_list
@@ -11,6 +11,4 @@ ProductionOrderModelRootSimulationRule
 ProductionOrderRootSimulationRule
 RootAppliedRuleCausalityMovementGroup
 SimulationLegacyPatches
-TradeModelSimulationRule
-Transformation
-TransformedResource
\ No newline at end of file
+TradeModelSimulationRule
\ No newline at end of file
diff --git a/product/ERP5/Document/AssortedResource.py b/product/ERP5/Document/AssortedResource.py
index 97cc4a6856..09201e2ff4 100644
--- a/product/ERP5/Document/AssortedResource.py
+++ b/product/ERP5/Document/AssortedResource.py
@@ -31,6 +31,7 @@ from AccessControl import ClassSecurityInfo
 from Products.ERP5Type import Permissions, PropertySheet, Constraint
 from Products.ERP5Type.XMLMatrix import XMLMatrix
 from Products.ERP5Type.Utils import cartesianProduct
+from Products.ERP5.Document.AmountGeneratorLine import AmountGeneratorLine
 from Products.ERP5.Document.TransformedResource import TransformedResource
 from Products.ERP5Type.Base import TempBase
 
@@ -114,14 +115,6 @@ class AssortedResource(TransformedResource):
     security = ClassSecurityInfo()
     security.declareObjectProtected(Permissions.AccessContentsInformation)
 
-    # Declarative properties
-    property_sheets = ( PropertySheet.Base
-                      , PropertySheet.SimpleItem
-                      , PropertySheet.CategoryCore
-                      , PropertySheet.Amount
-                      , PropertySheet.TransformedResource
-                      )
-
     # Local property sheet
     _properties = (
       { 'id'          : 'variation_base_category',
@@ -138,6 +131,8 @@ class AssortedResource(TransformedResource):
         'mode'        : 'w' },
     )
 
+    getCellAggregateKey = AmountGeneratorLine.getCellAggregateKey
+
     security.declareProtected(Permissions.AccessContentsInformation, 'getAssortedVariationCategoryList')
     def getAssortedVariationCategoryList(self, cell_index):
       """
@@ -500,8 +495,8 @@ class AssortedResource(TransformedResource):
 
       return error_list
 
-    security.declareProtected(Permissions.AccessContentsInformation, 'getAggregatedAmountList')
-    def getAggregatedAmountList(self, REQUEST):
+    if 0: # obsolete
+     def getAggregatedAmountList(self, REQUEST):
       # First, we set initial values for quantity and variation
       # Currently, we only consider discrete variations
       # Continuous variations will be implemented in a future version of ERP5
diff --git a/product/ERP5/Document/SupplyLink.py b/product/ERP5/Document/SupplyLink.py
index b6abcb911e..425b76142a 100644
--- a/product/ERP5/Document/SupplyLink.py
+++ b/product/ERP5/Document/SupplyLink.py
@@ -139,7 +139,7 @@ class SupplyLink(Path, XMLObject):
               supply_chain.getNextProductionIndustrialPhaseList(self)
           # XXX GetRelativeUrl copy/paste from transformation
           # Code duplication
-          ind_phase_url_list = [x.getRelativeUrl() \
+          ind_phase_url_list = [x.getCategoryRelativeUrl()
                                for x in next_industrial_phase_list]
 
           # Get the transformation to use
@@ -147,10 +147,11 @@ class SupplyLink(Path, XMLObject):
           rule = applied_rule.getSpecialiseValue()
           transformation = rule.getTransformation(movement)
           # Call getAggregatedAmountList
-          amount_list = transformation.getAggregatedAmountList(
-                       movement.getParentValue().getParentValue(),
-                       ind_phase_url_list=ind_phase_url_list)
-          resource_list = [x.getResourceValue() for x in amount_list]
+          tmp_context = movement.getParentValue().getParentValue().asContext()
+          tmp_context.asComposedDocument = lambda *args: transformation
+          resource_list = [x.getResourceValue()
+            for x in tmp_context.getAggregatedAmountList()
+            if x.getCausalityValue().getIndustrialPhase() in ind_phase_url_list]
           current_resource = movement.getResourceValue()
           if current_resource not in resource_list:
             # We can delivered this resource
diff --git a/product/ERP5/Document/TransformedResource.py b/product/ERP5/Document/TransformedResource.py
index 4a9802ecf7..21fb470db0 100644
--- a/product/ERP5/Document/TransformedResource.py
+++ b/product/ERP5/Document/TransformedResource.py
@@ -29,21 +29,13 @@
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #
 ##############################################################################
-import zope.interface
 
-from warnings import warn
 from AccessControl import ClassSecurityInfo
-
 from Products.ERP5Type import Permissions, PropertySheet, interfaces
-from Products.ERP5Type.XMLObject import XMLObject
-from Products.ERP5Type.XMLMatrix import XMLMatrix
-
-from Products.ERP5.Document.Amount import Amount
-from Products.ERP5.Document.MappedValue import MappedValue
+from Products.ERP5.Document.AmountGeneratorLine import AmountGeneratorLine
 
-from Products.ERP5.Document.Predicate import Predicate
 
-class TransformedResource(MappedValue, XMLMatrix, Amount):
+class TransformedResource(AmountGeneratorLine):
     """
     TransformedResource defines which resource is being transformed
     in order to produce a product define in the parent Transformation
@@ -51,8 +43,8 @@ class TransformedResource(MappedValue, XMLMatrix, Amount):
 
     TODO:
     - transformations used to work perfectly for more than 3 dimensions
-      of variations. However, this feature was broken with time and 
-      is no longer usable. It is time to reimplement it. This is 
+      of variations. However, this feature was broken with time and
+      is no longer usable. It is time to reimplement it. This is
       completely unrelated to MatrixBox reimplementation unlike
       what is stated in some comments.
     """
@@ -65,18 +57,8 @@ class TransformedResource(MappedValue, XMLMatrix, Amount):
     security.declareObjectProtected(Permissions.AccessContentsInformation)
 
     # Declarative properties
-    property_sheets = ( PropertySheet.Base
-                      , PropertySheet.SimpleItem
-                      , PropertySheet.CategoryCore
-                      , PropertySheet.Amount
-                      , PropertySheet.Reference
-                      , PropertySheet.TransformedResource
-                      )
-
-    # Declarative interfaces
-    zope.interface.implements(interfaces.IAmountGenerator,
-                              interfaces.IVariated,
-                              interfaces.IVariationRange,)
+    property_sheets = (PropertySheet.TransformedResource, )
+
     ### Mapped Value Definition
     # Provide default mapped value properties and categories if
     # not defined
@@ -91,30 +73,41 @@ class TransformedResource(MappedValue, XMLMatrix, Amount):
           result = self.getVariationRangeBaseCategoryList() # The current resource variation
       return result
 
+    def getCellAggregateKey(self):
+      """Define a key in order to aggregate amounts at cell level"""
+      return None
+
+    @classmethod
+    def getBaseAmountQuantity(cls, delivery_amount, base_application, rounding):
+      value = delivery_amount.getGeneratedAmountQuantity(base_application)
+      if base_application == 'produced_quantity':
+        value += delivery_amount.getQuantity()
+      return value
+
     def getBaseApplication(self):
       """
-      
+      """
+      return self.getBaseApplicationList()[0]
+
+    def getBaseApplicationList(self):
+      """
       """
       # It is OK to try to acquire
-      if getattr(self, '_baseGetBaseApplication', None) is not None:
-        result = self._baseGetBaseApplication()
-        if result:
-          return result
-      return 'produced_quantity'
+      return self._categoryGetBaseApplicationList() or ['produced_quantity']
 
     ### Variation matrix definition
     # XXX-JPS Some explanation needed
-    security.declareProtected(Permissions.AccessContentsInformation, 
+    security.declareProtected(Permissions.AccessContentsInformation,
                               'updateVariationCategoryList')
     def updateVariationCategoryList(self):
       """
-        Check if variation category list of the resource changed and 
+        Check if variation category list of the resource changed and
         update transformed resource by doing a set cell range
       """
       self.setQVariationBaseCategoryList(self.getQVariationBaseCategoryList())
       self.setVVariationBaseCategoryList(self.getVVariationBaseCategoryList())
 
-    security.declareProtected(Permissions.ModifyPortalContent, 
+    security.declareProtected(Permissions.ModifyPortalContent,
                               '_setQVariationBaseCategoryList')
     def _setQVariationBaseCategoryList(self, value):
       """
@@ -124,7 +117,7 @@ class TransformedResource(MappedValue, XMLMatrix, Amount):
       self._baseSetQVariationBaseCategoryList(value)
       self._updateCellRange('quantity')
 
-    security.declareProtected(Permissions.ModifyPortalContent, 
+    security.declareProtected(Permissions.ModifyPortalContent,
                               '_setVVariationBaseCategoryList')
     def _setVVariationBaseCategoryList(self, value):
       """
@@ -137,7 +130,7 @@ class TransformedResource(MappedValue, XMLMatrix, Amount):
       # XXX-JPS This should be handled by interaction workflow or interactor
       # XXX-JPS SO many cases are not handled well...
 
-    security.declareProtected(Permissions.ModifyPortalContent, 
+    security.declareProtected(Permissions.ModifyPortalContent,
                               'setVVariationBaseCategoryList')
     def setVVariationBaseCategoryList(self, value):
       """
diff --git a/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/SQLCatalog_catalogTransformation.xml b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/SQLCatalog_catalogTransformation.xml
index 2c7c338c55..6840db5f81 100644
--- a/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/SQLCatalog_catalogTransformation.xml
+++ b/product/ERP5/bootstrap/erp5_mysql_innodb_catalog/CatalogMethodTemplateItem/portal_catalog/erp5_mysql_innodb/SQLCatalog_catalogTransformation.xml
@@ -75,13 +75,14 @@ for transformation_relative_url, variation_list_list in transformation_item_list
     continue\n
   for variation_list in variation_list_list:\n
     movement = newTempMovement(resource, \'temp\',\n
+                               specialise_value=transformation,\n
                                variation_category_list=variation_list,\n
-                               resource=resource.getRelativeUrl(),\n
+                               resource_value=resource,\n
                                quantity=1.0)\n
     base_row = dict(uid=resource.getUid(), variation_text=movement.getVariationText())\n
 \n
     row_dict_list = []\n
-    for amount in transformation.getAggregatedAmountList([movement]):\n
+    for amount in movement.getAggregatedAmountList():\n
       transformed_resource_uid = amount.getResourceUid()\n
       quantity = amount.getQuantity()\n
       if transformed_resource_uid is not None and quantity is not None:\n
diff --git a/product/ERP5/mixin/amount_generator.py b/product/ERP5/mixin/amount_generator.py
index fe113164cb..b7249e866f 100644
--- a/product/ERP5/mixin/amount_generator.py
+++ b/product/ERP5/mixin/amount_generator.py
@@ -234,7 +234,9 @@ class AmountGeneratorMixin:
         # Then collect the mapped values (quantity, price, trade_phase...)
         for key in cell.getMappedValuePropertyList():
           # XXX-JPS Make sure handling of list properties can be handled
-          property_dict[key] = cell.getProperty(key)
+          dict_key = key in ('net_quantity', 'converted_quantity',
+                             'net_converted_quantity') and 'quantity' or key
+          property_dict[dict_key] = cell.getProperty(key)
         category_list = cell.getAcquiredCategoryMembershipList(
           cell.getMappedValueBaseCategoryList(), base=1)
         property_dict['category_list'] += category_list
@@ -279,14 +281,10 @@ class AmountGeneratorMixin:
         # (XXX is it OK ?) XXX-JPS Need careful review with taxes
         quantity = float(sum(map(base_amount.getGeneratedAmountQuantity,
                                  base_application_set)))
-        for quantity_key in ('net_quantity', 'converted_quantity',
-                             'net_converted_quantity', 'quantity'):
-          if quantity_key in property_dict:
-            try:
-              quantity *= property_dict.pop(quantity_key)
-            except TypeError: # None or ''
-              pass
-            break
+        try:
+          quantity *= property_dict.pop('quantity', 1)
+        except TypeError: # None or ''
+          pass
         if not quantity:
           continue
         # Backward compatibility
diff --git a/product/ERP5Legacy/Document/TransformationRule.py b/product/ERP5Legacy/Document/TransformationRule.py
index 6573b6ab9e..1397f2638f 100644
--- a/product/ERP5Legacy/Document/TransformationRule.py
+++ b/product/ERP5Legacy/Document/TransformationRule.py
@@ -217,24 +217,27 @@ class TransformationRule(TransformationSourcingRuleMixin, Rule):
                                   base_category_list=base_category_list)
       # Get the transformation to use
       transformation = self.getTransformation(applied_rule)
-      # Generate the fake context 
-      tmp_context = parent_movement.asContext(
-                   context=parent_movement, 
-                   REQUEST={'categories':category_list})
+      # Generate the fake context
+      tmp_context = parent_movement.asContext(categories=category_list)
+      tmp_context.asComposedDocument = lambda *args: transformation
       # Calculate the industrial phase list
       previous_ind_phase_list = supply_chain.\
           getPreviousPackingListIndustrialPhaseList(current_supply_link)
-      ind_phase_id_list = [x.getRelativeUrl() for x in previous_ind_phase_list]
+      ind_phase_url_list = [x.getCategoryRelativeUrl()
+                        for x in previous_ind_phase_list]
       # Call getAggregatedAmountList
       # XXX expand failed if transformation is not defined.
       # Do we need to catch the exception ?
-      amount_list = transformation.getAggregatedAmountList(
-                   tmp_context,
-                   ind_phase_url_list=ind_phase_id_list)
+      amount_list = tmp_context.getAggregatedAmountList()
       # Add entries in the consumed_movement_dict
       consumed_movement_dict = {}
       for amount in amount_list:
-        consumed_mvt_id = "%s_%s" % ("cr", amount.getId())
+        model_line = amount.getCausalityValue()
+        if model_line.getIndustrialPhase() not in ind_phase_url_list:
+          continue
+        consumed_mvt_id = "cr_%s_%s_%s" % (model_line.getParentId(),
+                                           model_line.getId(),
+                                           tmp_context.getId())
         stop_date = parent_movement.getStartDate()
         resource_price = amount.getResourcePrice()
         price = None
@@ -248,7 +251,7 @@ class TransformationRule(TransformationSourcingRuleMixin, Rule):
                         amount.getVariationCategoryList(),
           "variation_property_dict": \
                         amount.getVariationPropertyDict(),
-          "quantity": amount.getNetQuantity(), # getNetQuantity to support efficency from transformation
+          "quantity": amount.getNetQuantity(), # getNetQuantity to support efficency from <
           "price": price,
           "quantity_unit": amount.getQuantityUnit(),
           "destination_list": (),
diff --git a/product/ERP5Legacy/tests/testLegacyProductionOrder.py b/product/ERP5Legacy/tests/testLegacyProductionOrder.py
index 832ac06757..1067da5066 100644
--- a/product/ERP5Legacy/tests/testLegacyProductionOrder.py
+++ b/product/ERP5Legacy/tests/testLegacyProductionOrder.py
@@ -65,7 +65,8 @@ class TestProductionOrderMixin(TestOrderMixin):
   def getBusinessTemplateList(self):
     """
     """
-    return TestOrderMixin.getBusinessTemplateList(self) + ('erp5_mrp',)
+    return TestOrderMixin.getBusinessTemplateList(self) + (
+      'erp5_mrp', 'erp5_mrp_simulation_legacy')
 
   def setUpPreferences(self):
     portal = self.getPortal()
-- 
2.30.9