Commit 954f812e authored by gdlcf88's avatar gdlcf88

Limitations of ProductAttribute and ProductAttributeOption modifications, close #12

parent 41d11105
...@@ -24,18 +24,18 @@ namespace EasyAbp.EShop.Products.Products ...@@ -24,18 +24,18 @@ namespace EasyAbp.EShop.Products.Products
protected override string GetPolicyName { get; set; } = null; protected override string GetPolicyName { get; set; } = null;
protected override string GetListPolicyName { get; set; } = null; protected override string GetListPolicyName { get; set; } = null;
private readonly ISerializedAttributeOptionIdsFormatter _serializedAttributeOptionIdsFormatter; private readonly IAttributeOptionIdsSerializer _attributeOptionIdsSerializer;
private readonly IProductStoreRepository _productStoreRepository; private readonly IProductStoreRepository _productStoreRepository;
private readonly IProductCategoryRepository _productCategoryRepository; private readonly IProductCategoryRepository _productCategoryRepository;
private readonly IProductRepository _repository; private readonly IProductRepository _repository;
public ProductAppService( public ProductAppService(
ISerializedAttributeOptionIdsFormatter serializedAttributeOptionIdsFormatter, IAttributeOptionIdsSerializer attributeOptionIdsSerializer,
IProductStoreRepository productStoreRepository, IProductStoreRepository productStoreRepository,
IProductCategoryRepository productCategoryRepository, IProductCategoryRepository productCategoryRepository,
IProductRepository repository) : base(repository) IProductRepository repository) : base(repository)
{ {
_serializedAttributeOptionIdsFormatter = serializedAttributeOptionIdsFormatter; _attributeOptionIdsSerializer = attributeOptionIdsSerializer;
_productStoreRepository = productStoreRepository; _productStoreRepository = productStoreRepository;
_productCategoryRepository = productCategoryRepository; _productCategoryRepository = productCategoryRepository;
_repository = repository; _repository = repository;
...@@ -125,12 +125,29 @@ namespace EasyAbp.EShop.Products.Products ...@@ -125,12 +125,29 @@ namespace EasyAbp.EShop.Products.Products
protected virtual async Task UpdateProductAttributesAsync(Product product, CreateUpdateProductDto input) protected virtual async Task UpdateProductAttributesAsync(Product product, CreateUpdateProductDto input)
{ {
var isProductSkusEmpty = product.ProductSkus.IsNullOrEmpty();
var usedAttributeOptionIds = new HashSet<Guid>();
foreach (var serializedAttributeOptionIds in product.ProductSkus.Select(sku => sku.SerializedAttributeOptionIds))
{
foreach (var attributeOptionId in await _attributeOptionIdsSerializer.DeserializeAsync(serializedAttributeOptionIds))
{
usedAttributeOptionIds.Add(attributeOptionId);
}
}
foreach (var attributeDto in input.ProductAttributes) foreach (var attributeDto in input.ProductAttributes)
{ {
var attribute = product.ProductAttributes.FirstOrDefault(a => a.DisplayName == attributeDto.DisplayName); var attribute = product.ProductAttributes.FirstOrDefault(a => a.DisplayName == attributeDto.DisplayName);
if (attribute == null) if (attribute == null)
{ {
if (!isProductSkusEmpty)
{
throw new ProductAttributesModificationFailedException();
}
attribute = new ProductAttribute(GuidGenerator.Create(), attribute = new ProductAttribute(GuidGenerator.Create(),
attributeDto.DisplayName, attributeDto.Description); attributeDto.DisplayName, attributeDto.Description);
...@@ -150,16 +167,29 @@ namespace EasyAbp.EShop.Products.Products ...@@ -150,16 +167,29 @@ namespace EasyAbp.EShop.Products.Products
} }
} }
var exceptOptionNames = attribute.ProductAttributeOptions.Select(o => o.DisplayName) var removedOptionNames = attribute.ProductAttributeOptions.Select(o => o.DisplayName)
.Except(attributeDto.ProductAttributeOptions.Select(o => o.DisplayName)); .Except(attributeDto.ProductAttributeOptions.Select(o => o.DisplayName)).ToList();
if (!isProductSkusEmpty && removedOptionNames.Any() && usedAttributeOptionIds
.Intersect(attribute.ProductAttributeOptions
.Where(option => removedOptionNames.Contains(option.DisplayName))
.Select(option => option.Id)).Any())
{
throw new ProductAttributeOptionsDeletionFailedException();
}
attribute.ProductAttributeOptions.RemoveAll(o => exceptOptionNames.Contains(o.DisplayName)); attribute.ProductAttributeOptions.RemoveAll(o => removedOptionNames.Contains(o.DisplayName));
} }
var exceptAttributeNames = product.ProductAttributes.Select(a => a.DisplayName) var removedAttributeNames = product.ProductAttributes.Select(a => a.DisplayName)
.Except(input.ProductAttributes.Select(a => a.DisplayName)); .Except(input.ProductAttributes.Select(a => a.DisplayName)).ToList();
if (!isProductSkusEmpty && removedAttributeNames.Any())
{
throw new ProductAttributesModificationFailedException();
}
product.ProductAttributes.RemoveAll(a => exceptAttributeNames.Contains(a.DisplayName)); product.ProductAttributes.RemoveAll(a => removedAttributeNames.Contains(a.DisplayName));
} }
[Obsolete("Should use DeleteAsync(Guid id, Guid storeId)")] [Obsolete("Should use DeleteAsync(Guid id, Guid storeId)")]
...@@ -257,7 +287,7 @@ namespace EasyAbp.EShop.Products.Products ...@@ -257,7 +287,7 @@ namespace EasyAbp.EShop.Products.Products
CheckProductIsNotStatic(product); CheckProductIsNotStatic(product);
input.SerializedAttributeOptionIds = input.SerializedAttributeOptionIds =
await _serializedAttributeOptionIdsFormatter.ParseAsync(input.SerializedAttributeOptionIds); await _attributeOptionIdsSerializer.FormatAsync(input.SerializedAttributeOptionIds);
await CheckSkuAttributeOptionsAsync(product, input.SerializedAttributeOptionIds); await CheckSkuAttributeOptionsAsync(product, input.SerializedAttributeOptionIds);
......
using System;
using Volo.Abp;
namespace EasyAbp.EShop.Products.Products
{
public class ProductAttributeOptionsDeletionFailedException : BusinessException
{
public ProductAttributeOptionsDeletionFailedException() : base(
message: "Should ensure there are no SKUs using the attribute option which you want to delete.")
{
}
}
}
\ No newline at end of file
using System;
using Volo.Abp;
namespace EasyAbp.EShop.Products.Products
{
public class ProductAttributesModificationFailedException : BusinessException
{
public ProductAttributesModificationFailedException() : base(
message: "Should ensure SKUs are empty if you want to modify attributes of a product.")
{
}
}
}
\ No newline at end of file
...@@ -7,16 +7,21 @@ using Volo.Abp.DependencyInjection; ...@@ -7,16 +7,21 @@ using Volo.Abp.DependencyInjection;
namespace EasyAbp.EShop.Products.Products namespace EasyAbp.EShop.Products.Products
{ {
public class SerializedAttributeOptionIdsFormatter : ISerializedAttributeOptionIdsFormatter, ITransientDependency public class AttributeOptionIdsSerializer : IAttributeOptionIdsSerializer, ITransientDependency
{ {
public async Task<string> ParseAsync(string serializedAttributeOptionIds) public async Task<string> FormatAsync(string serializedAttributeOptionIds)
{ {
return await ParseAsync(JsonConvert.DeserializeObject<IEnumerable<Guid>>(serializedAttributeOptionIds)); return await SerializeAsync(await DeserializeAsync(serializedAttributeOptionIds));
} }
public Task<string> ParseAsync(IEnumerable<Guid> attributeOptionIds) public Task<string> SerializeAsync(IEnumerable<Guid> attributeOptionIds)
{ {
return Task.FromResult(JsonConvert.SerializeObject(attributeOptionIds.OrderBy(x => x))); return Task.FromResult(JsonConvert.SerializeObject(attributeOptionIds.OrderBy(x => x)));
} }
public Task<IEnumerable<Guid>> DeserializeAsync(string serializedAttributeOptionIds)
{
return Task.FromResult(JsonConvert.DeserializeObject<IEnumerable<Guid>>(serializedAttributeOptionIds));
}
} }
} }
\ No newline at end of file
...@@ -4,10 +4,12 @@ using System.Threading.Tasks; ...@@ -4,10 +4,12 @@ using System.Threading.Tasks;
namespace EasyAbp.EShop.Products.Products namespace EasyAbp.EShop.Products.Products
{ {
public interface ISerializedAttributeOptionIdsFormatter public interface IAttributeOptionIdsSerializer
{ {
Task<string> ParseAsync(string serializedAttributeOptionIds); Task<string> FormatAsync(string serializedAttributeOptionIds);
Task<string> ParseAsync(IEnumerable<Guid> attributeOptionIds); Task<string> SerializeAsync(IEnumerable<Guid> attributeOptionIds);
Task<IEnumerable<Guid>> DeserializeAsync(string serializedAttributeOptionIds);
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment