Skip to content

Commit 240b0aa

Browse files
committed
[FIX] tg_sale_loyalty: распространение is_accumulative на программы вида promotion
1 parent c94c2f0 commit 240b0aa

File tree

3 files changed

+93
-1
lines changed

3 files changed

+93
-1
lines changed

tg_sale_loyalty/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
from . import models
2+
from .post_load import post_load

tg_sale_loyalty/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"views/loyalty_program_views.xml",
1414
],
1515
"demo": [],
16-
"post_load": None,
16+
"post_load": "post_load",
1717
"pre_init_hook": None,
1818
"post_init_hook": None,
1919
"uninstall_hook": None,

tg_sale_loyalty/post_load.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import logging
2+
3+
_logger = logging.getLogger(__name__)
4+
5+
6+
def post_load():
7+
from odoo.addons.sale_loyalty.models.sale_order import (
8+
SaleOrder,
9+
_,
10+
defaultdict,
11+
float_is_zero,
12+
)
13+
14+
def _apply_program_reward(self, reward, coupon, **kwargs):
15+
"""
16+
Applies the reward to the order provided the given coupon has enough points.
17+
This method does not check for program rules.
18+
19+
This method also assumes the points added by the program triggers have already been computed.
20+
The temporary points are used if the program is applicable to the current order.
21+
22+
Returns a dict containing the error message or empty if everything went correctly.
23+
NOTE: A call to `_update_programs_and_rewards` is expected to reorder the discounts.
24+
"""
25+
self.ensure_one()
26+
# Use the old lines before creating new ones. These should already be in a 'reset' state.
27+
old_reward_lines = kwargs.get('old_lines', self.env['sale.order.line'])
28+
if reward.is_global_discount:
29+
global_discount_reward_lines = self._get_applied_global_discount_lines()
30+
global_discount_reward = global_discount_reward_lines.reward_id
31+
# changes start
32+
if global_discount_reward and global_discount_reward != reward and global_discount_reward.discount >= reward.discount and (global_discount_reward.program_id.is_accumulative is False or reward.program_id.is_accumulative is False):
33+
return {'error': _('A better global discount is already applied.')}
34+
# changes end
35+
elif global_discount_reward and global_discount_reward != reward:
36+
# Invalidate the old global discount as it may impact the new discount to apply
37+
global_discount_reward_lines._reset_loyalty(True)
38+
old_reward_lines |= global_discount_reward_lines
39+
if not reward.program_id.is_nominative and reward.program_id.applies_on == 'future' and coupon in self.coupon_point_ids.coupon_id:
40+
return {'error': _('The coupon can only be claimed on future orders.')}
41+
elif self._get_real_points_for_coupon(coupon) < reward.required_points:
42+
return {'error': _('The coupon does not have enough points for the selected reward.')}
43+
reward_vals = self._get_reward_line_values(reward, coupon, **kwargs)
44+
self._write_vals_from_reward_vals(reward_vals, old_reward_lines)
45+
return {}
46+
47+
SaleOrder._apply_program_reward = _apply_program_reward
48+
49+
def _get_claimable_rewards(self, forced_coupons=None):
50+
"""
51+
Fetch all rewards that are currently claimable from all concerned coupons,
52+
meaning coupons from applied programs and applied rewards or the coupons given as parameter.
53+
54+
Returns a dict containing the all the claimable rewards grouped by coupon.
55+
Coupons that can not claim any reward are not contained in the result.
56+
"""
57+
self.ensure_one()
58+
all_coupons = forced_coupons or (self.coupon_point_ids.coupon_id | self.order_line.coupon_id | self.applied_coupon_ids)
59+
has_payment_reward = any(line.reward_id.program_id.is_payment_program for line in self.order_line)
60+
total_is_zero = float_is_zero(self.amount_total, precision_digits=2)
61+
result = defaultdict(lambda: self.env['loyalty.reward'])
62+
global_discount_reward = self._get_applied_global_discount()
63+
active_products_domain = self.env['loyalty.reward']._get_active_products_domain()
64+
for coupon in all_coupons:
65+
# Skip coupons generated by this order that only apply on future orders
66+
if coupon.program_id.applies_on == 'future' and coupon.order_id == self:
67+
continue
68+
points = self._get_real_points_for_coupon(coupon)
69+
for reward in coupon.program_id.reward_ids:
70+
71+
if reward.is_global_discount and global_discount_reward and global_discount_reward.discount >= reward.discount and (global_discount_reward.program_id.is_accumulative is False or reward.program_id.is_accumulative is False):
72+
continue
73+
74+
# Discounts are not allowed if the total is zero unless there is a payment reward, in which case we allow discounts.
75+
# If the total is 0 again without the payment reward it will be removed.
76+
is_discount = reward.reward_type == 'discount'
77+
is_payment_program = reward.program_id.is_payment_program
78+
if is_discount and total_is_zero and (not has_payment_reward or is_payment_program):
79+
continue
80+
# Skip discount that has already been applied if not part of a payment program
81+
if is_discount and not is_payment_program and reward in self.order_line.reward_id:
82+
continue
83+
if reward.reward_type == 'product' and not reward.filtered_domain(
84+
active_products_domain
85+
):
86+
continue
87+
if points >= reward.required_points:
88+
result[coupon] |= reward
89+
return result
90+
91+
SaleOrder._get_claimable_rewards = _get_claimable_rewards

0 commit comments

Comments
 (0)