diff --git a/product/ERP5/AggregatedAmountList.py b/product/ERP5/AggregatedAmountList.py index 71499d8ed9108a1464b11f2f8c44d23e210f691e..9f079dff5d919ead5b0550a66f9887c9a151223d 100644 --- a/product/ERP5/AggregatedAmountList.py +++ b/product/ERP5/AggregatedAmountList.py @@ -27,15 +27,13 @@ # ############################################################################## -from UserList import UserList - import zope.interface from Products.ERP5Type import interfaces from Products.ERP5Type.Globals import InitializeClass from Products.PythonScripts.Utility import allow_class from AccessControl import ClassSecurityInfo -class AggregatedAmountList(UserList): +class AggregatedAmountList(list): """ Temporary object needed to aggregate Amount value And to calculate some report or total value diff --git a/product/ERP5/Document/Resource.py b/product/ERP5/Document/Resource.py index 82e56e6416736f711f9d6e728078577675c9ea70..a5c44ab582e6a6af73625508cf9bfd606597f061 100644 --- a/product/ERP5/Document/Resource.py +++ b/product/ERP5/Document/Resource.py @@ -658,21 +658,19 @@ class Resource(XMLObject, XMLMatrix, VariatedMixin): Get all pricing parameters from Predicate. """ # Search all categories context - new_category_list = [] - if context is not None: - new_category_list += context.getCategoryList() + if context is None: + new_category_list = [] + else: + new_category_list = context.getCategoryList() #XXX This should be 'category_list' instead of 'categories' to respect # the naming convention. Must take care of side effects when fixing - if kw.has_key('categories'): - new_category_list.extend(kw['categories']) - del kw['categories'] + new_category_list += kw.pop('categories', ()) resource_category = 'resource/' + self.getRelativeUrl() if not resource_category in new_category_list: - new_category_list += (resource_category, ) + new_category_list.append(resource_category) # Generate the predicate mapped value # to get some price values. portal = self.getPortalObject() - domain_tool = getToolByName(portal, 'portal_domains') if supply_path_type is None: portal_type_list = kw.pop('portal_type', portal.getPortalSupplyPathTypeList()) @@ -681,17 +679,20 @@ class Resource(XMLObject, XMLMatrix, VariatedMixin): else: portal_type_list = (supply_path_type,) + sort_method = kw.pop('sort_method', self._pricingSortMethod) # Generate the fake context - tmp_context = self.asContext(context=context, - categories=new_category_list, - REQUEST=REQUEST, **kw) - tmp_kw = kw.copy() - if 'sort_method' not in tmp_kw: - tmp_kw['sort_method'] = self._pricingSortMethod - mapped_value = domain_tool.generateMultivaluedMappedValue( + tmp_context = context.asContext(categories=new_category_list, + REQUEST=REQUEST, **kw) + # XXX When called for a generated amount, base_application may point + # to nonexistant base_amount (e.g. "produced_quantity" for + # transformations), which would make domain tool return nothing. + # Following hack cleans up a category we don't want to test anyway. + tmp_context.setBaseApplication(None) + mapped_value = portal.portal_domains.generateMultivaluedMappedValue( tmp_context, portal_type=portal_type_list, - has_cell_content=0, **tmp_kw) + has_cell_content=0, + sort_method=sort_method, **kw) # Get price parameters price_parameter_dict = { 'base_price': None, diff --git a/product/ERP5/Document/TradeModelLine.py b/product/ERP5/Document/TradeModelLine.py index 6d9eb6d3d2534ce848c469d60b0aa6fc44547bc2..adf84159744566a1d04ac16e834af1af195933cd 100644 --- a/product/ERP5/Document/TradeModelLine.py +++ b/product/ERP5/Document/TradeModelLine.py @@ -63,7 +63,7 @@ class TradeModelLine(AmountGeneratorLine): if self._baseGetQuantity(None) is not None: return ('quantity', 'price', 'step') # Else tax provides only a ratio on amount - return ('price', 'efficiency') + return ('price',) def getMappedValueBaseCategoryList(self): return self._baseGetMappedValueBaseCategoryList() or ('trade_phase',) diff --git a/product/ERP5/Document/Transformation.py b/product/ERP5/Document/Transformation.py index 623f954bc82e01fee94a8d34d1f78c5cb18ba25f..266ed8dd3085c5f6a82c85807d5333233dcebf74 100644 --- a/product/ERP5/Document/Transformation.py +++ b/product/ERP5/Document/Transformation.py @@ -92,6 +92,7 @@ class Transformation(MappedValue, VariatedMixin, Amount, AmountGeneratorMixin): # XXX add a 'transformation_amount_generator' group type kw['amount_generator_type_list'] = ('Transformation', 'Transformed Resource', + 'Transformation Operation', 'Assorted Resource') if context is not None: context = (context,) diff --git a/product/ERP5/Document/TransformedResource.py b/product/ERP5/Document/TransformedResource.py index fd2e740e52fb576efdf1b92205758cf92db2202b..c302d49c8c88dc0638497e8d9043bc2a5c4f53c9 100644 --- a/product/ERP5/Document/TransformedResource.py +++ b/product/ERP5/Document/TransformedResource.py @@ -63,8 +63,7 @@ class TransformedResource(AmountGeneratorLine): # Provide default mapped value properties and categories if # not defined def getMappedValuePropertyList(self): - return self._baseGetMappedValuePropertyList() or ( - 'converted_quantity', 'efficiency') + return self._baseGetMappedValuePropertyList() or ('quantity',) def getMappedValueBaseCategoryList(self): result = self._baseGetMappedValueBaseCategoryList() diff --git a/product/ERP5/mixin/amount_generator.py b/product/ERP5/mixin/amount_generator.py index 1ec604e67838cf32353cd4cb20b63a116522f2fc..4fbacb9a3208c1cddb3023724d1bbbd0e246e569 100644 --- a/product/ERP5/mixin/amount_generator.py +++ b/product/ERP5/mixin/amount_generator.py @@ -30,6 +30,7 @@ import random import zope.interface from AccessControl import ClassSecurityInfo from Acquisition import Implicit +from Products.ERP5.AggregatedAmountList import AggregatedAmountList from Products.ERP5Type import Permissions, interfaces from Products.ERP5Type.TransactionalVariable import getTransactionalVariable from Products.ERP5.Document.MappedValue import MappedValue @@ -167,7 +168,7 @@ class AmountGeneratorMixin: portal.getPortalAmountGeneratorCellTypeList() # Set empty result by default - result = [] + result = AggregatedAmountList() args = (getTransactionalVariable().setdefault( "amount_generator.BaseAmountDict", {}), @@ -230,15 +231,20 @@ class AmountGeneratorMixin: 'base_contribution_set': set(), 'category_list': [], 'causality_value_list': [], + 'efficiency': self.getEfficiency(), + 'quantity_unit': self.getQuantityUnit(), # XXX If they are several cells, we have duplicate references. 'reference': self.getReference(), } # Then collect the mapped values (quantity, price, trade_phase...) for key in cell.getMappedValuePropertyList(): + if key in ('net_converted_quantity', + 'net_quantity', 'converted_quantity'): + # XXX only 'quantity' is accepted and it is treated + # as if it was 'converted_quantity' + raise NotImplementedError # XXX-JPS Make sure handling of list properties can be handled - dict_key = key in ('net_quantity', 'converted_quantity', - 'net_converted_quantity') and 'quantity' or key - property_dict[dict_key] = cell.getProperty(key) + property_dict[key] = cell.getProperty(key) category_list = cell.getAcquiredCategoryMembershipList( cell.getMappedValueBaseCategoryList(), base=1) property_dict['category_list'] += category_list @@ -276,9 +282,7 @@ class AmountGeneratorMixin: # base_contribution_list - needed to produce reports with # getTotalPrice # 'efficiency' is stored separately in the generated amount, - # for future simulation of efficiencies (use net_quantity otherwise). - # 'converted_quantity' is used preferrably to 'quantity' since we - # need values converted to the default management unit. + # for future simulation of efficiencies. # If no quantity is provided, we consider that the value is 1.0 # (XXX is it OK ?) XXX-JPS Need careful review with taxes quantity = float(sum(map(base_amount.getGeneratedAmountQuantity, @@ -297,6 +301,8 @@ class AmountGeneratorMixin: # we only want the id to be unique so we pick a random causality causality_value.getRelativeUrl().replace('/', '_')) amount._setCategoryList(property_dict.pop('category_list', ())) + if amount.getQuantityUnit(): + del property_dict['quantity_unit'] amount._edit( quantity=quantity, # XXX Are title, int_index and description useful ?? @@ -304,6 +310,9 @@ class AmountGeneratorMixin: int_index=self.getIntIndex(), description=self.getDescription(), **property_dict) + # convert to default management unit if possible + amount._setQuantity(amount.getConvertedQuantity()) + amount._setQuantityUnit(amount.getResourceDefaultQuantityUnit()) if rounding: # We hope here that rounding is sufficient at line level amount = getRoundingProxy(amount, context=self) @@ -341,7 +350,7 @@ class AmountGeneratorMixin: amount_list=amount_list, rounding=rounding, amount_generator_type_list=amount_generator_type_list) aggregated_amount_dict = {} - result_list = [] + result_list = AggregatedAmountList() for amount in generated_amount_list: key = (amount.getPrice(), amount.getEfficiency(), amount.getReference(), amount.categories) diff --git a/product/ERP5/tests/testApparelTransformation.py b/product/ERP5/tests/testApparelTransformation.py index a4440e88dac6da65078c13e41dac4bab6fc133d8..87c270bddbe7d7b5bde2aa6c8fa77688f108666a 100644 --- a/product/ERP5/tests/testApparelTransformation.py +++ b/product/ERP5/tests/testApparelTransformation.py @@ -155,7 +155,8 @@ class TestApparelTransformation(TestOrderMixin, ERP5TypeTestCase): portal = self.getPortal() operation_dict = {} for operation_name in ('piquage', 'taillage'): - operation = portal.portal_categories.operation.newContent(id=operation_name) + operation = portal.portal_categories.operation.newContent(operation_name, + quantity_unit='time/min') operation_dict[operation_name] = operation sequence.edit(operation_dict=operation_dict) @@ -331,8 +332,7 @@ class TestApparelTransformation(TestOrderMixin, ERP5TypeTestCase): operation.edit( title = op_name, quantity = 10., - categories = operation.getCategoryList() + [ 'resource/' + operation_dict[op_name].getRelativeUrl(), - 'quantity_unit/time/min'], + resource_value=operation_dict[op_name], int_index=4, ) @@ -346,8 +346,7 @@ class TestApparelTransformation(TestOrderMixin, ERP5TypeTestCase): operation = transformation.newContent(portal_type=self.operation_portal_type) operation.edit( title = op_name, - categories = operation.getCategoryList() + [ 'resource/' + operation_dict[op_name].getRelativeUrl(), - 'quantity_unit/time/min'], + resource_value=operation_dict[op_name], int_index=5, ) base_category_list = ['size'] @@ -629,21 +628,17 @@ class TestApparelTransformation(TestOrderMixin, ERP5TypeTestCase): produced_resource = transformation.getResource() production_order_module = self.portal.getDefaultModule("Production Order") production_order = production_order_module.newContent( - portal_type="Production Order") + portal_type="Production Order", + temp_object=1, + specialise_value=transformation) for i, expected in enumerate(expected_list): context = production_order.newContent( - portal_type="Production Order Line") - context.edit( - quantity = 1.0, - variation_category_list = expected['id'], - resource = produced_resource, - specialise=transformation.getRelativeUrl(), + portal_type="Production Order Line", + quantity=1, + variation_category_list=expected['id'], + resource=produced_resource, ) - aggregated_amount_list = context.getAggregatedAmountList( - amount_generator_type_list=("Transformation", - "Transformation Transformed Resource", - "Transformation Operation", - )) + aggregated_amount_list = context.getAggregatedAmountList() expected_amount_list = expected['amount'] expected_amount_list_len = len(expected_amount_list)