[FIX] delivery_carrier,sale_giftcard: get the right shipping price even with gift card

Step:
- Create a product with sale price 120 USD
- Create a giftcard with balance 40 uSD
- Create a free Shipping cost of 40 USD fixed price and freeing above 100 USD
- Go to website->shop, select the product and checkout the cart(the shipping is free because price exceeds 100)
- Add the gift card to payment

Issue:
The shipping price gets from free to 40

Cause:
When computing the cost of the shipping the fact of the presence of a giftcard is not considered.

Solution:
Create a method to returns the amount of giftcard from a sale order and add to total price to check if the shipping is free

opw-3107284

closes odoo/odoo#120174

X-original-commit: c57184fd1c3d2846df4f618dee0027364eb62596
Signed-off-by: William Braeckman (wbr) <wbr@odoo.com>
Signed-off-by: Djoumatchoua Eteil Junior (etdj) <etdj@odoo.com>
This commit is contained in:
Eteil Djoumatchoua (etdj)
2023-05-16 13:36:59 +02:00
committed by Eteil Djoumatchoua(etdj)
parent 13de009694
commit 171aa0ec25
7 changed files with 126 additions and 4 deletions
+2 -1
View File
@@ -208,7 +208,8 @@ class DeliveryCarrier(models.Model):
# save the real price in case a free_over rule overide it to 0
res['carrier_price'] = res['price']
# free when order is large enough
if res['success'] and self.free_over and order._compute_amount_total_without_delivery() >= self.amount:
amount_without_delivery = order._compute_amount_total_without_delivery()
if res['success'] and self.free_over and self._compute_currency(order, amount_without_delivery, 'pricelist_to_company') >= self.amount:
res['warning_message'] = _('The shipping is free since the order amount exceeds %.2f.') % (self.amount)
res['price'] = 0.0
return res
+1 -1
View File
@@ -23,7 +23,7 @@ class SaleOrder(models.Model):
def _compute_amount_total_without_delivery(self):
self.ensure_one()
delivery_cost = sum([l.price_total for l in self.order_line if l.is_delivery])
return self.env['delivery.carrier']._compute_currency(self, self.amount_total - delivery_cost, 'pricelist_to_company')
return self.amount_total - delivery_cost
@api.depends('order_line')
def _compute_delivery_state(self):
@@ -3,3 +3,4 @@
from . import loyalty_program
from . import loyalty_reward
from . import sale_order
@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class SaleOrder(models.Model):
_inherit = "sale.order"
def _compute_amount_total_without_delivery(self):
self.ensure_one()
lines = self.order_line.filtered(lambda l: l.coupon_id)
return super()._compute_amount_total_without_delivery() - sum(lines.mapped('price_unit'))
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_loyalty_delivery
@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import common, Form
from odoo.exceptions import ValidationError
@common.tagged('post_install', '-at_install')
class TestLoyaltyDeliveryCost(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(TestLoyaltyDeliveryCost, cls).setUpClass()
cls.SaleOrder = cls.env['sale.order']
cls.partner_1 = cls.env['res.partner'].create({'name': 'My Test Customer'})
cls.pricelist = cls.env['product.pricelist'].create({
'name': 'Test Pricelist',
})
cls.product_4 = cls.env['product.product'].create({'name': 'A product to deliver'})
cls.product_uom_unit = cls.env.ref('uom.product_uom_unit')
def test_delivery_cost_gift_card(self):
"""
A customer has a carrier with the amount greater than the one to have
free shipping cost, then uses a gift card that lowers that amount to less
than the threshold: the shipping cost should still be 0.0
"""
product_delivery_free = self.env['product.product'].create({
'name': 'Free Delivery Charges',
'type': 'service',
'list_price': 40.0,
'categ_id': self.env.ref('delivery.product_category_deliveries').id,
})
free_delivery = self.env['delivery.carrier'].create({
'name': 'Delivery Now Free Over 100',
'fixed_price': 40,
'delivery_type': 'fixed',
'product_id': product_delivery_free.id,
'free_over': True,
'amount': 100,
})
program_gift_card = self.env['loyalty.program'].create({
'name': 'Gift Cards',
'applies_on': 'future',
'program_type': 'gift_card',
'trigger': 'auto',
'reward_ids': [(0, 0, {
'reward_type': 'discount',
'discount': 1,
'discount_mode': 'per_point',
'discount_applicability': 'order',
})]
})
self.env['loyalty.generate.wizard'].with_context(active_id=program_gift_card.id).create({
'coupon_qty': 1,
'points_granted': 40,
}).generate_coupons()
gift_card = program_gift_card.coupon_ids[0]
sale_normal_delivery_charges = self.SaleOrder.create({
'partner_id': self.partner_1.id,
'partner_invoice_id': self.partner_1.id,
'partner_shipping_id': self.partner_1.id,
'pricelist_id': self.pricelist.id,
'order_line': [(0, 0, {
'name': 'PC Assamble + 2GB RAM',
'product_id': self.product_4.id,
'product_uom_qty': 1,
'product_uom': self.product_uom_unit.id,
'price_unit': 120.00,
})]
})
self._apply_promo_code(sale_normal_delivery_charges, gift_card.code)
sale_normal_delivery_charges.action_confirm()
delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
'default_order_id': sale_normal_delivery_charges.id,
'default_carrier_id': free_delivery.id,
}))
delivery_wizard.save().button_confirm()
self.assertEqual(len(sale_normal_delivery_charges.order_line), 3)
self.assertEqual(sale_normal_delivery_charges.amount_untaxed, 80.0, "Delivery cost is not Added")
def _apply_promo_code(self, order, code, no_reward_fail=True):
status = order._try_apply_code(code)
if 'error' in status:
raise ValidationError(status['error'])
if not status and no_reward_fail:
# Can happen if global discount got filtered out in `_get_claimable_rewards`
raise ValidationError('No reward to claim with this coupon')
coupons = self.env['loyalty.card']
rewards = self.env['loyalty.reward']
for coupon, coupon_rewards in status.items():
coupons |= coupon
rewards |= coupon_rewards
if len(coupons) == 1 and len(rewards) == 1:
status = order._apply_program_reward(rewards, coupons)
if 'error' in status:
raise ValidationError(status['error'])
@@ -165,8 +165,10 @@ class StockPicking(models.Model):
def send_to_shipper(self):
self.ensure_one()
res = self.carrier_id.send_shipping(self)[0]
if self.carrier_id.free_over and self.sale_id and self.sale_id._compute_amount_total_without_delivery() >= self.carrier_id.amount:
res['exact_price'] = 0.0
if self.carrier_id.free_over and self.sale_id:
amount_without_delivery = self.sale_id._compute_amount_total_without_delivery()
if self.carrier_id._compute_currency(self.sale_id, amount_without_delivery, 'pricelist_to_company') >= self.carrier_id.amount:
res['exact_price'] = 0.0
self.carrier_price = res['exact_price'] * (1.0 + (self.carrier_id.margin / 100.0))
if res['tracking_number']:
previous_pickings = self.env['stock.picking']