[FIX] sale_coupon_delivery: Do not unlink reward line if 'free_shipping'

The methods delivery_set and delivery_unset are called everywhere (mostly on the ecommerce). The reasons for that is that we do not want several shipping lines on the same order. A better way to achieve this would have been to create the line if it doesn't exist or write on it to modify the 'price_unit' instead.

The side effect of that behavior is:
- A delivery line is set on the order.
- We apply a coupon to get a free shipping
- We go on the payment page. The method _cart_update is called, which calls delivery_set, so delivery_unset. The shipping line is unlinked to create again a new shipping line with the price updated. As the shipping line is removed, a recomputation of the reward lines is made. The program isn't applicable anymore as there's no shipping line on the order. The reward is thus removed.

That way, it's impossible to have a free shipping reward on the ecommerce and achieve the full checkout process.

What's done in this commit:

If a free shipping is applicable by code or if a free shipping can be automatically applied. It will be done with a price of 0.0 if there's no shipping line or the price_unit on the shipping line if set. If the shipping line is removed (every 2 seconds on a checkout process), the reward line is not unlinked and the price is set to 0.0.

That way, it's now possible to make a full flow.

NB: If a line is unlinked on an order, we unlink the reward line if it's the last one set on the order. This is to avoid free shipping line coming back on a new order in the ecommerce even if not applicable.
This commit is contained in:
Yannick Tivisse
2017-02-24 11:01:23 +01:00
parent 3b71aeb77c
commit 12a06dcfa6
2 changed files with 24 additions and 6 deletions
+3 -5
View File
@@ -13,14 +13,12 @@ class SaleCouponProgram(models.Model):
Returns the programs when the reward is actually in the order lines
"""
programs = super(SaleCouponProgram, self)._filter_not_ordered_reward_programs(order)
for program in self:
if program.reward_type == 'free_shipping' and \
not order.order_line.filtered(lambda line: line.is_delivery):
programs -= program
# Do not filter on free delivery programs. As delivery_unset is called everywhere (which is
# rather stupid), the delivery line is unliked to be created again instead of writing on it to
# modify the price_unit. That way, the reward is unlink and is not set back again.
return programs
def _check_promo_code(self, order, coupon_code):
if self.reward_type == 'free_shipping' and not order.order_line.filtered(lambda line: line.is_delivery):
return {'error': _('The shipping costs are not in the order lines.')}
return super(SaleCouponProgram, self)._check_promo_code(order, coupon_code)
+21 -1
View File
@@ -24,7 +24,7 @@ class SaleOrder(models.Model):
return {
'name': "Discount: %s" % (program.name),
'product_id': program.discount_line_product_id.id,
'price_unit': - delivery_line.price_unit,
'price_unit': delivery_line and - delivery_line.price_unit or 0.0,
'product_uom_qty': 1.0,
'product_uom': program.discount_line_product_id.uom_id.id,
'order_id': self.id,
@@ -34,3 +34,23 @@ class SaleOrder(models.Model):
def _get_lines_unit_prices(self):
return [x.price_unit for x in self.order_line.filtered(lambda x: not x.is_delivery and not x.program_id)]
class SalesOrderLine(models.Model):
_inherit = "sale.order.line"
def unlink(self):
# Due to delivery_set and delivery_unset methods that are called everywhere, don't unlink
# reward lines if it's a free shipping
orders = self.mapped('order_id')
applied_programs = orders.mapped('no_code_promo_program_ids') + \
orders.mapped('code_promo_program_id') + \
orders.mapped('applied_coupon_ids').mapped('program_id')
free_shipping_products = applied_programs.filtered(
lambda program: program.reward_type == 'free_shipping'
).mapped('discount_line_product_id')
lines_to_unlink = self.filtered(lambda line: line.product_id not in free_shipping_products)
# Unless these lines are the last ones
res = super(SalesOrderLine, lines_to_unlink).unlink()
only_free_shipping_line_orders = orders.filtered(lambda order: len(order.order_line.ids) == 1 and order.order_line.is_reward_line)
super(SalesOrderLine, only_free_shipping_line_orders.mapped('order_line')).unlink()
return res