Skip to content

Commit

Permalink
Fixing Coupon Issue (#1041)
Browse files Browse the repository at this point in the history
* Fixing Coupon Issue: 1.MaxDiscountAmount wasn't applied. 2.Coupon usage limit was per product now it's per order

* Adding Arabic to default supported language

* Enhance Searching Functionality. Search within localized properties. Also search in Product Description and Specification

* Fix Duplication of localized resources

* Search Ehnancements. Get brand from search and add as a filter.

---------

Co-authored-by: SWE CMS <swe-cms@outlook.com>
  • Loading branch information
N8hax and SWE CMS committed Sep 4, 2023
1 parent 8c5d01a commit 1c749af
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace SimplCommerce.Module.Catalog.Services
{
public class ProductService : IProductService
{
private const string ProductEntityTypeId = "Product";
private const string ProductEntityTypeId = nameof(Product);

private readonly IRepository<Product> _productRepository;
private readonly IEntityService _entityService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,18 @@ private void AutoRegisterNewString(string name, string culture)
using (var scope = _serviceProvider.CreateScope())
{
var resourceRepository = scope.ServiceProvider.GetRequiredService<IRepository<Resource>>();

//Avoid duplications
if (resourceRepository.Query().Any(x => x.CultureId == culture && x.Key.ToLower() == name.ToLower()))
{
return;
}
var res = new Resource()
{
CultureId = culture,
Key = name,
Value = name
};

resourceRepository.Add(res);
resourceRepository.SaveChanges();

Expand Down
31 changes: 9 additions & 22 deletions src/Modules/SimplCommerce.Module.Pricing/Services/CouponService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public async Task<CouponValidationResult> Validate(long customerId, string coupo
.FirstOrDefaultAsync(x => x.Code == couponCode);
var validationResult = new CouponValidationResult { Succeeded = false };

if(coupon == null || !coupon.CartRule.IsActive)
if (coupon == null || !coupon.CartRule.IsActive)
{
validationResult.ErrorMessage = $"The coupon {couponCode} is not exist.";
return validationResult;
Expand All @@ -50,7 +50,7 @@ public async Task<CouponValidationResult> Validate(long customerId, string coupo
}

var couponUsageCount = _cartRuleUsageRepository.Query().Count(x => x.CouponId == coupon.Id);
if(coupon.CartRule.UsageLimitPerCoupon.HasValue && couponUsageCount >= coupon.CartRule.UsageLimitPerCoupon)
if (coupon.CartRule.UsageLimitPerCoupon.HasValue && couponUsageCount >= coupon.CartRule.UsageLimitPerCoupon)
{
validationResult.ErrorMessage = $"The coupon {couponCode} is all used.";
return validationResult;
Expand All @@ -64,7 +64,7 @@ public async Task<CouponValidationResult> Validate(long customerId, string coupo
}

IList<DiscountableProduct> discountableProducts = new List<DiscountableProduct>();
if(!coupon.CartRule.Products.Any() && !coupon.CartRule.Categories.Any())
if (!coupon.CartRule.Products.Any() && !coupon.CartRule.Categories.Any())
{
var productIds = cart.Items.Select(x => x.ProductId);
discountableProducts = _productRepository.Query()
Expand All @@ -87,22 +87,7 @@ public async Task<CouponValidationResult> Validate(long customerId, string coupo
var discountableProduct = discountableProducts.FirstOrDefault(x => x.Id == item.ProductId);
if (discountableProduct != null)
{
var discountedProduct = new DiscountedProduct { Id = discountableProduct.Id, Name = discountableProduct.Name, Price = discountableProduct.Price, Quantity = 1 };
couponUsageCount = couponUsageCount + 1;
couponUsageByCustomerCount = couponUsageByCustomerCount + 1;
for (var i = 1; i < item.Quantity; i++)
{
if ((coupon.CartRule.UsageLimitPerCoupon.HasValue && couponUsageCount >= coupon.CartRule.UsageLimitPerCoupon) ||
(coupon.CartRule.UsageLimitPerCustomer.HasValue && couponUsageByCustomerCount >= coupon.CartRule.UsageLimitPerCustomer))
{
break;
}

discountedProduct.Quantity = discountedProduct.Quantity + 1;
couponUsageCount = couponUsageCount + 1;
couponUsageByCustomerCount = couponUsageByCustomerCount + 1;
}

var discountedProduct = new DiscountedProduct { Id = discountableProduct.Id, Name = discountableProduct.Name, Price = discountableProduct.Price, Quantity = item.Quantity };
validationResult.DiscountedProducts.Add(discountedProduct);
}
}
Expand All @@ -122,13 +107,15 @@ public async Task<CouponValidationResult> Validate(long customerId, string coupo
switch (coupon.CartRule.RuleToApply)
{
case "cart_fixed":
validationResult.DiscountAmount = coupon.CartRule.DiscountAmount;
validationResult.DiscountAmount = Math.Min(coupon.CartRule.DiscountAmount, coupon.CartRule.MaxDiscountAmount.GetValueOrDefault(decimal.MaxValue));
return validationResult;

case "by_percent":
foreach(var item in validationResult.DiscountedProducts)
var maxDiscountAmount = coupon.CartRule.MaxDiscountAmount.GetValueOrDefault(decimal.MaxValue);
foreach (var item in validationResult.DiscountedProducts)
{
item.DiscountAmount = (item.Price * coupon.CartRule.DiscountAmount / 100) * item.Quantity;
item.DiscountAmount = Math.Min((item.Price * coupon.CartRule.DiscountAmount / 100) * item.Quantity, maxDiscountAmount);
maxDiscountAmount -= item.DiscountAmount;
}

validationResult.DiscountAmount = validationResult.DiscountedProducts.Sum(x => x.DiscountAmount);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using SimplCommerce.Infrastructure.Data;
using SimplCommerce.Infrastructure.Localization;
using SimplCommerce.Module.Catalog.Areas.Catalog.ViewModels;
using SimplCommerce.Module.Catalog.Models;
using SimplCommerce.Module.Catalog.Services;
using SimplCommerce.Module.Core.Data;
using SimplCommerce.Module.Core.Services;
using SimplCommerce.Module.Search.Areas.Search.ViewModels;
using SimplCommerce.Module.Search.Models;
Expand All @@ -21,6 +23,7 @@ public class SearchController : Controller
private readonly IRepository<Product> _productRepository;
private readonly IRepository<Brand> _brandRepository;
private readonly IRepository<Category> _categoryRepository;
private readonly IRepository<LocalizedContentProperty> _localizedContentPropertyRepository;
private readonly IMediaService _mediaService;
private readonly IRepository<Query> _queryRepository;
private readonly IProductPricingService _productPricingService;
Expand All @@ -29,6 +32,7 @@ public class SearchController : Controller
public SearchController(IRepository<Product> productRepository,
IRepository<Brand> brandRepository,
IRepository<Category> categoryRepository,
IRepository<LocalizedContentProperty> localizedContentPropertyRepository,
IMediaService mediaService,
IRepository<Query> queryRepository,
IProductPricingService productPricingService,
Expand All @@ -38,6 +42,7 @@ public class SearchController : Controller
_productRepository = productRepository;
_brandRepository = brandRepository;
_categoryRepository = categoryRepository;
_localizedContentPropertyRepository = localizedContentPropertyRepository;
_mediaService = mediaService;
_queryRepository = queryRepository;
_productPricingService = productPricingService;
Expand All @@ -48,24 +53,47 @@ public class SearchController : Controller
[HttpGet("search")]
public IActionResult Index(SearchOption searchOption)
{
// Case no query
if (string.IsNullOrWhiteSpace(searchOption.Query))
{
return Redirect("~/");
}

// Case searching for specific brand
var brand = _brandRepository.Query().FirstOrDefault(x => x.Name == searchOption.Query && x.IsPublished);
if (brand != null)
{
return Redirect(string.Format("~/{0}", brand.Slug));
}

// Case brand included in the query
var includedBrand = _brandRepository.Query().FirstOrDefault(x => searchOption.Query.Contains(x.Name) && x.IsPublished);
if (includedBrand != null)
{
searchOption.Query = searchOption.Query.Replace(includedBrand.Name, "", StringComparison.OrdinalIgnoreCase);
}

searchOption.Query = searchOption.Query.Trim();

var model = new SearchResult
{
CurrentSearchOption = searchOption,
FilterOption = new FilterOption()
};

var query = _productRepository.Query().Where(x => x.Name.Contains(searchOption.Query) && x.IsPublished && x.IsVisibleIndividually);
var matchedLocalizedProductIds = _localizedContentPropertyRepository.Query().Where(x => x.EntityType == nameof(Product)
&& x.Value.ToLower().Contains(searchOption.Query.ToLower()))
.Select(x => x.EntityId)
.Distinct()
.ToList();

var query = _productRepository.Query().Where(x =>
x.IsPublished && x.IsVisibleIndividually &&
(matchedLocalizedProductIds.Contains(x.Id)
|| x.Name.ToLower().Contains(searchOption.Query.ToLower())
|| x.ShortDescription.ToLower().Contains(searchOption.Query.ToLower())
|| x.Description.ToLower().Contains(searchOption.Query.ToLower())
|| x.Specification.ToLower().Contains(searchOption.Query.ToLower())));

if (!query.Any())
{
Expand Down Expand Up @@ -98,7 +126,7 @@ public IActionResult Index(SearchOption searchOption)
var brands = searchOption.GetBrands().ToArray();
if (brands.Any())
{
query = query.Where(x => x.BrandId.HasValue && brands.Contains(x.Brand.Slug));
query = query.Where(x => (x.BrandId.HasValue && brands.Contains(x.Brand.Slug) || (includedBrand != null && x.BrandId == includedBrand.Id)));
}

model.TotalProduct = query.Count();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<ProjectReference Include="..\..\SimplCommerce.Infrastructure\SimplCommerce.Infrastructure.csproj" />
<ProjectReference Include="..\SimplCommerce.Module.Catalog\SimplCommerce.Module.Catalog.csproj" />
<ProjectReference Include="..\SimplCommerce.Module.Core\SimplCommerce.Module.Core.csproj" />
<ProjectReference Include="..\SimplCommerce.Module.Localization\SimplCommerce.Module.Localization.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2194,7 +2194,11 @@ protected override void Up(MigrationBuilder migrationBuilder)
migrationBuilder.InsertData(
table: "Localization_Culture",
columns: new[] { "Id", "Name" },
values: new object[] { "en-US", "English (US)" });
values: new object[,]
{
{"en-US", "English (US)"},
{"ar-Eg", "Arabic (Egypt)" }
});

migrationBuilder.InsertData(
table: "Payments_PaymentProvider",
Expand Down

0 comments on commit 1c749af

Please sign in to comment.