diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/IProductAppService.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/IProductAppService.cs index 077bf733..b88f4367 100644 --- a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/IProductAppService.cs +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/IProductAppService.cs @@ -23,5 +23,7 @@ namespace EasyAbp.EShop.Products.Products Task GetAsync(Guid id, Guid storeId); Task DeleteSkuAsync(Guid productId, Guid productSkuId, Guid storeId); + + Task GetPurchasableStatusAsync(Guid productId, Guid productSkuId, Guid storeId); } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/Products/ProductAppService.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/Products/ProductAppService.cs index aee89680..8c6b29ab 100644 --- a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/Products/ProductAppService.cs +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/Products/ProductAppService.cs @@ -24,17 +24,20 @@ namespace EasyAbp.EShop.Products.Products protected override string GetPolicyName { get; set; } = null; protected override string GetListPolicyName { get; set; } = null; + private readonly IProductPurchasableStatusProvider _productPurchasableStatusProvider; private readonly IAttributeOptionIdsSerializer _attributeOptionIdsSerializer; private readonly IProductStoreRepository _productStoreRepository; private readonly IProductCategoryRepository _productCategoryRepository; private readonly IProductRepository _repository; public ProductAppService( + IProductPurchasableStatusProvider productPurchasableStatusProvider, IAttributeOptionIdsSerializer attributeOptionIdsSerializer, IProductStoreRepository productStoreRepository, IProductCategoryRepository productCategoryRepository, IProductRepository repository) : base(repository) { + _productPurchasableStatusProvider = productPurchasableStatusProvider; _attributeOptionIdsSerializer = attributeOptionIdsSerializer; _productStoreRepository = productStoreRepository; _productCategoryRepository = productCategoryRepository; @@ -351,6 +354,15 @@ namespace EasyAbp.EShop.Products.Products return ObjectMapper.Map(product); } + public async Task GetPurchasableStatusAsync(Guid productId, Guid productSkuId, Guid storeId) + { + var product = await _repository.GetAsync(productId); + + var productSku = product.ProductSkus.Single(sku => sku.Id == productSkuId); + + return await _productPurchasableStatusProvider.GetPurchasableStatusAsync(product, productSku, storeId); + } + protected virtual async Task UpdateProductCategoriesAsync(Guid productId, IEnumerable categoryIds) { await _productCategoryRepository.DeleteAsync(x => x.ProductId.Equals(productId)); diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/GetProductPurchasableStatusResult.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/GetProductPurchasableStatusResult.cs new file mode 100644 index 00000000..4307890e --- /dev/null +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/GetProductPurchasableStatusResult.cs @@ -0,0 +1,9 @@ +namespace EasyAbp.EShop.Products.Products +{ + public class GetProductPurchasableStatusResult + { + public ProductPurchasableStatus PurchasableStatus { get; set; } + + public string Reason { get; set; } + } +} \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductPurchasableStatus.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductPurchasableStatus.cs new file mode 100644 index 00000000..d7b20303 --- /dev/null +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductPurchasableStatus.cs @@ -0,0 +1,8 @@ +namespace EasyAbp.EShop.Products.Products +{ + public enum ProductPurchasableStatus + { + CanBePurchased = 1, + CanNotBePurchased = 2 + } +} \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductPurchasableStatusProvider.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductPurchasableStatusProvider.cs new file mode 100644 index 00000000..80784e22 --- /dev/null +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductPurchasableStatusProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; + +namespace EasyAbp.EShop.Products.Products +{ + public interface IProductPurchasableStatusProvider + { + Task CheckPurchasableAsync(Product product, ProductSku productSku, Guid storeId); + + Task GetPurchasableStatusAsync(Product product, ProductSku productSku, + Guid storeId); + } +} \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductIsNotPurchasableException.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductIsNotPurchasableException.cs new file mode 100644 index 00000000..2a3ce54f --- /dev/null +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductIsNotPurchasableException.cs @@ -0,0 +1,13 @@ +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}") + { + } + } +} \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductPurchasableStatusProvider.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductPurchasableStatusProvider.cs new file mode 100644 index 00000000..cd57c392 --- /dev/null +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductPurchasableStatusProvider.cs @@ -0,0 +1,29 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace EasyAbp.EShop.Products.Products +{ + public class ProductPurchasableStatusProvider : IProductPurchasableStatusProvider, ITransientDependency + { + public async Task CheckPurchasableAsync(Product product, ProductSku productSku, Guid storeId) + { + var result = await GetPurchasableStatusAsync(product, productSku, storeId); + + if (result.PurchasableStatus != ProductPurchasableStatus.CanBePurchased) + { + throw new ProductIsNotPurchasableException(product.Id, result.Reason); + } + } + + public async Task GetPurchasableStatusAsync(Product product, ProductSku productSku, Guid storeId) + { + // Todo: Determine whether the product can be purchased. + return new GetProductPurchasableStatusResult + { + PurchasableStatus = ProductPurchasableStatus.CanBePurchased, + Reason = null + }; + } + } +} \ No newline at end of file