Commit 5bfec569 authored by Julien Muchembled's avatar Julien Muchembled

Bugfixes to Transformation + new testLegacyTransformation

git-svn-id: https://svn.erp5.org/repos/public/erp5/sandbox/amount_generator@39282 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent ea488e40
...@@ -63,8 +63,7 @@ class Amount(Base, VariatedMixin): ...@@ -63,8 +63,7 @@ class Amount(Base, VariatedMixin):
# Declarative interfaces # Declarative interfaces
zope.interface.implements(interfaces.IAmount) zope.interface.implements(interfaces.IAmount)
property_sheets = ( PropertySheet.Base property_sheets = ( PropertySheet.SimpleItem
, PropertySheet.SimpleItem
, PropertySheet.Amount , PropertySheet.Amount
, PropertySheet.Price , PropertySheet.Price
, PropertySheet.Reference , PropertySheet.Reference
......
...@@ -27,14 +27,14 @@ ...@@ -27,14 +27,14 @@
# #
############################################################################## ##############################################################################
import zope.interface
from math import log from math import log
from warnings import warn from warnings import warn
from AccessControl import ClassSecurityInfo 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.XMLMatrix import XMLMatrix
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Base import Base from Products.ERP5Type.Base import Base
from Products.ERP5Type.Utils import cartesianProduct from Products.ERP5Type.Utils import cartesianProduct
...@@ -44,7 +44,7 @@ from Products.CMFCore.utils import getToolByName ...@@ -44,7 +44,7 @@ from Products.CMFCore.utils import getToolByName
from zLOG import LOG, WARNING from zLOG import LOG, WARNING
class Resource(XMLMatrix, VariatedMixin): class Resource(XMLObject, XMLMatrix, VariatedMixin):
""" """
A Resource A Resource
""" """
...@@ -57,20 +57,13 @@ class Resource(XMLMatrix, VariatedMixin): ...@@ -57,20 +57,13 @@ class Resource(XMLMatrix, VariatedMixin):
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative interfaces
zope.interface.implements( interfaces.IVariated, )
# Declarative properties # Declarative properties
property_sheets = ( PropertySheet.Base property_sheets = ( PropertySheet.DublinCore
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Price , PropertySheet.Price
, PropertySheet.Resource , PropertySheet.Resource
, PropertySheet.Reference , PropertySheet.Reference
, PropertySheet.Comment , PropertySheet.Comment
, PropertySheet.FlowCapacity , PropertySheet.FlowCapacity
, PropertySheet.VariationRange
, PropertySheet.DefaultSupply , PropertySheet.DefaultSupply
, PropertySheet.Aggregated , PropertySheet.Aggregated
) )
......
...@@ -147,10 +147,9 @@ class SupplyLink(Path, XMLObject): ...@@ -147,10 +147,9 @@ class SupplyLink(Path, XMLObject):
rule = applied_rule.getSpecialiseValue() rule = applied_rule.getSpecialiseValue()
transformation = rule.getTransformation(movement) transformation = rule.getTransformation(movement)
# Call getAggregatedAmountList # Call getAggregatedAmountList
tmp_context = movement.getParentValue().getParentValue().asContext() input_amount = applied_rule.getParentValue()
tmp_context.asComposedDocument = lambda *args: transformation
resource_list = [x.getResourceValue() 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] if x.getCausalityValue().getIndustrialPhase() in ind_phase_url_list]
current_resource = movement.getResourceValue() current_resource = movement.getResourceValue()
if current_resource not in resource_list: if current_resource not in resource_list:
......
...@@ -31,14 +31,12 @@ ...@@ -31,14 +31,12 @@
# #
############################################################################## ##############################################################################
from zLOG import LOG, WARNING from zLOG import LOG, WARNING
import zope.interface
from warnings import warn from warnings import warn
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.CMFCategory.Renderer import Renderer 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.Document.MappedValue import MappedValue
from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin from Products.ERP5.mixin.amount_generator import AmountGeneratorMixin
...@@ -46,7 +44,9 @@ from Products.ERP5.mixin.variated import VariatedMixin ...@@ -46,7 +44,9 @@ from Products.ERP5.mixin.variated import VariatedMixin
from Products.ERP5.mixin.composition import CompositionMixin from Products.ERP5.mixin.composition import CompositionMixin
from Products.ERP5Type.XMLObject import XMLObject 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 Build of material - contains a list of transformed resources
...@@ -65,59 +65,47 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin): ...@@ -65,59 +65,47 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin):
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties # Declarative properties
property_sheets = ( PropertySheet.Base property_sheets = ( PropertySheet.Comment
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.VariationRange
, PropertySheet.Predicate
, PropertySheet.Comment
, PropertySheet.Reference
, PropertySheet.Version , PropertySheet.Version
#, PropertySheet.Resource #, PropertySheet.Resource
, PropertySheet.TransformedResource , PropertySheet.TransformedResource
, PropertySheet.Path
, PropertySheet.Transformation , PropertySheet.Transformation
, PropertySheet.Order , PropertySheet.Order
, PropertySheet.Task , PropertySheet.Task
) )
# Declarative interfaces def getAggregatedAmountList(self, *args, **kw):
zope.interface.implements(interfaces.IVariated, """
interfaces.IVariationRange, """
interfaces.IAmountGenerator 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 # Predicate Value implementation
# asPredicate takes into account the resource # asPredicate takes into account the resource
# XXX-JPS not Impl. # 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 # Mapped Value implementation
# Transformation itself provides no properties or categories # Transformation itself provides no properties or categories
def getMappedValuePropertyList(self): def getMappedValuePropertyList(self):
...@@ -126,34 +114,6 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin): ...@@ -126,34 +114,6 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin):
def getMappedValueBaseCategoryList(self): def getMappedValueBaseCategoryList(self):
return () 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 # IVariationRange and IVariated Implementation
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'updateVariationCategoryList') 'updateVariationCategoryList')
...@@ -229,6 +189,15 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin): ...@@ -229,6 +189,15 @@ class Transformation(MappedValue, AmountGeneratorMixin, VariatedMixin):
base_category_list, base=1, display_none_category=0) base_category_list, base=1, display_none_category=0)
return result 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, security.declareProtected(Permissions.AccessContentsInformation,
'getVariationCategoryItemList') 'getVariationCategoryItemList')
def getVariationCategoryItemList(self, base_category_list=(), base=1, def getVariationCategoryItemList(self, base_category_list=(), base=1,
......
...@@ -71,6 +71,8 @@ class TransformedResource(AmountGeneratorLine): ...@@ -71,6 +71,8 @@ class TransformedResource(AmountGeneratorLine):
if not result: if not result:
if not self.hasCellContent(base_id='variation'): if not self.hasCellContent(base_id='variation'):
result = self.getVariationRangeBaseCategoryList() # The current resource variation result = self.getVariationRangeBaseCategoryList() # The current resource variation
if 'trade_phase' not in result:
result.append('trade_phase')
return result return result
def getCellAggregateKey(self): def getCellAggregateKey(self):
...@@ -81,7 +83,7 @@ class TransformedResource(AmountGeneratorLine): ...@@ -81,7 +83,7 @@ class TransformedResource(AmountGeneratorLine):
def getBaseAmountQuantity(cls, delivery_amount, base_application, rounding): def getBaseAmountQuantity(cls, delivery_amount, base_application, rounding):
value = delivery_amount.getGeneratedAmountQuantity(base_application) value = delivery_amount.getGeneratedAmountQuantity(base_application)
if base_application == 'produced_quantity': if base_application == 'produced_quantity':
value += delivery_amount.getQuantity() value += delivery_amount.getConvertedQuantity()
return value return value
def getBaseApplication(self): def getBaseApplication(self):
......
...@@ -174,8 +174,10 @@ class AmountGeneratorMixin: ...@@ -174,8 +174,10 @@ class AmountGeneratorMixin:
dict(rounding=rounding)) dict(rounding=rounding))
# If amount_list is None, then try to collect amount_list from # If amount_list is None, then try to collect amount_list from
# the current context # the current context
default_target = None
if amount_list is None: if amount_list is None:
if self.providesIMovementCollection(): if self.providesIMovementCollection():
default_target = 'isMovement'
base_amount_list = BaseAmountDict(*args).__of__(self) \ base_amount_list = BaseAmountDict(*args).__of__(self) \
.recurseMovementList(self.getMovementList()) .recurseMovementList(self.getMovementList())
elif self.providesIAmount(): elif self.providesIAmount():
...@@ -204,8 +206,8 @@ class AmountGeneratorMixin: ...@@ -204,8 +206,8 @@ class AmountGeneratorMixin:
return return
elif (self.getPortalType() not in amount_generator_line_type_list): elif (self.getPortalType() not in amount_generator_line_type_list):
return return
if not getattr(delivery_amount, self.isTargetDelivery() and target_method = self.isTargetDelivery() and 'isDelivery' or default_target
'isDelivery' or 'isMovement')(): if target_method and not getattr(delivery_amount, target_method)():
return return
# Try to collect cells and aggregate their mapped properties # Try to collect cells and aggregate their mapped properties
# using resource + variation as aggregation key or base_application # using resource + variation as aggregation key or base_application
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
from warnings import warn from warnings import warn
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.CMFCategory.Renderer import Renderer from Products.CMFCategory.Renderer import Renderer
from Products.ERP5Type import interfaces, Permissions from Products.ERP5Type import interfaces, Permissions, PropertySheet
import zope.interface import zope.interface
...@@ -54,7 +54,11 @@ class VariatedMixin: ...@@ -54,7 +54,11 @@ class VariatedMixin:
security = ClassSecurityInfo() security = ClassSecurityInfo()
# Declarative interfaces # 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, security.declareProtected(Permissions.AccessContentsInformation,
'getVariationBaseCategoryList') 'getVariationBaseCategoryList')
......
...@@ -395,25 +395,16 @@ class TestProductionOrderMixin(TestOrderMixin): ...@@ -395,25 +395,16 @@ class TestProductionOrderMixin(TestOrderMixin):
""" """
Fills categories of variation Fills categories of variation
""" """
transformation = sequence.get('transformation') 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, def stepFillTransformationWithResource(self, sequence=None, sequence_list=None,
**kw): **kw):
transformation = sequence.get('transformation') transformation = sequence.get('transformation')
resource = sequence.get('resource') resource = sequence.get('resource')
self.assertNotEquals(None, resource) self.assertNotEquals(None, resource)
transformation.setResourceValue(resource)
transformation.edit(
resource_value = resource
)
def stepSetOrderLineQuantity(self, sequence=None, sequence_list=None, def stepSetOrderLineQuantity(self, sequence=None, sequence_list=None,
**kw): **kw):
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
# #
############################################################################## ##############################################################################
from testProductionOrder import TestProductionOrderMixin from Products.ERP5.tests.testProductionOrder import TestProductionOrderMixin
from testInventoryAPI import BaseTestUnitConversion from Products.ERP5.tests.testInventoryAPI import BaseTestUnitConversion
import transaction import transaction
class TestTransformationMixin(TestProductionOrderMixin): class TestTransformationMixin(TestProductionOrderMixin):
...@@ -146,15 +146,7 @@ class TestTransformation(TestTransformationMixin, BaseTestUnitConversion): ...@@ -146,15 +146,7 @@ class TestTransformation(TestTransformationMixin, BaseTestUnitConversion):
resource_value=component, resource_value=component,
quantity=1) quantity=1)
transformed_resource.setTested(True) transformed_resource.setTested(True)
from Products.ERP5Type.Document import newTempAmount aggregated_amount, = transformation.getAggregatedAmountList()
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]
# Make sure that the isTested method is working properly on the # Make sure that the isTested method is working properly on the
# temp object # temp object
self.assertTrue(aggregated_amount.isTested()) self.assertTrue(aggregated_amount.isTested())
......
...@@ -219,7 +219,6 @@ class TransformationRule(TransformationSourcingRuleMixin, Rule): ...@@ -219,7 +219,6 @@ class TransformationRule(TransformationSourcingRuleMixin, Rule):
transformation = self.getTransformation(applied_rule) transformation = self.getTransformation(applied_rule)
# Generate the fake context # Generate the fake context
tmp_context = parent_movement.asContext(categories=category_list) tmp_context = parent_movement.asContext(categories=category_list)
tmp_context.asComposedDocument = lambda *args: transformation
# Calculate the industrial phase list # Calculate the industrial phase list
previous_ind_phase_list = supply_chain.\ previous_ind_phase_list = supply_chain.\
getPreviousPackingListIndustrialPhaseList(current_supply_link) getPreviousPackingListIndustrialPhaseList(current_supply_link)
...@@ -228,7 +227,7 @@ class TransformationRule(TransformationSourcingRuleMixin, Rule): ...@@ -228,7 +227,7 @@ class TransformationRule(TransformationSourcingRuleMixin, Rule):
# Call getAggregatedAmountList # Call getAggregatedAmountList
# XXX expand failed if transformation is not defined. # XXX expand failed if transformation is not defined.
# Do we need to catch the exception ? # 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 # Add entries in the consumed_movement_dict
consumed_movement_dict = {} consumed_movement_dict = {}
for amount in amount_list: for amount in amount_list:
......
...@@ -98,9 +98,8 @@ class TestProductionOrderMixin(TestOrderMixin): ...@@ -98,9 +98,8 @@ class TestProductionOrderMixin(TestOrderMixin):
some categories for testing them some categories for testing them
""" """
TestOrderMixin.createCategories(self) TestOrderMixin.createCategories(self)
operation_category_list = ['operation1', 'operation2']
if len(self.category_tool.operation.contentValues()) == 0: 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( o = self.category_tool.operation.newContent(
portal_type='Category', portal_type='Category',
id=category_id) id=category_id)
......
# -*- 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)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment