From 5bfec5695270b40741020b2dbef0301e853f28f6 Mon Sep 17 00:00:00 2001 From: Julien Muchembled <jm@nexedi.com> Date: Mon, 18 Oct 2010 14:12:01 +0000 Subject: [PATCH] Bugfixes to Transformation + new testLegacyTransformation git-svn-id: https://svn.erp5.org/repos/public/erp5/sandbox/amount_generator@39282 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5/Document/Amount.py | 3 +- product/ERP5/Document/Resource.py | 15 +-- product/ERP5/Document/SupplyLink.py | 5 +- product/ERP5/Document/Transformation.py | 115 +++++++----------- product/ERP5/Document/TransformedResource.py | 4 +- product/ERP5/mixin/amount_generator.py | 6 +- product/ERP5/mixin/variated.py | 8 +- product/ERP5/tests/testProductionOrder.py | 13 +- product/ERP5/tests/testTransformation.py | 14 +-- .../ERP5Legacy/Document/TransformationRule.py | 3 +- .../tests/testLegacyProductionOrder.py | 3 +- .../tests/testLegacyTransformation.py | 36 ++++++ 12 files changed, 105 insertions(+), 120 deletions(-) create mode 100644 product/ERP5Legacy/tests/testLegacyTransformation.py diff --git a/product/ERP5/Document/Amount.py b/product/ERP5/Document/Amount.py index 14d1607889..a922bca1a5 100644 --- a/product/ERP5/Document/Amount.py +++ b/product/ERP5/Document/Amount.py @@ -63,8 +63,7 @@ class Amount(Base, VariatedMixin): # Declarative interfaces zope.interface.implements(interfaces.IAmount) - property_sheets = ( PropertySheet.Base - , PropertySheet.SimpleItem + property_sheets = ( PropertySheet.SimpleItem , PropertySheet.Amount , PropertySheet.Price , PropertySheet.Reference diff --git a/product/ERP5/Document/Resource.py b/product/ERP5/Document/Resource.py index 8d8222b07a..82e56e6416 100644 --- a/product/ERP5/Document/Resource.py +++ b/product/ERP5/Document/Resource.py @@ -27,14 +27,14 @@ # ############################################################################## -import zope.interface from math import log from warnings import warn from AccessControl import ClassSecurityInfo -from Products.ERP5Type import Permissions, PropertySheet, interfaces +from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type.XMLMatrix import XMLMatrix +from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.Base import Base from Products.ERP5Type.Utils import cartesianProduct @@ -44,7 +44,7 @@ from Products.CMFCore.utils import getToolByName from zLOG import LOG, WARNING -class Resource(XMLMatrix, VariatedMixin): +class Resource(XMLObject, XMLMatrix, VariatedMixin): """ A Resource """ @@ -57,20 +57,13 @@ class Resource(XMLMatrix, VariatedMixin): security = ClassSecurityInfo() security.declareObjectProtected(Permissions.AccessContentsInformation) - # Declarative interfaces - zope.interface.implements( interfaces.IVariated, ) - # Declarative properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore + property_sheets = ( PropertySheet.DublinCore , PropertySheet.Price , PropertySheet.Resource , PropertySheet.Reference , PropertySheet.Comment , PropertySheet.FlowCapacity - , PropertySheet.VariationRange , PropertySheet.DefaultSupply , PropertySheet.Aggregated ) diff --git a/product/ERP5/Document/SupplyLink.py b/product/ERP5/Document/SupplyLink.py index 425b76142a..1e79e37e0f 100644 --- a/product/ERP5/Document/SupplyLink.py +++ b/product/ERP5/Document/SupplyLink.py @@ -147,10 +147,9 @@ class SupplyLink(Path, XMLObject): rule = applied_rule.getSpecialiseValue() transformation = rule.getTransformation(movement) # Call getAggregatedAmountList - tmp_context = movement.getParentValue().getParentValue().asContext() - tmp_context.asComposedDocument = lambda *args: transformation + input_amount = applied_rule.getParentValue() resource_list = [x.getResourceValue() - for x in tmp_context.getAggregatedAmountList() + for x in transformation.getAggregatedAmountList((input_amount,)) if x.getCausalityValue().getIndustrialPhase() in ind_phase_url_list] current_resource = movement.getResourceValue() if current_resource not in resource_list: diff --git a/product/ERP5/Document/Transformation.py b/product/ERP5/Document/Transformation.py index a9ed756c9b..623f954bc8 100644 --- a/product/ERP5/Document/Transformation.py +++ b/product/ERP5/Document/Transformation.py @@ -31,14 +31,12 @@ # ############################################################################## from zLOG import LOG, WARNING - -import zope.interface - from warnings import warn from AccessControl import ClassSecurityInfo from Products.CMFCategory.Renderer import Renderer -from Products.ERP5Type import Permissions, PropertySheet, interfaces +from Products.ERP5Type import Permissions, PropertySheet +from Products.ERP5.Document.Amount import Amount from Products.ERP5.Document.MappedValue import MappedValue from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin @@ -46,7 +44,9 @@ from Products.ERP5.mixin.variated import VariatedMixin from Products.ERP5.mixin.composition import CompositionMixin from Products.ERP5Type.XMLObject import XMLObject -class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin): +# XXX Give priority to VariatedMixin (over Amount) due to conflicting +# implementations of getVariationBaseCategoryList +class Transformation(MappedValue, VariatedMixin, Amount, AmountGeneratorMixin): """ Build of material - contains a list of transformed resources @@ -65,59 +65,47 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin): security.declareObjectProtected(Permissions.AccessContentsInformation) # Declarative properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore - , PropertySheet.VariationRange - , PropertySheet.Predicate - , PropertySheet.Comment - , PropertySheet.Reference + property_sheets = ( PropertySheet.Comment , PropertySheet.Version #, PropertySheet.Resource , PropertySheet.TransformedResource - , PropertySheet.Path , PropertySheet.Transformation , PropertySheet.Order , PropertySheet.Task ) - # Declarative interfaces - zope.interface.implements(interfaces.IVariated, - interfaces.IVariationRange, - interfaces.IAmountGenerator - ) + def getAggregatedAmountList(self, *args, **kw): + """ + """ + getAggregatedAmountList = \ + super(Transformation, self).getAggregatedAmountList + # Detect old use of getAggregatedAmountList + if 'context' in kw: + context = kw.pop('context') + else: + if not args or isinstance(args[0], (list, tuple)): + return getAggregatedAmountList(*args, **kw) + context, args = args[0], args[1:] + warn("The API of getAggregatedAmountList has changed:" + " it must be called on the context instead of passing" + " the context as first parameter", DeprecationWarning) + # XXX add a 'transformation_amount_generator' group type + kw['amount_generator_type_list'] = ('Transformation', + 'Transformed Resource', + 'Assorted Resource') + if context is not None: + context = (context,) + return getAggregatedAmountList(context, *args, **kw) + + def getQuantity(self, default=None): + # Used for amount generation + # (Transformation is defined for 1 unit of target resource) + return 1 # Predicate Value implementation # asPredicate takes into account the resource # XXX-JPS not Impl. - def getCellAggregateKey(self, amount_generator_cell): - """Define a key in order to aggregate amounts at cell level - - Transformed Resource (Transformation) - key must be None because: - - quantity and variation are defined in different cells so that the - user does not need to enter values depending on all axes - - amount_generator_cell.test should filter only 1 variant - current key = (acquired resource, acquired variation) - - Assorted Resource (Transformation) - key = (assorted resource, assorted resource variation) - usually resource and quantity provided together - - Payroll - key = (payroll resource, payroll resource variation) - - Tax - key = (tax resource, tax resource variation) - """ - if len(amount_generator_cell.contentValues()): - key = (amount_generator_cell.getRelativeUrl(),) - else: - key = (amount_generator_cell.getParentValue().getRelativeUrl(),) - return key - # Mapped Value implementation # Transformation itself provides no properties or categories def getMappedValuePropertyList(self): @@ -126,34 +114,6 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin): def getMappedValueBaseCategoryList(self): return () - # Amount Generator Mixin - def _getGlobalPropertyDict(self, context, amount_list=None, rounding=False): - """ - No global properties needed - """ - return { - } - - def _getAmountPropertyDict(self, amount, amount_list=None, rounding=False): - """ - Produced amount quantity is needed to initialize transformation - """ - # XXX 1 is for compatibility - return { - 'produced_quantity' : amount.getQuantity(1), - } - - def getBaseApplication(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' - # IVariationRange and IVariated Implementation security.declareProtected(Permissions.AccessContentsInformation, 'updateVariationCategoryList') @@ -229,6 +189,15 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin): 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, diff --git a/product/ERP5/Document/TransformedResource.py b/product/ERP5/Document/TransformedResource.py index 21fb470db0..fd2e740e52 100644 --- a/product/ERP5/Document/TransformedResource.py +++ b/product/ERP5/Document/TransformedResource.py @@ -71,6 +71,8 @@ class TransformedResource(AmountGeneratorLine): if not result: if not self.hasCellContent(base_id='variation'): result = self.getVariationRangeBaseCategoryList() # The current resource variation + if 'trade_phase' not in result: + result.append('trade_phase') return result def getCellAggregateKey(self): @@ -81,7 +83,7 @@ class TransformedResource(AmountGeneratorLine): def getBaseAmountQuantity(cls, delivery_amount, base_application, rounding): value = delivery_amount.getGeneratedAmountQuantity(base_application) if base_application == 'produced_quantity': - value += delivery_amount.getQuantity() + value += delivery_amount.getConvertedQuantity() return value def getBaseApplication(self): diff --git a/product/ERP5/mixin/amount_generator.py b/product/ERP5/mixin/amount_generator.py index b7249e866f..1ec604e678 100644 --- a/product/ERP5/mixin/amount_generator.py +++ b/product/ERP5/mixin/amount_generator.py @@ -174,8 +174,10 @@ class AmountGeneratorMixin: dict(rounding=rounding)) # If amount_list is None, then try to collect amount_list from # the current context + default_target = None if amount_list is None: if self.providesIMovementCollection(): + default_target = 'isMovement' base_amount_list = BaseAmountDict(*args).__of__(self) \ .recurseMovementList(self.getMovementList()) elif self.providesIAmount(): @@ -204,8 +206,8 @@ class AmountGeneratorMixin: return elif (self.getPortalType() not in amount_generator_line_type_list): return - if not getattr(delivery_amount, self.isTargetDelivery() and - 'isDelivery' or 'isMovement')(): + target_method = self.isTargetDelivery() and 'isDelivery' or default_target + if target_method and not getattr(delivery_amount, target_method)(): return # Try to collect cells and aggregate their mapped properties # using resource + variation as aggregation key or base_application diff --git a/product/ERP5/mixin/variated.py b/product/ERP5/mixin/variated.py index bd3844c7d4..f494bb3d1b 100644 --- a/product/ERP5/mixin/variated.py +++ b/product/ERP5/mixin/variated.py @@ -30,7 +30,7 @@ from warnings import warn from AccessControl import ClassSecurityInfo from Products.CMFCategory.Renderer import Renderer -from Products.ERP5Type import interfaces, Permissions +from Products.ERP5Type import interfaces, Permissions, PropertySheet import zope.interface @@ -54,7 +54,11 @@ class VariatedMixin: security = ClassSecurityInfo() # Declarative interfaces - zope.interface.implements(interfaces.IVariated) + zope.interface.implements(interfaces.IVariated, + interfaces.IVariationRange) + + isRADContent = 1 # for 'property_sheets' + property_sheets = (PropertySheet.VariationRange, ) security.declareProtected(Permissions.AccessContentsInformation, 'getVariationBaseCategoryList') diff --git a/product/ERP5/tests/testProductionOrder.py b/product/ERP5/tests/testProductionOrder.py index af085db9d9..5c02e7afcf 100644 --- a/product/ERP5/tests/testProductionOrder.py +++ b/product/ERP5/tests/testProductionOrder.py @@ -395,25 +395,16 @@ class TestProductionOrderMixin(TestOrderMixin): """ Fills categories of variation """ - transformation = sequence.get('transformation') + transformation.setVariationBaseCategoryList(self.variation_category_list) - transformation.edit( - variation_base_category_list = self.variation_category_list - ) - def stepFillTransformationWithResource(self, sequence=None, sequence_list=None, **kw): transformation = sequence.get('transformation') - resource = sequence.get('resource') - self.assertNotEquals(None, resource) - - transformation.edit( - resource_value = resource - ) + transformation.setResourceValue(resource) def stepSetOrderLineQuantity(self, sequence=None, sequence_list=None, **kw): diff --git a/product/ERP5/tests/testTransformation.py b/product/ERP5/tests/testTransformation.py index a8a1bd1be1..fa1b6ad317 100644 --- a/product/ERP5/tests/testTransformation.py +++ b/product/ERP5/tests/testTransformation.py @@ -26,8 +26,8 @@ # ############################################################################## -from testProductionOrder import TestProductionOrderMixin -from testInventoryAPI import BaseTestUnitConversion +from Products.ERP5.tests.testProductionOrder import TestProductionOrderMixin +from Products.ERP5.tests.testInventoryAPI import BaseTestUnitConversion import transaction class TestTransformationMixin(TestProductionOrderMixin): @@ -146,15 +146,7 @@ class TestTransformation(TestTransformationMixin, BaseTestUnitConversion): resource_value=component, quantity=1) transformed_resource.setTested(True) - from Products.ERP5Type.Document import newTempAmount - amount = newTempAmount(transformation, "foobar") - amount.edit( - quantity = 1.0, - resource = component.getRelativeUrl(), - ) - aggregated_amount_list = transformation.getAggregatedAmountList(amount) - self.assertEquals(len(aggregated_amount_list), 1) - aggregated_amount = aggregated_amount_list[0] + aggregated_amount, = transformation.getAggregatedAmountList() # Make sure that the isTested method is working properly on the # temp object self.assertTrue(aggregated_amount.isTested()) diff --git a/product/ERP5Legacy/Document/TransformationRule.py b/product/ERP5Legacy/Document/TransformationRule.py index 1397f2638f..35ec49279c 100644 --- a/product/ERP5Legacy/Document/TransformationRule.py +++ b/product/ERP5Legacy/Document/TransformationRule.py @@ -219,7 +219,6 @@ class TransformationRule(TransformationSourcingRuleMixin, Rule): transformation = self.getTransformation(applied_rule) # 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) @@ -228,7 +227,7 @@ class TransformationRule(TransformationSourcingRuleMixin, Rule): # Call getAggregatedAmountList # XXX expand failed if transformation is not defined. # Do we need to catch the exception ? - amount_list = tmp_context.getAggregatedAmountList() + amount_list = transformation.getAggregatedAmountList((tmp_context,)) # Add entries in the consumed_movement_dict consumed_movement_dict = {} for amount in amount_list: diff --git a/product/ERP5Legacy/tests/testLegacyProductionOrder.py b/product/ERP5Legacy/tests/testLegacyProductionOrder.py index 1067da5066..25875c44e2 100644 --- a/product/ERP5Legacy/tests/testLegacyProductionOrder.py +++ b/product/ERP5Legacy/tests/testLegacyProductionOrder.py @@ -98,9 +98,8 @@ class TestProductionOrderMixin(TestOrderMixin): some categories for testing them """ TestOrderMixin.createCategories(self) - operation_category_list = ['operation1', 'operation2'] if len(self.category_tool.operation.contentValues()) == 0: - for category_id in operation_category_list: + for category_id in self.operation_category_list: o = self.category_tool.operation.newContent( portal_type='Category', id=category_id) diff --git a/product/ERP5Legacy/tests/testLegacyTransformation.py b/product/ERP5Legacy/tests/testLegacyTransformation.py new file mode 100644 index 0000000000..4ae5c830f2 --- /dev/null +++ b/product/ERP5Legacy/tests/testLegacyTransformation.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +############################################################################## +# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved. +# Julien Muchembled <jm@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility 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 +# guarantees 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +############################################################################## + +import sys +from Products.ERP5Legacy.tests import testLegacyProductionOrder +sys.modules['Products.ERP5.tests.testProductionOrder'] = \ + testLegacyProductionOrder +from Products.ERP5.tests.testTransformation import * + +from Products.ERP5Legacy.tests import Legacy_getBusinessTemplateList +Legacy_getBusinessTemplateList(TestTransformation) -- 2.30.9