Skip to content

Commit 6235fd5

Browse files
Improvements/code (#591)
* Refactor ProductDeletedEventHandler dependencies * Refactor GetSearchProductsQueryHandler for readability * Remove explicit 500 status code and error message * Refactor discount handling in PricingService * Refactor GetSearchProductsQueryHandler for readability
1 parent 7466434 commit 6235fd5

File tree

13 files changed

+786
-666
lines changed

13 files changed

+786
-666
lines changed

src/Business/Grand.Business.Catalog/Events/Handlers/ProductDeletedEventHandler.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using Grand.Business.Core.Interfaces.Catalog.Products;
2-
using Grand.Data;
1+
using Grand.Data;
32
using Grand.Domain.Catalog;
43
using Grand.Domain.Customers;
54
using Grand.Domain.Seo;
@@ -18,7 +17,6 @@ public class ProductDeletedEventHandler : INotificationHandler<EntityDeleted<Pro
1817
private readonly IRepository<Product> _productRepository;
1918
private readonly IRepository<ProductReview> _productReviewRepository;
2019
private readonly IRepository<ProductTag> _productTagRepository;
21-
private readonly IProductTagService _productTagService;
2220

2321
public ProductDeletedEventHandler(
2422
IRepository<Product> productRepository,
@@ -27,8 +25,7 @@ public ProductDeletedEventHandler(
2725
IRepository<EntityUrl> entityUrlRepository,
2826
IRepository<ProductTag> productTagRepository,
2927
IRepository<ProductReview> productReviewRepository,
30-
IRepository<ProductDeleted> productDeletedRepository,
31-
IProductTagService productTagService)
28+
IRepository<ProductDeleted> productDeletedRepository)
3229
{
3330
_productRepository = productRepository;
3431
_customerGroupProductRepository = customerGroupProductRepository;
@@ -37,7 +34,6 @@ public ProductDeletedEventHandler(
3734
_productTagRepository = productTagRepository;
3835
_productReviewRepository = productReviewRepository;
3936
_productDeletedRepository = productDeletedRepository;
40-
_productTagService = productTagService;
4137
}
4238

4339
public async Task Handle(EntityDeleted<Product> notification, CancellationToken cancellationToken)
@@ -73,7 +69,9 @@ await _entityUrlRepository.DeleteManyAsync(x =>
7369
//delete product tags
7470
var existingProductTags = _productTagRepository.Table
7571
.Where(x => notification.Entity.ProductTags.ToList().Contains(x.Name)).ToList();
76-
foreach (var tag in existingProductTags) await _productTagService.DetachProductTag(tag, notification.Entity.Id);
72+
73+
foreach (var tag in existingProductTags)
74+
await _productTagRepository.UpdateField(tag.Id, x => x.Count, tag.Count - 1);
7775

7876
//insert to deleted products
7977
var productDeleted = JsonSerializer.Deserialize<ProductDeleted>(JsonSerializer.Serialize(notification.Entity));

src/Business/Grand.Business.Catalog/Queries/Handlers/GetSearchProductsQueryHandler.cs

Lines changed: 358 additions & 206 deletions
Large diffs are not rendered by default.
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
using Grand.Business.Core.Interfaces.Catalog.Brands;
2+
using Grand.Business.Core.Interfaces.Catalog.Categories;
3+
using Grand.Business.Core.Interfaces.Catalog.Collections;
4+
using Grand.Business.Core.Interfaces.Catalog.Discounts;
5+
using Grand.Business.Core.Interfaces.Customers;
6+
using Grand.Business.Core.Utilities.Catalog;
7+
using Grand.Domain.Catalog;
8+
using Grand.Domain.Customers;
9+
using Grand.Domain.Directory;
10+
using Grand.Domain.Discounts;
11+
using Grand.Domain.Stores;
12+
13+
namespace Grand.Business.Catalog.Services.Discounts;
14+
15+
public class DiscountHandlerService : IDiscountHandlerService
16+
{
17+
private readonly IDiscountService _discountService;
18+
private readonly ICategoryService _categoryService;
19+
private readonly IBrandService _brandService;
20+
private readonly ICollectionService _collectionService;
21+
private readonly IVendorService _vendorService;
22+
private readonly IDiscountValidationService _discountValidationService;
23+
private readonly CatalogSettings _catalogSettings;
24+
25+
public DiscountHandlerService(
26+
IDiscountService discountService,
27+
ICategoryService categoryService,
28+
IBrandService brandService,
29+
ICollectionService collectionService,
30+
IVendorService vendorService,
31+
IDiscountValidationService discountValidationService,
32+
CatalogSettings catalogSettings)
33+
{
34+
_discountService = discountService;
35+
_categoryService = categoryService;
36+
_brandService = brandService;
37+
_collectionService = collectionService;
38+
_vendorService = vendorService;
39+
_discountValidationService = discountValidationService;
40+
_catalogSettings = catalogSettings;
41+
}
42+
43+
/// <summary>
44+
/// Gets allowed discounts
45+
/// </summary>
46+
/// <param name="product">Product</param>
47+
/// <param name="customer">Customer</param>
48+
/// <param name="store">Store</param>
49+
/// <param name="currency">Currency</param>
50+
/// <returns>Discounts</returns>
51+
private async Task AddAllowedDiscounts(IList<ApplyDiscount> allowedDiscounts, IEnumerable<string> appliedDiscounts, Customer customer, Store store, Currency currency, DiscountType discountType)
52+
{
53+
foreach (var appliedDiscount in appliedDiscounts)
54+
{
55+
var discount = await _discountService.GetDiscountById(appliedDiscount);
56+
if (discount == null) continue;
57+
var validDiscount = await _discountValidationService.ValidateDiscount(discount, customer, store, currency);
58+
if (validDiscount.IsValid && discount.DiscountTypeId == discountType)
59+
allowedDiscounts.Add(new ApplyDiscount {
60+
CouponCode = validDiscount.CouponCode,
61+
DiscountId = discount.Id,
62+
IsCumulative = discount.IsCumulative,
63+
MaximumDiscountedQuantity = discount.MaximumDiscountedQuantity
64+
});
65+
}
66+
}
67+
68+
public virtual async Task<IList<ApplyDiscount>> GetAllowedDiscounts(Product product, Customer customer, Store store, Currency currency)
69+
{
70+
var allowedDiscounts = new List<ApplyDiscount>();
71+
if (_catalogSettings.IgnoreDiscounts)
72+
return allowedDiscounts;
73+
74+
//discounts applied to products
75+
await AddAllowedDiscounts(allowedDiscounts, product.AppliedDiscounts, customer, store, currency, DiscountType.AssignedToSkus);
76+
77+
//discounts applied to all products
78+
var allProductDiscounts = await _discountService.GetActiveDiscountsByContext(DiscountType.AssignedToAllProducts, store.Id, currency.CurrencyCode);
79+
await AddAllowedDiscounts(allowedDiscounts, allProductDiscounts.Select(d => d.Id), customer, store, currency, DiscountType.AssignedToAllProducts);
80+
81+
//discounts applied to categories
82+
foreach (var productCategory in product.ProductCategories)
83+
{
84+
var category = await _categoryService.GetCategoryById(productCategory.CategoryId);
85+
if (category == null) continue;
86+
await AddAllowedDiscounts(allowedDiscounts, category.AppliedDiscounts, customer, store, currency, DiscountType.AssignedToCategories);
87+
}
88+
89+
//discounts applied to brands
90+
if (!string.IsNullOrEmpty(product.BrandId))
91+
{
92+
var brand = await _brandService.GetBrandById(product.BrandId);
93+
if (brand != null)
94+
await AddAllowedDiscounts(allowedDiscounts, brand.AppliedDiscounts, customer, store, currency, DiscountType.AssignedToBrands);
95+
}
96+
97+
//discounts applied to collections
98+
foreach (var productCollection in product.ProductCollections)
99+
{
100+
var collection = await _collectionService.GetCollectionById(productCollection.CollectionId);
101+
if (collection == null) continue;
102+
await AddAllowedDiscounts(allowedDiscounts, collection.AppliedDiscounts, customer, store, currency, DiscountType.AssignedToCollections);
103+
}
104+
105+
//discounts applied to vendors
106+
if (!string.IsNullOrEmpty(product.VendorId))
107+
{
108+
var vendor = await _vendorService.GetVendorById(product.VendorId);
109+
if (vendor != null)
110+
await AddAllowedDiscounts(allowedDiscounts, vendor.AppliedDiscounts, customer, store, currency, DiscountType.AssignedToVendors);
111+
}
112+
113+
return FilterDiscountsByMaxQuantity(allowedDiscounts);
114+
}
115+
116+
private static IList<ApplyDiscount> FilterDiscountsByMaxQuantity(IList<ApplyDiscount> discounts)
117+
{
118+
if (!discounts.Any())
119+
return discounts;
120+
121+
// Identify discounts that are cumulative and have a MaximumDiscountedQuantity > 0
122+
var cumulativeDiscounts = discounts
123+
.Where(d => d.IsCumulative && (d.MaximumDiscountedQuantity ?? 0) > 0)
124+
.ToList();
125+
126+
if (!cumulativeDiscounts.Any())
127+
return discounts;
128+
129+
// Determine the maximum MaximumDiscountedQuantity among cumulative discounts
130+
var maxQuantity = cumulativeDiscounts.Max(d => d.MaximumDiscountedQuantity ?? 0);
131+
132+
// Select cumulative discounts with the maximum MaximumDiscountedQuantity
133+
var maxCumulativeDiscounts = cumulativeDiscounts
134+
.Where(d => d.MaximumDiscountedQuantity == maxQuantity)
135+
.ToList();
136+
137+
// Select discounts that are not cumulative or have MaximumDiscountedQuantity <= 0
138+
var otherDiscounts = discounts
139+
.Where(d => !(d.IsCumulative && (d.MaximumDiscountedQuantity ?? 0) > 0))
140+
.ToList();
141+
142+
// Combine the filtered cumulative discounts with the other discounts
143+
return maxCumulativeDiscounts.Concat(otherDiscounts).ToList();
144+
}
145+
146+
public async Task<(List<ApplyDiscount> appliedDiscount, double discountAmount)> GetDiscountAmount(Product product, Customer customer, Store store, Currency currency, double productPriceWithoutDiscount)
147+
{
148+
var allowedDiscounts = await GetAllowedDiscounts(product, customer, store, currency);
149+
150+
//no discounts
151+
if (!allowedDiscounts.Any())
152+
return ([], 0);
153+
154+
var preferredDiscount = await _discountService.GetPreferredDiscount(allowedDiscounts, customer, currency,
155+
product, productPriceWithoutDiscount);
156+
157+
return (preferredDiscount.appliedDiscount, preferredDiscount.discountAmount);
158+
}
159+
}

0 commit comments

Comments
 (0)