Commit 3b0e01ed authored by Jérome Perrin's avatar Jérome Perrin

pdm: support defining price in another quantity unit

So far price were always assumed to be defined in the default
quantity unit of the resource, even though supply lines had a
quantity unit field, it was ignored. But it can be useful to
define prices using another quantity unit than the default quantity
unit of the resource, for example when a resource is purchased
in kg but managed in m³.

To support such scenario, we adjust the priced quantity unit
when applying price.
parent 258b75ba
# coding: utf-8
result = context.getPriceParameterDict(context=movement, **kw) result = context.getPriceParameterDict(context=movement, **kw)
# Calculate # Calculate
...@@ -76,7 +77,22 @@ unit_base_price *= 1 + result["surcharge_ratio"] ...@@ -76,7 +77,22 @@ unit_base_price *= 1 + result["surcharge_ratio"]
# Divide by the priced quantity # Divide by the priced quantity
priced_quantity = result['priced_quantity'] priced_quantity = result['priced_quantity']
if priced_quantity: # If this priced quantity is in a different quantity unit from the
# resource's default quantity unit, we have to convert this quantity
# to the resource quantity unit.
# For example, if we have a resource managed in Kilogram and we have
# a supply line saying that the price for 250 Grams is 100€, we adjust this
# priced quantity to be 0.25 (Kilogram)
supply_line_quantity_unit = next(iter(result.get('quantity_unit', ())), None)
resource_default_quantity_unit = context.getDefaultQuantityUnit()
if resource_default_quantity_unit != supply_line_quantity_unit:
priced_quantity = context.convertQuantity(
priced_quantity or 1,
supply_line_quantity_unit,
resource_default_quantity_unit,
movement.getVariationCategoryList()
)
if priced_quantity and priced_quantity != 1:
unit_base_price /= priced_quantity unit_base_price /= priced_quantity
result["price"] = unit_base_price result["price"] = unit_base_price
......
...@@ -35,9 +35,10 @@ if context.getParentValue().getParentValue().getPortalType() in ( ...@@ -35,9 +35,10 @@ if context.getParentValue().getParentValue().getPortalType() in (
#backwards compatibility #backwards compatibility
mapped_value_property_list = context.getMappedValuePropertyList() mapped_value_property_list = context.getMappedValuePropertyList()
if not 'priced_quantity' in mapped_value_property_list: for mapped_property in ('priced_quantity', 'quantity_unit'):
mapped_value_property_list.append('priced_quantity') if not mapped_property in mapped_value_property_list:
context.setMappedValuePropertyList(mapped_value_property_list) mapped_value_property_list.append(mapped_property)
context.setMappedValuePropertyList(mapped_value_property_list)
# XXX: An hack that the context cell may not have the start_date_range_min/max properties. # XXX: An hack that the context cell may not have the start_date_range_min/max properties.
# But they don't acquire it parent the properties. # But they don't acquire it parent the properties.
......
...@@ -36,9 +36,10 @@ if context.getParentValue().getPortalType() in ( ...@@ -36,9 +36,10 @@ if context.getParentValue().getPortalType() in (
#backwards compatibility #backwards compatibility
mapped_value_property_list = context.getMappedValuePropertyList() mapped_value_property_list = context.getMappedValuePropertyList()
if not 'priced_quantity' in mapped_value_property_list: for mapped_property in ('priced_quantity', 'quantity_unit'):
mapped_value_property_list.append('priced_quantity') if not mapped_property in mapped_value_property_list:
context.setMappedValuePropertyList(mapped_value_property_list) mapped_value_property_list.append(mapped_property)
context.setMappedValuePropertyList(mapped_value_property_list)
return context.generatePredicate(membership_criterion_base_category_list = base_category_tuple, return context.generatePredicate(membership_criterion_base_category_list = base_category_tuple,
criterion_property_list = ('start_date',)) criterion_property_list = ('start_date',))
...@@ -9,4 +9,5 @@ context.setMappedValuePropertyList([ ...@@ -9,4 +9,5 @@ context.setMappedValuePropertyList([
'surcharge_ratio', 'variable_additional_price', 'surcharge_ratio', 'variable_additional_price',
'non_discountable_additional_price', 'non_discountable_additional_price',
'priced_quantity', 'base_unit_price', 'priced_quantity', 'base_unit_price',
'quantity_unit',
]) ])
...@@ -176,6 +176,13 @@ class TestResource(ERP5TypeTestCase): ...@@ -176,6 +176,13 @@ class TestResource(ERP5TypeTestCase):
self.quantity_unit_liter = quantity_unit_volume.newContent( self.quantity_unit_liter = quantity_unit_volume.newContent(
portal_type='Category', id='liter') portal_type='Category', id='liter')
self.metric_type_volume = self.portal.portal_categories.metric_type._getOb(
'volume', None)
if self.metric_type_volume is None:
self.metric_type_volume = self.portal.portal_categories.metric_type.newContent(
id='volume',
portal_type='Category')
unit_conversion_module = self.portal.quantity_unit_conversion_module unit_conversion_module = self.portal.quantity_unit_conversion_module
weight_group = unit_conversion_module._getOb('weight', None) weight_group = unit_conversion_module._getOb('weight', None)
if weight_group is None: if weight_group is None:
...@@ -192,6 +199,22 @@ class TestResource(ERP5TypeTestCase): ...@@ -192,6 +199,22 @@ class TestResource(ERP5TypeTestCase):
quantity=0.001) quantity=0.001)
gram_definition.validate() gram_definition.validate()
volume_group = unit_conversion_module._getOb('volume', None)
if volume_group is None:
volume_group = unit_conversion_module.newContent(
id='volume',
portal_type='Quantity Unit Conversion Group',
quantity_unit_value=self.quantity_unit_liter)
volume_group.validate()
liter_definition = volume_group._getOb('liter', None)
if liter_definition is None:
liter_definition = volume_group.newContent(
id='liter',
portal_type='Quantity Unit Conversion Definition',
quantity_unit_value=self.quantity_unit_liter,
quantity=1)
liter_definition.validate()
# create some product line categories # create some product line categories
product_line = self.portal.portal_categories.product_line product_line = self.portal.portal_categories.product_line
if product_line._getOb('a', None) is None: if product_line._getOb('a', None) is None:
...@@ -1043,6 +1066,62 @@ class TestResource(ERP5TypeTestCase): ...@@ -1043,6 +1066,62 @@ class TestResource(ERP5TypeTestCase):
self.assertEqual(1, sale_order_line.getPrice()) self.assertEqual(1, sale_order_line.getPrice())
self.assertEqual(5000, sale_order_line.getTotalPrice()) self.assertEqual(5000, sale_order_line.getTotalPrice())
def testGetPriceDefinedInDifferentQuantityUnit(self):
resource = self.portal.getDefaultModule(self.product_portal_type)\
.newContent(portal_type=self.product_portal_type)
resource.setDefaultQuantityUnitValue(self.quantity_unit_kilo)
supply_line = resource.newContent(
portal_type=self.sale_supply_line_portal_type)
supply_line.setDefaultQuantityUnitValue(self.quantity_unit_gram)
supply_line.setBasePrice(5)
# price for 1 gram is 5, so price for 1 kg is 5000
self.tic()
sale_order = self.portal.getDefaultModule("Sale Order").newContent(
portal_type='Sale Order',)
sale_order_line = sale_order.newContent(
portal_type=self.sale_order_line_portal_type,
resource_value=resource,
quantity=5)
self.assertEqual(sale_order_line.getPrice(), 5000)
# price for 250g is 100
supply_line.setPricedQuantity(250)
supply_line.setBasePrice(100)
self.tic()
# so for 1kg it is 400
sale_order_line.setPrice(None)
self.assertEqual(sale_order_line.getPrice(), 400)
def testGetPriceDefinedForDifferentMetric(self):
resource = self.portal.getDefaultModule(self.product_portal_type)\
.newContent(portal_type=self.product_portal_type)
resource.setQuantityUnitValueList([
self.quantity_unit_kilo,
self.quantity_unit_liter
])
# this resource exists in kg or liter, one Kg is 0.75 liter.
measure = resource.newContent(
portal_type='Measure'
)
measure.setMetricTypeValue(self.metric_type_volume)
measure.setQuantityUnitValue(self.quantity_unit_liter)
measure.setQuantity(0.75)
supply_line = resource.newContent(
portal_type=self.sale_supply_line_portal_type)
supply_line.setDefaultQuantityUnitValue(self.quantity_unit_liter)
supply_line.setBasePrice(4)
# price for 1l is 4, so price for 1kg is 3
self.tic()
sale_order = self.portal.getDefaultModule("Sale Order").newContent(
portal_type='Sale Order',)
sale_order_line = sale_order.newContent(
portal_type=self.sale_order_line_portal_type,
resource_value=resource,
quantity=1)
self.assertEqual(sale_order_line.getPrice(), 3)
def testGetPriceWithPricedQuantity(self): def testGetPriceWithPricedQuantity(self):
resource = self.portal.getDefaultModule(self.product_portal_type)\ resource = self.portal.getDefaultModule(self.product_portal_type)\
.newContent(portal_type=self.product_portal_type) .newContent(portal_type=self.product_portal_type)
......
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