Skip to content

Commit 2a8f648

Browse files
committed
Discount rule has spent amount including sub total option can cause wrong discount calculation if the cart contains a product several times
1 parent ee9a7c0 commit 2a8f648

File tree

4 files changed

+43
-17
lines changed

4 files changed

+43
-17
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
* Private messages: Fixes "No route in the route table matches the supplied values"
6161
* Payone: Hash string incorrect for frontend API payments where the order has more than 9 products
6262
* Export mail notification: Download link not working if SSL is enabled
63+
* Discount rule has spent amount including sub total option can cause wrong discount calculation if the cart contains a product several times
6364

6465

6566
## SmartStore.NET 2.5

src/Libraries/SmartStore.Services/Discounts/DiscountService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ public virtual bool IsDiscountValid(Discount discount, Customer customer, string
363363
Store = store
364364
};
365365

366-
if (!requirementRule.Value.CheckRequirement(request))
366+
// TODO: cache result... CheckRequirement is very often called
367+
if (!requirementRule.Value.CheckRequirement(request))
367368
return false;
368369
}
369370

src/Plugins/SmartStore.DiscountRules/Description.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Description: Contains common discount requirement rule providers like "Billing country is", "Customer role is", "Had spent amount" etc.
33
Group: Marketing
44
SystemName: SmartStore.DiscountRules
5-
Version: 2.5.0
5+
Version: 2.5.0.1
66
MinAppVersion: 2.5.0
77
DisplayOrder: 0
88
FileName: SmartStore.DiscountRules.dll

src/Plugins/SmartStore.DiscountRules/Providers/HadSpentAmountRule.cs

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
4+
using Newtonsoft.Json;
35
using SmartStore.Core.Domain.Orders;
6+
using SmartStore.Core.Logging;
47
using SmartStore.Core.Plugins;
5-
using SmartStore.Services.Discounts;
8+
using SmartStore.DiscountRules.Settings;
9+
using SmartStore.Services.Catalog;
610
using SmartStore.Services.Customers;
11+
using SmartStore.Services.Discounts;
712
using SmartStore.Services.Orders;
8-
using SmartStore.Services.Catalog;
913
using SmartStore.Services.Tax;
10-
using SmartStore.Core.Localization;
11-
using SmartStore.DiscountRules.Settings;
12-
using Newtonsoft.Json;
1314

1415
namespace SmartStore.DiscountRules
1516
{
@@ -21,15 +22,18 @@ public partial class HadSpentAmountRule : DiscountRequirementRuleBase
2122
private readonly IOrderService _orderService;
2223
private readonly IPriceCalculationService _priceCalculationService;
2324
private readonly ITaxService _taxService;
25+
private readonly ILogger _logger;
2426

2527
public HadSpentAmountRule(
2628
IOrderService orderService,
2729
IPriceCalculationService priceCalculationService,
28-
ITaxService taxService)
30+
ITaxService taxService,
31+
ILogger logger)
2932
{
30-
this._orderService = orderService;
31-
this._priceCalculationService = priceCalculationService;
32-
this._taxService = taxService;
33+
_orderService = orderService;
34+
_priceCalculationService = priceCalculationService;
35+
_taxService = taxService;
36+
_logger = logger;
3337
}
3438

3539
public override bool CheckRequirement(CheckDiscountRequirementRequest request)
@@ -88,14 +92,34 @@ private bool CheckTotalHistoryRequirement(CheckDiscountRequirementRequest reques
8892

8993
private bool CheckCurrentSubTotalRequirement(CheckDiscountRequirementRequest request)
9094
{
91-
var cartItems = request.Customer.GetCartItems(ShoppingCartType.ShoppingCart, request.Store.Id);
95+
var spentAmount = decimal.Zero;
9296

93-
decimal spentAmount = decimal.Zero;
94-
decimal taxRate = decimal.Zero;
95-
foreach (var sci in cartItems)
97+
try
9698
{
97-
// includeDiscounts == true produces a stack overflow!
98-
spentAmount += sci.Item.Quantity * _taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetUnitPrice(sci, false), out taxRate);
99+
var taxRate = decimal.Zero;
100+
var cartItems = request.Customer.GetCartItems(ShoppingCartType.ShoppingCart, request.Store.Id);
101+
102+
foreach (var cartItem in cartItems)
103+
{
104+
var product = cartItem.Item.Product;
105+
Dictionary<string, object> mergedValuesClone = null;
106+
107+
// we must reapply merged values because CheckCurrentSubTotalRequirement uses price calculation and is called by it itself.
108+
// this can cause wrong discount calculation if the cart contains a product several times.
109+
if (product.MergedDataValues != null)
110+
mergedValuesClone = new Dictionary<string, object>(product.MergedDataValues);
111+
112+
// includeDiscounts == true produces a stack overflow!
113+
spentAmount += cartItem.Item.Quantity * _taxService.GetProductPrice(product, _priceCalculationService.GetUnitPrice(cartItem, false), out taxRate);
114+
115+
if (mergedValuesClone != null)
116+
product.MergedDataValues = new Dictionary<string, object>(mergedValuesClone);
117+
}
118+
}
119+
catch (Exception exception)
120+
{
121+
_logger.Error(exception);
122+
return false;
99123
}
100124

101125
return spentAmount >= request.DiscountRequirement.SpentAmount;

0 commit comments

Comments
 (0)