[FIX] delivery: fix price when variable is weight*volume

Before this commit, when using a shipping method with the variable
weight*volume for price computation, the price was growing with the
square of the ordered quantities. This is because both volume and
weight were multiplied by the quantity, before being multiplied with
each other in the next step.

This commit fixes the issue by introducing the variable weight*volume
at the beginning of the computation.

In order not to break anything in stable, the new variable is added as a
kwarg to the useful methods.

OPW-3802315

closes odoo/odoo#159007

X-original-commit: 0a8db0fa14bb63abd0b2a8f0234d86700b6c1e2e
Signed-off-by: Vallaeys Valentin (vava) <vava@odoo.com>
This commit is contained in:
vava-odoo
2024-03-23 14:11:53 +00:00
parent 16d8438955
commit a941cd62bb
2 changed files with 45 additions and 6 deletions
+7 -6
View File
@@ -333,7 +333,7 @@ class DeliveryCarrier(models.Model):
self.ensure_one()
self = self.sudo()
order = order.sudo()
total = weight = volume = quantity = 0
total = weight = volume = quantity = wv = 0
total_delivery = 0.0
for line in order.order_line:
if line.state == 'cancel':
@@ -347,6 +347,7 @@ class DeliveryCarrier(models.Model):
qty = line.product_uom._compute_quantity(line.product_uom_qty, line.product_id.uom_id)
weight += (line.product_id.weight or 0.0) * qty
volume += (line.product_id.volume or 0.0) * qty
wv += (line.product_id.weight or 0.0) * (line.product_id.volume or 0.0) * qty
quantity += qty
total = (order.amount_total or 0.0) - total_delivery
@@ -356,23 +357,23 @@ class DeliveryCarrier(models.Model):
# 2- saved weight to use on sale order
# 3- total order line weight as fallback
weight = self.env.context.get('order_weight') or order.shipping_weight or weight
return self._get_price_from_picking(total, weight, volume, quantity)
return self._get_price_from_picking(total, weight, volume, quantity, wv=wv)
def _get_price_dict(self, total, weight, volume, quantity):
def _get_price_dict(self, total, weight, volume, quantity, wv=0.):
'''Hook allowing to retrieve dict to be used in _get_price_from_picking() function.
Hook to be overridden when we need to add some field to product and use it in variable factor from price rules. '''
return {
'price': total,
'volume': volume,
'weight': weight,
'wv': volume * weight,
'wv': wv or volume * weight,
'quantity': quantity
}
def _get_price_from_picking(self, total, weight, volume, quantity):
def _get_price_from_picking(self, total, weight, volume, quantity, wv=0.):
price = 0.0
criteria_found = False
price_dict = self._get_price_dict(total, weight, volume, quantity)
price_dict = self._get_price_dict(total, weight, volume, quantity, wv=wv)
if self.free_over and total >= self.amount:
return 0
for line in self.price_rule_ids:
@@ -353,3 +353,41 @@ class TestDeliveryCost(common.TransactionCase):
('is_delivery', '=', True)
])
self.assertEqual(line.price_unit, self.normal_delivery.fixed_price)
def test_price_with_weight_volume_variable(self):
""" Test that the price is correctly computed when the variable is weight*volume. """
qty = 3
list_price = 2
volume = 2.5
weight = 1.5
sale_order = self.env['sale.order'].create({
'partner_id': self.partner_18.id,
'order_line': [
(0, 0, {
'product_id': self.env['product.product'].create({
'name': 'wv',
'weight': weight,
'volume': volume,
}).id,
'product_uom_qty': qty,
'product_uom': self.product_uom_unit.id,
}),
],
})
delivery = self.env['delivery.carrier'].create({
'name': 'Delivery Charges',
'delivery_type': 'base_on_rule',
'product_id': self.product_delivery_normal.id,
'price_rule_ids': [(0, 0, {
'variable': 'price',
'operator': '>=',
'max_value': 0,
'list_price': list_price,
'variable_factor': 'wv',
})]
})
self.assertEqual(
delivery._get_price_available(sale_order),
qty * list_price * weight * volume,
"The shipping price is not correctly computed with variable weight*volume.",
)