Skip to content

Commit 114dc22

Browse files
authored
#376 Discount - by percent of product price and bug fixed (#394)
1 parent 495c1dc commit 114dc22

File tree

9 files changed

+87
-31
lines changed

9 files changed

+87
-31
lines changed

src/Modules/SimplCommerce.Module.Orders/Controllers/OrderApiController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ public async Task<IActionResult> Get(long id)
183183
ProductName = x.Product.Name,
184184
ProductPrice = x.ProductPrice,
185185
Quantity = x.Quantity,
186+
DiscountAmount = x.DiscountAmount,
186187
TaxAmount = x.TaxAmount,
187188
TaxPercent = x.TaxPercent,
188189
VariationOptions = OrderItemVm.GetVariationOption(x.Product)

src/Modules/SimplCommerce.Module.Orders/Services/OrderService.cs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ public async Task<Result<Order>> CreateOrder(User user, string paymentMethod, st
109109
}
110110

111111
var applyDiscountResult = await ApplyDiscountIfAny(user, cart);
112-
if (!applyDiscountResult.Success)
112+
if (!applyDiscountResult.Succeeded)
113113
{
114-
return Result.Fail<Order>(applyDiscountResult.Error);
114+
return Result.Fail<Order>(applyDiscountResult.ErrorMessage);
115115
}
116116

117117
var validateShippingMethodResult = await ValidateShippingMethod(shippingMethodName, shippingAddress, cart);
@@ -178,19 +178,25 @@ public async Task<Result<Order>> CreateOrder(User user, string paymentMethod, st
178178
orderItem.ProductPrice = orderItem.ProductPrice - orderItem.TaxAmount;
179179
}
180180

181+
var discountedItem = applyDiscountResult.DiscountedProducts.FirstOrDefault(x => x.Id == cartItem.ProductId);
182+
if(discountedItem != null)
183+
{
184+
orderItem.DiscountAmount = discountedItem.DiscountAmount;
185+
}
186+
181187
order.AddOrderItem(orderItem);
182188
cartItem.Product.StockQuantity = cartItem.Product.StockQuantity - cartItem.Quantity;
183189
}
184190

185191
order.OrderStatus = orderStatus;
186-
order.CouponCode = cart.CouponCode;
192+
order.CouponCode = applyDiscountResult.CouponCode;
187193
order.CouponRuleName = cart.CouponRuleName;
188-
order.DiscountAmount = applyDiscountResult.Value;
194+
order.DiscountAmount = applyDiscountResult.DiscountAmount;
189195
order.ShippingAmount = shippingMethod.Price;
190196
order.ShippingMethod = shippingMethod.Name;
191197
order.TaxAmount = order.OrderItems.Sum(x => x.TaxAmount);
192198
order.SubTotal = order.OrderItems.Sum(x => x.ProductPrice * x.Quantity);
193-
order.SubTotalWithDiscount = order.SubTotal - applyDiscountResult.Value;
199+
order.SubTotalWithDiscount = order.SubTotal - applyDiscountResult.DiscountAmount;
194200
order.OrderTotal = order.SubTotal + order.TaxAmount + order.ShippingAmount - order.DiscountAmount;
195201
_orderRepository.Add(order);
196202

@@ -282,12 +288,11 @@ public async Task<decimal> GetTax(long cartOwnerUserId, long countryId, long sta
282288
return taxAmount;
283289
}
284290

285-
private async Task<Result<decimal>> ApplyDiscountIfAny(User user, Cart cart)
291+
private async Task<CouponValidationResult> ApplyDiscountIfAny(User user, Cart cart)
286292
{
287-
decimal discount = 0;
288293
if (string.IsNullOrWhiteSpace(cart.CouponCode))
289294
{
290-
return Result.Ok(discount);
295+
return new CouponValidationResult { Succeeded = true, DiscountAmount = 0 };
291296
}
292297

293298
var cartInfoForCoupon = new CartInfoForCoupon
@@ -298,14 +303,16 @@ private async Task<Result<decimal>> ApplyDiscountIfAny(User user, Cart cart)
298303
var couponValidationResult = await _couponService.Validate(cart.CouponCode, cartInfoForCoupon);
299304
if (couponValidationResult.Succeeded)
300305
{
301-
discount = couponValidationResult.DiscountAmount;
302-
_couponService.AddCouponUsage(user.Id, couponValidationResult.CouponId);
303-
return Result.Ok(discount);
304-
}
305-
else
306-
{
307-
return Result.Fail<decimal>($"Unable to apply coupon {cart.CouponCode}. {couponValidationResult.ErrorMessage}");
306+
foreach (var item in couponValidationResult.DiscountedProducts)
307+
{
308+
for (var i = 0; i < item.Quantity; i++)
309+
{
310+
_couponService.AddCouponUsage(user.Id, couponValidationResult.CouponId);
311+
}
312+
}
308313
}
314+
315+
return couponValidationResult;
309316
}
310317

311318
private async Task<Result<ShippingPrice>> ValidateShippingMethod(string shippingMethodName, Address shippingAddress, Cart cart)

src/Modules/SimplCommerce.Module.Pricing/Services/CouponService.cs

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,46 +60,82 @@ public async Task<CouponValidationResult> Validate(string couponCode, CartInfoFo
6060

6161
var currentCustomer = await _workContext.GetCurrentUser();
6262
var couponUsageByCustomerCount = _couponUsageRepository.Query().Count(x => x.CouponId == coupon.Id && x.UserId == currentCustomer.Id);
63-
if (coupon.CartRule.UsageLimitPerCustomer.HasValue && couponUsageCount >= coupon.CartRule.UsageLimitPerCustomer)
63+
if (coupon.CartRule.UsageLimitPerCustomer.HasValue && couponUsageByCustomerCount >= coupon.CartRule.UsageLimitPerCustomer)
6464
{
6565
validationResult.ErrorMessage = $"You can use the coupon {couponCode} only {coupon.CartRule.UsageLimitPerCustomer} times";
6666
return validationResult;
6767
}
6868

69-
IList<DiscountedProduct> discountedProducts = new List<DiscountedProduct>();
70-
if(coupon.CartRule.Products.Any() || coupon.CartRule.Categories.Any())
69+
IList<DiscountableProduct> discountableProducts = new List<DiscountableProduct>();
70+
if(!coupon.CartRule.Products.Any() && !coupon.CartRule.Categories.Any())
7171
{
72-
var discounttableProducts = GetDiscountableProduct(coupon.CartRule.Products, coupon.CartRule.Categories);
73-
foreach(var item in cart.Items)
72+
var productIds = cart.Items.Select(x => x.ProductId);
73+
discountableProducts = _productRepository.Query()
74+
.Where(x => productIds.Contains(x.Id))
75+
.Select(x => new DiscountableProduct { Id = x.Id, Name = x.Name, Price = x.Price }).ToList();
76+
}
77+
else
78+
{
79+
discountableProducts = GetDiscountableProduct(coupon.CartRule.Products, coupon.CartRule.Categories);
80+
}
81+
82+
foreach (var item in cart.Items)
83+
{
84+
if ((coupon.CartRule.UsageLimitPerCoupon.HasValue && couponUsageCount >= coupon.CartRule.UsageLimitPerCoupon) ||
85+
(coupon.CartRule.UsageLimitPerCustomer.HasValue && couponUsageByCustomerCount >= coupon.CartRule.UsageLimitPerCustomer))
7486
{
75-
var discounttableProduct = discounttableProducts.FirstOrDefault(x => x.Id == item.ProductId);
87+
break;
88+
}
7689

77-
if (discounttableProduct != null)
90+
var discountableProduct = discountableProducts.FirstOrDefault(x => x.Id == item.ProductId);
91+
if (discountableProduct != null)
92+
{
93+
var discountedProduct = new DiscountedProduct { Id = discountableProduct.Id, Name = discountableProduct.Name, Price = discountableProduct.Price, Quantity = 1 };
94+
couponUsageCount = couponUsageCount + 1;
95+
couponUsageByCustomerCount = couponUsageByCustomerCount + 1;
96+
for (var i = 1; i < item.Quantity; i++)
7897
{
79-
discountedProducts.Add(new DiscountedProduct { Id = discounttableProduct.Id, Name = discounttableProduct.Name, Price = discounttableProduct.Price, Quantity = item.Quantity });
98+
if ((coupon.CartRule.UsageLimitPerCoupon.HasValue && couponUsageCount >= coupon.CartRule.UsageLimitPerCoupon) ||
99+
(coupon.CartRule.UsageLimitPerCustomer.HasValue && couponUsageByCustomerCount >= coupon.CartRule.UsageLimitPerCustomer))
100+
{
101+
break;
102+
}
103+
104+
discountedProduct.Quantity = discountedProduct.Quantity + 1;
105+
couponUsageCount = couponUsageCount + 1;
106+
couponUsageByCustomerCount = couponUsageByCustomerCount + 1;
80107
}
81-
}
82108

83-
if (!discountedProducts.Any())
84-
{
85-
validationResult.ErrorMessage = $"The coupon {couponCode} doesn't apply to any products in your cart";
86-
return validationResult;
109+
validationResult.DiscountedProducts.Add(discountedProduct);
87110
}
88111
}
89112

113+
if (!validationResult.DiscountedProducts.Any())
114+
{
115+
validationResult.ErrorMessage = $"The coupon {couponCode} doesn't apply to any products in your cart";
116+
return validationResult;
117+
}
118+
90119
switch (coupon.CartRule.RuleToApply)
91120
{
92121
case "cart_fixed":
93122
validationResult.Succeeded = true;
94123
validationResult.CouponId = coupon.Id;
124+
validationResult.CouponCode = coupon.Code;
95125
validationResult.CouponRuleName = coupon.CartRule.Name;
96126
validationResult.DiscountAmount = coupon.CartRule.DiscountAmount;
97127
return validationResult;
98128
case "by_percent":
99129
validationResult.Succeeded = true;
100130
validationResult.CouponId = coupon.Id;
131+
validationResult.CouponCode = coupon.Code;
101132
validationResult.CouponRuleName = coupon.CartRule.Name;
102-
validationResult.DiscountAmount = discountedProducts.Sum(x => (x.Price * coupon.CartRule.DiscountAmount / 100) * x.Quantity);
133+
foreach(var item in validationResult.DiscountedProducts)
134+
{
135+
item.DiscountAmount = (item.Price * coupon.CartRule.DiscountAmount / 100) * item.Quantity;
136+
}
137+
138+
validationResult.DiscountAmount = validationResult.DiscountedProducts.Sum(x => x.DiscountAmount);
103139
return validationResult;
104140
default:
105141
throw new InvalidOperationException($"{coupon.CartRule.RuleToApply} is not supported");

src/Modules/SimplCommerce.Module.Pricing/Services/CouponValidationResult.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ public class CouponValidationResult
88

99
public decimal DiscountAmount { get; set; }
1010

11+
public string CouponCode { get; set; }
12+
1113
public string CouponRuleName { get; set; }
1214

1315
public string ErrorMessage { get; set; }
1416

1517
public long CouponId { get; set; }
18+
19+
public IList<DiscountedProduct> DiscountedProducts { get; set; } = new List<DiscountedProduct>();
1620
}
1721
}

src/Modules/SimplCommerce.Module.Pricing/Services/DiscountedProduct.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ public class DiscountedProduct
99
public decimal Price { get; set; }
1010

1111
public int Quantity { get; set; }
12+
13+
public decimal DiscountAmount { get; set; }
1214
}
1315
}

src/Modules/SimplCommerce.Module.ShoppingCart/Services/CartService.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ public async Task<CartVm> GetCart(long userId)
108108
{
109109
cartVm.Discount = couponValidationResult.DiscountAmount;
110110
}
111+
else
112+
{
113+
cartVm.CouponValidationErrorMessage = couponValidationResult.ErrorMessage;
114+
}
111115
}
112116

113117
return cartVm;

src/Modules/SimplCommerce.Module.ShoppingCart/ViewModels/CartVm.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public class CartVm
1616

1717
public string DiscountString { get { return Discount.ToString("C"); } }
1818

19+
public string CouponValidationErrorMessage { get; set; }
20+
1921
public bool IsProductPriceIncludeTax { get; set; }
2022

2123
public decimal? TaxAmount { get; set; }

src/Modules/SimplCommerce.Module.ShoppingCart/Views/Cart/Index.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
<h4>@Localizer["Coupon code"]</h4>
5858
<form class="form-inline">
5959
<div class="form-group">
60-
<label>{{vm.couponErrorMessage}}</label>
60+
<label>{{vm.cart.couponValidationErrorMessage}}</label>
6161
</div>
6262
<div class="form-group">
6363
<input type="text" class="form-control" name="couponCode" ng-model="vm.couponCode" placeholder="Enter coupon">

src/Modules/SimplCommerce.Module.ShoppingCart/wwwroot/shoppingcart-list.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
vm.couponErrorMessage = '';
3939
shoppingCartService.applyCoupon(vm.couponCode).then(function (result) {
4040
if (result.data.succeeded == false) {
41-
vm.couponErrorMessage = result.data.errorMessage;
41+
vm.cart.couponValidationErrorMessage = result.data.errorMessage;
4242
} else {
4343
cartDataCallback(result);
4444
}

0 commit comments

Comments
 (0)