mirror of https://github.com/EasyAbp/EShop.git
16 changed files with 134 additions and 159 deletions
@ -0,0 +1,52 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class BasicPurchasableCheckProvider : IPurchasableCheckProvider, ITransientDependency |
|||
{ |
|||
public async Task CheckAsync(CreateOrderDto input, Dictionary<Guid, ProductDto> productDict) |
|||
{ |
|||
await CheckProductsPublishedAsync(input, productDict); |
|||
|
|||
await CheckInventoriesSufficientAsync(input, productDict); |
|||
} |
|||
|
|||
protected virtual Task CheckProductsPublishedAsync(CreateOrderDto input, |
|||
Dictionary<Guid, ProductDto> productDict) |
|||
{ |
|||
foreach (var productId in input.OrderLines.Select(dto => dto.ProductId).Distinct().ToArray()) |
|||
{ |
|||
if (!productDict[productId].IsPublished) |
|||
{ |
|||
throw new NotPurchasableException(productId, null, "Unpublished project"); |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
protected virtual Task CheckInventoriesSufficientAsync(CreateOrderDto input, |
|||
Dictionary<Guid, ProductDto> productDict) |
|||
{ |
|||
foreach (var orderLine in input.OrderLines) |
|||
{ |
|||
var inventory = productDict[orderLine.ProductId].ProductSkus |
|||
.Single(sku => sku.Id == orderLine.ProductSkuId).Inventory; |
|||
|
|||
if (inventory < orderLine.Quantity) |
|||
{ |
|||
throw new NotPurchasableException(orderLine.ProductId, orderLine.ProductSkuId, |
|||
"Insufficient inventory"); |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public interface IPurchasableCheckManager |
|||
{ |
|||
Task CheckAsync(CreateOrderDto input, Dictionary<Guid, ProductDto> productDict); |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public interface IPurchasableCheckProvider |
|||
{ |
|||
Task CheckAsync(CreateOrderDto input, Dictionary<Guid, ProductDto> productDict); |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class NotPurchasableException : BusinessException |
|||
{ |
|||
public NotPurchasableException(Guid productId, Guid? productSkuId, string reason) : base( |
|||
message: $"Product {productId} (SKU: {productSkuId}) cannot be purchased, the reason is: {reason}") |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using EasyAbp.EShop.Orders.Orders.Dtos; |
|||
using EasyAbp.EShop.Products.Products.Dtos; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Orders.Orders |
|||
{ |
|||
public class PurchasableCheckManager : IPurchasableCheckManager, ITransientDependency |
|||
{ |
|||
private readonly IServiceProvider _serviceProvider; |
|||
|
|||
public PurchasableCheckManager(IServiceProvider serviceProvider) |
|||
{ |
|||
_serviceProvider = serviceProvider; |
|||
} |
|||
|
|||
public async Task CheckAsync(CreateOrderDto input, Dictionary<Guid, ProductDto> productDict) |
|||
{ |
|||
var providers = _serviceProvider.GetServices<IPurchasableCheckProvider>(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
await provider.CheckAsync(input, productDict); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
namespace EasyAbp.EShop.Products.Products |
|||
{ |
|||
public class CheckProductPurchasableResult |
|||
{ |
|||
public bool IsPurchasable { get; set; } |
|||
|
|||
public string Reason { get; set; } |
|||
|
|||
public CheckProductPurchasableResult( |
|||
bool isPurchasable, |
|||
string reason = null) |
|||
{ |
|||
IsPurchasable = isPurchasable; |
|||
Reason = reason; |
|||
} |
|||
} |
|||
} |
|||
@ -1,51 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products |
|||
{ |
|||
public class BasicProductPurchasableCheckHandler : IProductPurchasableCheckHandler, ITransientDependency |
|||
{ |
|||
private readonly IProductInventoryProvider _productInventoryProvider; |
|||
|
|||
public BasicProductPurchasableCheckHandler( |
|||
IProductInventoryProvider productInventoryProvider) |
|||
{ |
|||
_productInventoryProvider = productInventoryProvider; |
|||
} |
|||
|
|||
public async Task<CheckProductPurchasableResult> CheckAsync(Product product, ProductSku productSku, Guid storeId, |
|||
Dictionary<string, object> extraProperties) |
|||
{ |
|||
if (!await IsProductPublishedAsync(product)) |
|||
{ |
|||
return new CheckProductPurchasableResult(false, "Unpublished project"); |
|||
} |
|||
|
|||
if (!await IsInventorySufficientAsync(product, productSku, storeId, extraProperties)) |
|||
{ |
|||
return new CheckProductPurchasableResult(false, "Insufficient inventory"); |
|||
} |
|||
|
|||
return new CheckProductPurchasableResult(true); |
|||
} |
|||
|
|||
protected virtual Task<bool> IsProductPublishedAsync(Product product) |
|||
{ |
|||
return Task.FromResult(product.IsPublished); |
|||
} |
|||
|
|||
protected virtual async Task<bool> IsInventorySufficientAsync(Product product, ProductSku productSku, Guid storeId, Dictionary<string, object> extraProperties) |
|||
{ |
|||
if (!extraProperties.TryGetValue("Quantity", out var quantity)) |
|||
{ |
|||
throw new ProductPurchasableCheckHandlerMissingPropertyException( |
|||
nameof(BasicProductPurchasableCheckHandler), "Quantity"); |
|||
} |
|||
|
|||
return await _productInventoryProvider.IsInventorySufficientAsync(product, productSku, storeId, |
|||
Convert.ToInt32(quantity)); |
|||
} |
|||
} |
|||
} |
|||
@ -1,12 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products |
|||
{ |
|||
public interface IProductPurchasableCheckHandler |
|||
{ |
|||
Task<CheckProductPurchasableResult> CheckAsync(Product product, ProductSku productSku, Guid storeId, |
|||
Dictionary<string, object> extraProperties); |
|||
} |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products |
|||
{ |
|||
public class ProductIsNotPurchasableException : BusinessException |
|||
{ |
|||
public ProductIsNotPurchasableException(Guid id, string reason) : base( |
|||
message: $"Product {id} cannot be purchased, the reason is: {reason}") |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
using System; |
|||
using Volo.Abp; |
|||
|
|||
namespace EasyAbp.EShop.Products.Products |
|||
{ |
|||
public class ProductPurchasableCheckHandlerMissingPropertyException : BusinessException |
|||
{ |
|||
public ProductPurchasableCheckHandlerMissingPropertyException(string handlerName, string propertyKey) : base( |
|||
message: $"The {handlerName} is missing extra property: {propertyKey}") |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue