[FIX] sale_loyalty: add ewallet and coupons to cart

Steps to reproduce:
- go to e-commerce;
- add two products (A and B) to the cart;
- apply an eWallet;
- apply a coupons which allows a 100% discount on product A.

Issue:
A traceback appears (Internal Server Error).

Cause:
We are trying to access a dictionary value
a key which does not exist.

Solution:
Correct the distribution of the amount of payment programs.

opw-3115066

closes odoo/odoo#110036

X-original-commit: 0654d87211d9d9319e94b87a8bc6469778633f02
Signed-off-by: William Braeckman (wbr) <wbr@odoo.com>
Signed-off-by: Lefebvre Thomas (thle) <thle@odoo.com>
This commit is contained in:
Thomas Lefebvre (thle)
2023-01-17 08:17:52 +01:00
parent cb243d6918
commit 42b5a8d86e
2 changed files with 116 additions and 5 deletions
+11 -3
View File
@@ -229,6 +229,7 @@ class SaleOrder(models.Model):
continue
discount_lines[line.reward_identifier_code] |= line
order_lines -= self.order_line.filtered("reward_id")
cheapest_line = False
for lines in discount_lines.values():
line_reward = lines.reward_id
@@ -252,12 +253,19 @@ class SaleOrder(models.Model):
# Fixed prices are per tax
discounted_amounts = {line.tax_id: abs(line.price_total) for line in lines}
for line in itertools.chain(non_common_lines, common_lines):
discounted_amount = discounted_amounts[line.tax_id]
# For gift card and eWallet programs we have no tax but we can consume the amount completely
if lines.reward_id.program_id.is_payment_program:
discounted_amount = discounted_amounts[lines.tax_id]
else:
discounted_amount = discounted_amounts[line.tax_id]
if discounted_amount == 0:
continue
remaining = remaining_amount_per_line[line]
consumed = min(remaining, discounted_amount)
discounted_amounts[line.tax_id] -= consumed
if lines.reward_id.program_id.is_payment_program:
discounted_amounts[lines.tax_id] -= consumed
else:
discounted_amounts[line.tax_id] -= consumed
remaining_amount_per_line[line] -= consumed
discountable = 0
@@ -310,7 +318,7 @@ class SaleOrder(models.Model):
converted_discount = self.currency_id._convert(min(max_discount, discountable), reward.currency_id, self.company_id, fields.Date.today())
point_cost = converted_discount / reward.discount
# Gift cards and eWallets are considered gift cards and should not have any taxes
if reward.program_id.program_type in ('ewallet', 'gift_card'):
if reward.program_id.is_payment_program:
return [{
'name': reward.description,
'product_id': reward.discount_line_product_id.id,
+105 -2
View File
@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import TransactionCase, tagged, new_test_user
from odoo.tests import tagged, new_test_user
from odoo.addons.sale_loyalty.tests.common import TestSaleCouponCommon
from odoo import Command
@tagged('post_install', '-at_install')
class TestLoyalty(TransactionCase):
class TestLoyalty(TestSaleCouponCommon):
@classmethod
def setUpClass(cls):
@@ -117,3 +119,104 @@ class TestLoyalty(TransactionCase):
# This last one will try to find related POS lines while user have not access to POS.
order._action_cancel()
self.assertFalse(order.coupon_point_ids)
def test_distribution_amount_payment_programs(self):
"""
Check how the amount of a payment reward is distributed.
An ewallet should not be used to refund taxes.
Its amount must be distributed between the products.
"""
# Create two products
product_a, product_b = self.env['product.product'].create([
{
'name': 'Product A',
'list_price': 100,
'sale_ok': True,
'taxes_id': [Command.set(self.tax_15pc_excl.ids)],
},
{
'name': 'Product B',
'list_price': 100,
'sale_ok': True,
'taxes_id': [Command.set(self.tax_15pc_excl.ids)],
},
])
# Create a coupon and a ewallet
coupon_program, ewallet_program = self.env['loyalty.program'].create([
{
'name': 'Coupon Program',
'program_type': 'coupons',
'trigger': 'with_code',
'applies_on': 'both',
'reward_ids': [Command.create({
'reward_type': 'discount',
'discount': 100.0,
'discount_applicability': 'specific',
'discount_product_domain': '[("name", "=", "Product A")]',
})],
},
{
'name': 'eWallet Program',
'program_type': 'ewallet',
'applies_on': 'future',
'trigger': 'auto',
'rule_ids': [Command.create({
'reward_point_mode': 'money',
})],
'reward_ids': [Command.create({
'discount_mode': 'per_point',
'discount': 1,
'discount_applicability': 'order',
})],
}
])
coupon_partner, _ = self.env['loyalty.card'].create([
{
'program_id': coupon_program.id,
'partner_id': self.partner_a.id,
'points': 1,
'code': '5555',
},
{
'program_id': ewallet_program.id,
'partner_id': self.partner_a.id,
'points': 115,
},
])
# Create the order
order = self.env['sale.order'].with_user(self.user_salemanager).create({
'partner_id': self.partner_a.id,
'order_line': [
Command.create({
'product_id': product_a.id,
}),
Command.create({
'product_id': product_b.id,
}),
]
})
self.assertEqual(order.amount_total, 230.0)
self.assertEqual(order.amount_untaxed, 200.0)
self.assertEqual(order.amount_tax, 30.0)
# Apply the eWallet
order._update_programs_and_rewards()
self._claim_reward(order, ewallet_program)
self.assertEqual(order.amount_total, 115.0)
self.assertEqual(order.amount_untaxed, 85.0)
self.assertEqual(order.amount_tax, 30.0)
self.assertEqual(order.reward_amount, -115.0)
# Apply the coupon
self._apply_promo_code(order, coupon_partner.code)
self.assertEqual(order.amount_total, 0.0)
self.assertEqual(order.amount_untaxed, -15.0)
self.assertEqual(order.amount_tax, 15.0)
self.assertEqual(order.reward_amount, -215.0)