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