Skip to content

Commit

Permalink
Minor refactor - discounts services (#470)
Browse files Browse the repository at this point in the history
This PR encompasses the refactoring of the Discount Service, introducing significant enhancements to the discount calculation and retrieval processes. A notable change is the implementation of the GetDiscountAmountProvider through the use of the Mediator pattern, enabling the calculation of discounts via a plugin mechanism. Additionally, the Mediator pattern has been applied to facilitate the retrieval of a list of applied discounts, ensuring a more streamlined and efficient process. The Discount Service has been further modularized by separating it into IDiscountValidationService and IDiscountProviderLoader. This division not only clarifies the service's responsibilities but also enhances its maintainability and scalability by allowing for more focused implementations of its constituent parts.
  • Loading branch information
KrzysztofPajak authored Feb 24, 2024
1 parent ecaf59c commit 44c24dd
Show file tree
Hide file tree
Showing 32 changed files with 1,001 additions and 752 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Grand.Business.Core.Interfaces.Catalog.Discounts;
using Grand.Business.Core.Queries.Catalog;
using Grand.Domain.Catalog;
using Grand.Domain.Customers;
using Grand.Domain.Discounts;
using MediatR;

namespace Grand.Business.Catalog.Queries.Handlers;

public class GetDiscountAmountProviderHandler : IRequestHandler<GetDiscountAmountProvider, double>
{
private readonly IDiscountProviderLoader _discountProviderLoader;

public GetDiscountAmountProviderHandler(IDiscountProviderLoader discountProviderLoader)
{
_discountProviderLoader = discountProviderLoader;
}

public Task<double> Handle(GetDiscountAmountProvider request, CancellationToken cancellationToken)
{
return GetDiscountAmountProvider(request.Discount, request.Customer, request.Product, request.Amount);
}

/// <summary>
/// Get amount from discount amount provider
/// </summary>
/// <param name="discount"></param>
/// <param name="product"></param>
/// <param name="amount"></param>
/// <param name="customer"></param>
/// <returns></returns>
private async Task<double> GetDiscountAmountProvider(Discount discount, Customer customer, Product product, double amount)
{
var discountAmountProvider = _discountProviderLoader.LoadDiscountAmountProviderBySystemName(discount.DiscountPluginName);
if (discountAmountProvider == null)
return 0;
return await discountAmountProvider.DiscountAmount(discount, customer, product, amount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Grand.Business.Core.Queries.Catalog;
using Grand.Data;
using Grand.Domain;
using Grand.Domain.Discounts;
using MediatR;

namespace Grand.Business.Catalog.Queries.Handlers;

public class GetDiscountUsageHistoryQueryHandler : IRequestHandler<GetDiscountUsageHistoryQuery, IPagedList<DiscountUsageHistory>>
{
private readonly IRepository<DiscountUsageHistory> _discountUsageHistoryRepository;

public GetDiscountUsageHistoryQueryHandler(IRepository<DiscountUsageHistory> discountUsageHistoryRepository)
{
_discountUsageHistoryRepository = discountUsageHistoryRepository;
}

public async Task<IPagedList<DiscountUsageHistory>> Handle(GetDiscountUsageHistoryQuery request, CancellationToken cancellationToken)
{
var query = from d in _discountUsageHistoryRepository.Table
select d;

if (!string.IsNullOrEmpty(request.DiscountId))
query = query.Where(duh => duh.DiscountId == request.DiscountId);
if (!string.IsNullOrEmpty(request.CustomerId))
query = query.Where(duh => duh.CustomerId == request.CustomerId);
if (!string.IsNullOrEmpty(request.OrderId))
query = query.Where(duh => duh.OrderId == request.OrderId);
if (request.Canceled.HasValue)
query = query.Where(duh => duh.Canceled == request.Canceled.Value);
query = query.OrderByDescending(c => c.CreatedOnUtc);

return await PagedList<DiscountUsageHistory>.Create(query, request.PageIndex, request.PageSize);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using Grand.Business.Core.Interfaces.Catalog.Discounts;

namespace Grand.Business.Catalog.Services.Discounts;

public class DiscountProviderLoader : IDiscountProviderLoader
{
private readonly IEnumerable<IDiscountProvider> _discountProviders;
private readonly IEnumerable<IDiscountAmountProvider> _discountAmountProviders;

public DiscountProviderLoader(IEnumerable<IDiscountProvider> discountProviders, IEnumerable<IDiscountAmountProvider> discountAmountProviders)
{
_discountProviders = discountProviders;
_discountAmountProviders = discountAmountProviders;
}

/// <summary>
/// Load discount provider by rule system name
/// </summary>
/// <param name="ruleSystemName">Rule system name</param>
/// <returns>Found discount</returns>
public virtual IDiscountProvider LoadDiscountProviderByRuleSystemName(string ruleSystemName)
{
var discountPlugins = LoadAllDiscountProviders();
foreach (var discountPlugin in discountPlugins)
{
var rules = discountPlugin.GetRequirementRules();

if (!rules.Any(x => x.SystemName.Equals(ruleSystemName, StringComparison.OrdinalIgnoreCase)))
continue;
return discountPlugin;
}
return null;
}

/// <summary>
/// Load all discount providers
/// </summary>
/// <returns>Discount providers</returns>
public virtual IList<IDiscountProvider> LoadAllDiscountProviders()
{
return _discountProviders.ToList();
}

/// <summary>
/// Get all discount amount providers
/// </summary>
/// <returns></returns>
public virtual IList<IDiscountAmountProvider> LoadDiscountAmountProviders()
{
return _discountAmountProviders.ToList();
}

/// <summary>
/// Load discount amountProviderBySystemName
/// </summary>
/// <param name="systemName"></param>
/// <returns></returns>
public virtual IDiscountAmountProvider LoadDiscountAmountProviderBySystemName(string systemName)
{
return _discountAmountProviders.FirstOrDefault(x => x.SystemName.Equals(systemName, StringComparison.OrdinalIgnoreCase));
}


}
Loading

0 comments on commit 44c24dd

Please sign in to comment.