Commit f56695c2 authored by gdlcf88's avatar gdlcf88

Change ProductDetail to an aggregate root and make it also related to ProductSku, close #1

parent 581cf178
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace EasyAbp.EShop.Products.Products.Dtos
namespace EasyAbp.EShop.Products.ProductDetails.Dtos
{
public class CreateUpdateProductDetailDto
{
/// <summary>
/// This property is for product management permission checking
/// </summary>
[DisplayName("ProductDetailStoreId")]
public Guid StoreId { get; set; }
[DisplayName("ProductDetailDescription")]
public string Description { get; set; }
}
......
using System;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Products.ProductDetails.Dtos
{
public class ProductDetailDto : EntityDto<Guid>
{
public string Description { get; set; }
}
}
\ No newline at end of file
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Products.ProductDetails
{
public interface IProductDetailAppService :
ICrudAppService<
ProductDetailDto,
Guid,
PagedAndSortedResultRequestDto,
CreateUpdateProductDetailDto,
CreateUpdateProductDetailDto>
{
Task DeleteAsync(Guid id, Guid storeId);
}
}
\ No newline at end of file
......@@ -8,10 +8,12 @@ namespace EasyAbp.EShop.Products.Products.Dtos
{
public class CreateUpdateProductDto : IValidatableObject
{
[Required]
[DisplayName("ProductProductTypeId")]
public Guid ProductTypeId { get; set; }
[DisplayName("ProductDetailId")]
public Guid ProductDetailId { get; set; }
/// <summary>
/// This property is set for adding the store to ProductStore in creation, or for permission checking in update.
/// </summary>
......@@ -25,8 +27,6 @@ namespace EasyAbp.EShop.Products.Products.Dtos
[DisplayName("ProductDisplayName")]
public string DisplayName { get; set; }
public CreateUpdateProductDetailDto ProductDetail { get; set; }
public ICollection<CreateUpdateProductAttributeDto> ProductAttributes { get; set; }
[DisplayName("ProductInventoryStrategy")]
......
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Products.Products.Dtos
{
public class ProductDetailDto : EntityDto
{
public string Description { get; set; }
}
}
\ No newline at end of file
......@@ -8,6 +8,8 @@ namespace EasyAbp.EShop.Products.Products.Dtos
{
public Guid ProductTypeId { get; set; }
public Guid ProductDetailId { get; set; }
public ICollection<Guid> CategoryIds { get; set; }
public string DisplayName { get; set; }
......@@ -20,8 +22,6 @@ namespace EasyAbp.EShop.Products.Products.Dtos
public bool IsPublished { get; set; }
public ProductDetailDto ProductDetail { get; set; }
public ICollection<ProductAttributeDto> ProductAttributes { get; set; }
public ICollection<ProductSkuDto> ProductSkus { get; set; }
......
......@@ -16,5 +16,7 @@ namespace EasyAbp.EShop.Products.Products.Dtos
public int Sold { get; set; }
public int OrderMinQuantity { get; set; }
public Guid? ProductDetailId { get; set; }
}
}
\ No newline at end of file
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Authorization;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.ProductStores;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Products.ProductDetails
{
public class ProductDetailAppService : CrudAppService<ProductDetail, ProductDetailDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateProductDetailDto, CreateUpdateProductDetailDto>,
IProductDetailAppService
{
protected override string CreatePolicyName { get; set; } = ProductsPermissions.Products.Create;
protected override string DeletePolicyName { get; set; } = ProductsPermissions.Products.Delete;
protected override string UpdatePolicyName { get; set; } = ProductsPermissions.Products.Update;
protected override string GetPolicyName { get; set; } = ProductsPermissions.Products.Default;
protected override string GetListPolicyName { get; set; } = ProductsPermissions.Products.Default;
private readonly IProductRepository _productRepository;
private readonly IProductStoreRepository _productStoreRepository;
private readonly IProductDetailRepository _repository;
public ProductDetailAppService(
IProductRepository productRepository,
IProductStoreRepository productStoreRepository,
IProductDetailRepository repository) : base(repository)
{
_productRepository = productRepository;
_productStoreRepository = productStoreRepository;
_repository = repository;
}
public override async Task<ProductDetailDto> UpdateAsync(Guid id, CreateUpdateProductDetailDto input)
{
await CheckUpdatePolicyAsync();
var product = await _productRepository.GetAsync(x => x.ProductDetailId == id);
await CheckStoreIsProductOwnerAsync(product.Id, input.StoreId);
var detail = await GetEntityByIdAsync(id);
MapToEntity(input, detail);
await Repository.UpdateAsync(detail, autoSave: true);
return MapToGetOutputDto(detail);
}
public virtual async Task DeleteAsync(Guid id, Guid storeId)
{
await CheckDeletePolicyAsync();
var product = await _productRepository.GetAsync(x => x.ProductDetailId == id);
await CheckStoreIsProductOwnerAsync(product.Id, storeId);
await Repository.DeleteAsync(id);
}
[RemoteService(false)]
public override Task DeleteAsync(Guid id)
{
throw new NotImplementedException();
}
[RemoteService(false)]
public override Task<PagedResultDto<ProductDetailDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
throw new NotImplementedException();
}
protected virtual async Task CheckStoreIsProductOwnerAsync(Guid productId, Guid storeId)
{
var productStore = await _productStoreRepository.GetAsync(productId, storeId);
if (!productStore.IsOwner)
{
throw new StoreIsNotProductOwnerException(productId, storeId);
}
}
}
}
\ No newline at end of file
......@@ -4,10 +4,12 @@ using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Authorization;
using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Products.ProductStores;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
namespace EasyAbp.EShop.Products.Products
{
......@@ -53,6 +55,8 @@ namespace EasyAbp.EShop.Products.Products
await Repository.InsertAsync(product, autoSave: true);
await CheckProductDetailIdAsync(product.Id, input.ProductDetailId);
await AddProductToStoreAsync(product.Id, input.StoreId);
await UpdateProductCategoriesAsync(product.Id, input.CategoryIds);
......@@ -60,6 +64,19 @@ namespace EasyAbp.EShop.Products.Products
return MapToGetOutputDto(product);
}
private async Task CheckProductDetailIdAsync(Guid currentProductId, Guid desiredProductDetailId)
{
var otherOwner = await _repository.FindAsync(x =>
x.ProductDetailId == desiredProductDetailId && x.Id != currentProductId);
// Todo: should also check ProductSku owner
if (otherOwner != null)
{
throw new EntityNotFoundException(typeof(ProductDetail), desiredProductDetailId);
}
}
protected virtual async Task AddProductToStoreAsync(Guid productId, Guid storeId)
{
await _productStoreRepository.InsertAsync(new ProductStore(GuidGenerator.Create(), CurrentTenant.Id,
......@@ -80,18 +97,20 @@ namespace EasyAbp.EShop.Products.Products
await Repository.UpdateAsync(product, autoSave: true);
await CheckProductDetailIdAsync(product.Id, input.ProductDetailId);
await UpdateProductCategoriesAsync(product.Id, input.CategoryIds);
return MapToGetOutputDto(product);
}
protected virtual async Task CheckStoreIsProductOwnerAsync(Guid id, Guid storeId)
protected virtual async Task CheckStoreIsProductOwnerAsync(Guid productId, Guid storeId)
{
var productStore = await _productStoreRepository.GetAsync(id, storeId);
var productStore = await _productStoreRepository.GetAsync(productId, storeId);
if (!productStore.IsOwner)
{
throw new StoreIsNotProductOwnerException(id, storeId);
throw new StoreIsNotProductOwnerException(productId, storeId);
}
}
......@@ -134,7 +153,7 @@ namespace EasyAbp.EShop.Products.Products
product.ProductAttributes.RemoveAll(a => exceptAttributeNames.Contains(a.DisplayName));
}
[RemoteService(IsMetadataEnabled = false)]
[RemoteService(false)]
public override async Task DeleteAsync(Guid id)
{
throw new NotImplementedException();
......
......@@ -7,6 +7,8 @@ using EasyAbp.EShop.Products.ProductTypes.Dtos;
using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.ProductCategories.Dtos;
using AutoMapper;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using Volo.Abp.AutoMapper;
namespace EasyAbp.EShop.Products
......@@ -29,7 +31,8 @@ namespace EasyAbp.EShop.Products
.ForSourceMember(dto => dto.CategoryIds, opt => opt.DoNotValidate())
.Ignore(p => p.ProductAttributes)
.Ignore(p => p.ProductSkus);
CreateMap<CreateUpdateProductDetailDto, ProductDetail>(MemberList.Source);
CreateMap<CreateUpdateProductDetailDto, ProductDetail>(MemberList.Source)
.ForSourceMember(dto => dto.StoreId, opt => opt.DoNotValidate());
CreateMap<CreateUpdateProductAttributeDto, ProductAttribute>(MemberList.Source);
CreateMap<CreateUpdateProductAttributeOptionDto, ProductAttributeOption>(MemberList.Source);
CreateMap<Category, CategoryDto>();
......
......@@ -5,8 +5,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
......@@ -6,8 +6,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
......@@ -5,8 +5,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
......@@ -5,8 +5,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
......@@ -6,8 +6,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
......@@ -6,8 +6,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
......@@ -5,8 +5,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
......@@ -6,8 +6,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
......@@ -6,8 +6,11 @@
"Product": "Product",
"ProductStore": "ProductStore",
"ProductProductTypeId": "ProductProductTypeId",
"ProductDetailId": "ProductDetailId",
"ProductProductStoreId": "ProductProductStoreId",
"ProductDisplayName": "ProductDisplayName",
"ProductDetailProductId": "ProductDetailProductId",
"ProductDetailProductSkuId": "ProductDetailProductSkuId",
"ProductDetailDescription": "ProductDetailDescription",
"ProductDetailDisplayOrder": "ProductDetailDisplayOrder",
"ProductAttributeNames": "ProductAttributeNames",
......
using System;
using System.Linq;
using EasyAbp.EShop.Products.Products;
using Volo.Abp.Domain.Repositories;
namespace EasyAbp.EShop.Products.ProductDetails
{
public interface IProductDetailRepository : IRepository<ProductDetail, Guid>
{
}
}
\ No newline at end of file
using System;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
namespace EasyAbp.EShop.Products.Products
namespace EasyAbp.EShop.Products.ProductDetails
{
public class ProductDetail : Entity
public class ProductDetail : FullAuditedAggregateRoot<Guid>
{
public virtual Guid ProductId { get; protected set; }
[CanBeNull]
public virtual string Description { get; protected set; }
protected ProductDetail() {}
public ProductDetail(
Guid productId,
[CanBeNull] string description)
Guid id,
[CanBeNull] string description) : base(id)
{
ProductId = productId;
Description = description;
}
public override object[] GetKeys()
public void SetDescription(string description)
{
return new object[] {ProductId};
Description = description;
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using EasyAbp.EShop.Products.ProductDetails;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities.Auditing;
......@@ -9,6 +10,8 @@ namespace EasyAbp.EShop.Products.Products
{
public virtual Guid ProductTypeId { get; protected set; }
public virtual Guid ProductDetailId { get; protected set; }
[NotNull]
public virtual string DisplayName { get; protected set; }
......@@ -21,8 +24,6 @@ namespace EasyAbp.EShop.Products.Products
public virtual bool IsPublished { get; protected set; }
public virtual ProductDetail ProductDetail { get; protected set; }
public virtual ICollection<ProductAttribute> ProductAttributes { get; protected set; }
public virtual ICollection<ProductSku> ProductSkus { get; protected set; }
......@@ -36,6 +37,7 @@ namespace EasyAbp.EShop.Products.Products
public Product(
Guid id,
Guid productTypeId,
Guid productDetailId,
string displayName,
InventoryStrategy inventoryStrategy,
bool isPublished,
......@@ -44,6 +46,7 @@ namespace EasyAbp.EShop.Products.Products
) :base(id)
{
ProductTypeId = productTypeId;
ProductDetailId = productDetailId;
DisplayName = displayName;
InventoryStrategy = inventoryStrategy;
IsPublished = isPublished;
......
......@@ -22,6 +22,8 @@ namespace EasyAbp.EShop.Products.Products
public virtual int OrderMinQuantity { get; protected set; }
public Guid? ProductDetailId { get; set; }
protected ProductSku() {}
public ProductSku(
......@@ -32,7 +34,8 @@ namespace EasyAbp.EShop.Products.Products
decimal price,
int inventory,
int sold,
int orderMinQuantity) : base(id)
int orderMinQuantity,
Guid? productDetailId) : base(id)
{
SerializedAttributeOptionIds = serializedAttributeOptionIds;
Currency = currency;
......@@ -41,6 +44,7 @@ namespace EasyAbp.EShop.Products.Products
Inventory = inventory;
Sold = sold;
OrderMinQuantity = orderMinQuantity;
ProductDetailId = productDetailId;
}
}
}
\ No newline at end of file
......@@ -12,8 +12,4 @@
<ProjectReference Include="..\EasyAbp.EShop.Products.Domain\EasyAbp.EShop.Products.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="EasyAbp\EShop\Products" />
</ItemGroup>
</Project>
......@@ -2,6 +2,7 @@ using EasyAbp.EShop.Products.ProductStores;
using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.ProductTypes;
using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.Products;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
......@@ -22,8 +23,9 @@ namespace EasyAbp.EShop.Products.EntityFrameworkCore
/* Add custom repositories here. Example:
* options.AddRepository<Question, EfCoreQuestionRepository>();
*/
options.AddRepository<Product, ProductRepository>();
options.AddRepository<Category, CategoryRepository>();
options.AddRepository<Product, ProductRepository>();
options.AddRepository<ProductDetail, ProductDetailRepository>();
options.AddRepository<ProductType, ProductTypeRepository>();
options.AddRepository<ProductCategory, ProductCategoryRepository>();
options.AddRepository<ProductStore, ProductStoreRepository>();
......
......@@ -5,6 +5,7 @@ using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.ProductTypes;
using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductStores;
namespace EasyAbp.EShop.Products.EntityFrameworkCore
......
......@@ -5,6 +5,7 @@ using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.ProductTypes;
using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductStores;
namespace EasyAbp.EShop.Products.EntityFrameworkCore
......
......@@ -4,6 +4,7 @@ using EasyAbp.EShop.Products.ProductTypes;
using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.Products;
using System;
using EasyAbp.EShop.Products.ProductDetails;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;
......@@ -57,7 +58,6 @@ namespace EasyAbp.EShop.Products.EntityFrameworkCore
b.ToTable(options.TablePrefix + "ProductDetails", options.Schema);
b.ConfigureByConvention();
/* Configure more properties here */
b.HasKey(x => new { x.ProductId });
});
builder.Entity<ProductAttribute>(b =>
......
using System;
using EasyAbp.EShop.Products.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace EasyAbp.EShop.Products.ProductDetails
{
public class ProductDetailRepository : EfCoreRepository<ProductsDbContext, ProductDetail, Guid>, IProductDetailRepository
{
public ProductDetailRepository(IDbContextProvider<ProductsDbContext> dbContextProvider) : base(dbContextProvider)
{
}
}
}
\ No newline at end of file
......@@ -16,7 +16,6 @@ namespace EasyAbp.EShop.Products.Products
public override IQueryable<Product> WithDetails()
{
return base.WithDetails()
.Include(x => x.ProductDetail)
.Include(x => x.ProductAttributes).ThenInclude(x => x.ProductAttributeOptions)
.Include(x => x.ProductSkus);
}
......
......@@ -4,6 +4,8 @@ using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.Categories.Dtos;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Products.ProductTypes;
......@@ -16,6 +18,9 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
{
public class CreateModalModel : ProductsPageModel
{
[BindProperty(SupportsGet = true)]
public Guid StoreId { get; set; }
[BindProperty]
public CreateEditProductViewModel Product { get; set; }
......@@ -25,19 +30,22 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
private readonly IProductTypeAppService _productTypeAppService;
private readonly ICategoryAppService _categoryAppService;
private readonly IProductDetailAppService _productDetailAppService;
private readonly IProductAppService _service;
public CreateModalModel(
IProductTypeAppService productTypeAppService,
ICategoryAppService categoryAppService,
IProductDetailAppService productDetailAppService,
IProductAppService service)
{
_productTypeAppService = productTypeAppService;
_categoryAppService = categoryAppService;
_productDetailAppService = productDetailAppService;
_service = service;
}
public virtual async Task OnGetAsync(Guid storeId, Guid? categoryId)
public virtual async Task OnGetAsync(Guid? categoryId)
{
ProductTypes =
(await _productTypeAppService.GetListAsync(new PagedAndSortedResultRequestDto
......@@ -51,7 +59,11 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
Product = new CreateEditProductViewModel
{
StoreId = storeId
StoreId = StoreId,
ProductDetail = new CreateEditProductDetailViewModel
{
StoreId = StoreId
}
};
if (categoryId.HasValue)
......@@ -62,7 +74,16 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
public virtual async Task<IActionResult> OnPostAsync()
{
await _service.CreateAsync(ObjectMapper.Map<CreateEditProductViewModel, CreateUpdateProductDto>(Product));
var detail = await _productDetailAppService.CreateAsync(
ObjectMapper
.Map<CreateEditProductDetailViewModel, CreateUpdateProductDetailDto>(Product.ProductDetail));
var createDto = ObjectMapper.Map<CreateEditProductViewModel, CreateUpdateProductDto>(Product);
createDto.ProductDetailId = detail.Id;
var product = await _service.CreateAsync(createDto);
return NoContent();
}
}
......
......@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using Microsoft.AspNetCore.Mvc;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
......@@ -28,15 +30,18 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
private readonly IProductTypeAppService _productTypeAppService;
private readonly ICategoryAppService _categoryAppService;
private readonly IProductDetailAppService _productDetailAppService;
private readonly IProductAppService _service;
public EditModalModel(
IProductTypeAppService productTypeAppService,
ICategoryAppService categoryAppService,
IProductDetailAppService productDetailAppService,
IProductAppService service)
{
_productTypeAppService = productTypeAppService;
_categoryAppService = categoryAppService;
_productDetailAppService = productDetailAppService;
_service = service;
}
......@@ -54,15 +59,34 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
var productDto = await _service.GetAsync(Id);
var detailDto = await _productDetailAppService.GetAsync(productDto.ProductDetailId);
Product = ObjectMapper.Map<ProductDto, CreateEditProductViewModel>(productDto);
Product.ProductDetail = new CreateEditProductDetailViewModel
{
StoreId = storeId,
Description = detailDto.Description
};
Product.StoreId = storeId;
}
public virtual async Task<IActionResult> OnPostAsync()
{
await _service.UpdateAsync(Id,
ObjectMapper.Map<CreateEditProductViewModel, CreateUpdateProductDto>(Product));
var product = await _service.GetAsync(Id);
var detail = await _productDetailAppService.GetAsync(product.ProductDetailId);
await _productDetailAppService.UpdateAsync(detail.Id,
ObjectMapper
.Map<CreateEditProductDetailViewModel, CreateUpdateProductDetailDto>(Product.ProductDetail));
var updateProductDto = ObjectMapper.Map<CreateEditProductViewModel, CreateUpdateProductDto>(Product);
updateProductDto.ProductDetailId = detail.Id;
await _service.UpdateAsync(Id, updateProductDto);
return NoContent();
}
}
......
......@@ -2,7 +2,7 @@
namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels
{
public class CreateUpdateProductAttributeOptionViewModel
public class CreateEditProductAttributeOptionViewModel
{
[Required]
[Display(Name = "ProductAttributeOptionDisplayName")]
......
......@@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels
{
public class CreateUpdateProductAttributeViewModel
public class CreateEditProductAttributeViewModel
{
[Required]
[Display(Name = "ProductAttributeDisplayName")]
......@@ -15,6 +15,6 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewM
[Display(Name = "ProductAttributeDisplayOrder")]
public int DisplayOrder { get; set; } = 0;
public List<CreateUpdateProductAttributeOptionViewModel> ProductAttributeOptions { get; set; }
public List<CreateEditProductAttributeOptionViewModel> ProductAttributeOptions { get; set; }
}
}
\ No newline at end of file
......@@ -4,12 +4,17 @@ using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels
{
public class CreateUpdateProductDetailViewModel
public class CreateEditProductDetailViewModel
{
[HiddenInput]
[Display(Name = "ProductStore")]
public Guid StoreId { get; set; }
[TextArea(Rows = 4)]
[Display(Name = "ProductDetailDescription")]
public string Description { get; set; }
......
......@@ -28,7 +28,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewM
[Display(Name = "ProductDisplayName")]
public string DisplayName { get; set; }
public CreateUpdateProductDetailViewModel ProductDetail { get; set; }
public CreateEditProductDetailViewModel ProductDetail { get; set; }
[Required]
[Placeholder("ProductAttributeNamesPlaceholder")]
......
......@@ -34,7 +34,7 @@ $(function () {
return l('ProductDeletionConfirmationMessage', data.record.id);
},
action: function (data) {
service.delete({ id: data.record.id, storeId: storeId })
service.delete(data.record.id, storeId)
.then(function () {
abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload();
......
......@@ -5,6 +5,7 @@ using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Products.Categories.Dtos;
using EasyAbp.EShop.Products.ProductTypes.Dtos;
using AutoMapper;
using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels;
using Volo.Abp.AutoMapper;
......@@ -18,7 +19,9 @@ namespace EasyAbp.EShop.Products.Web
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<ProductDto, CreateEditProductViewModel>()
.Ignore(dto => dto.ProductDetail)
.Ignore(dto => dto.StoreId)
.ForSourceMember(dto => dto.ProductDetailId, opt => opt.DoNotValidate())
// .Ignore(x => x.ProductAttributes);
.ForMember(dest => dest.ProductAttributeNames,
opt => opt.MapFrom(source =>
......@@ -29,6 +32,8 @@ namespace EasyAbp.EShop.Products.Web
.Select(a => a.ProductAttributeOptions.Select(o => o.DisplayName).JoinAsString(","))
.JoinAsString(Environment.NewLine)));
CreateMap<CreateEditProductViewModel, CreateUpdateProductDto>()
.Ignore(dto => dto.ProductDetailId)
.ForSourceMember(model => model.ProductDetail, opt => opt.DoNotValidate())
.ForMember(dest => dest.ProductAttributes,
opt => opt.MapFrom(x =>
x.ProductAttributeNames.Split(",", StringSplitOptions.RemoveEmptyEntries).Select((s, i) =>
......@@ -40,12 +45,13 @@ namespace EasyAbp.EShop.Products.Web
.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(o =>
new CreateUpdateProductAttributeOptionDto {DisplayName = o}))
})));
CreateMap<ProductDetailDto, CreateUpdateProductDetailViewModel>();
CreateMap<CreateUpdateProductDetailViewModel, CreateUpdateProductDetailDto>();
CreateMap<ProductAttributeDto, CreateUpdateProductAttributeViewModel>();
CreateMap<CreateUpdateProductAttributeViewModel, CreateUpdateProductAttributeDto>();
CreateMap<ProductAttributeOptionDto, CreateUpdateProductAttributeOptionViewModel>();
CreateMap<CreateUpdateProductAttributeOptionViewModel, CreateUpdateProductAttributeOptionDto>();
CreateMap<ProductDetailDto, CreateEditProductDetailViewModel>()
.Ignore(model => model.StoreId);
CreateMap<CreateEditProductDetailViewModel, CreateUpdateProductDetailDto>();
CreateMap<ProductAttributeDto, CreateEditProductAttributeViewModel>();
CreateMap<CreateEditProductAttributeViewModel, CreateUpdateProductAttributeDto>();
CreateMap<ProductAttributeOptionDto, CreateEditProductAttributeOptionViewModel>();
CreateMap<CreateEditProductAttributeOptionViewModel, CreateUpdateProductAttributeOptionDto>();
CreateMap<CategoryDto, CreateUpdateCategoryDto>();
CreateMap<ProductTypeDto, CreateUpdateProductTypeDto>();
}
......
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace EasyMall.Migrations
{
public partial class ProductEntitiesAdjustment : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_ProductsProductDetails_ProductsProducts_ProductId",
table: "ProductsProductDetails");
migrationBuilder.DropPrimaryKey(
name: "PK_ProductsProductDetails",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "ProductId",
table: "ProductsProductDetails");
migrationBuilder.AddColumn<Guid>(
name: "ProductDetailId",
table: "ProductsProductSkus",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "ProductDetailId",
table: "ProductsProducts",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddColumn<Guid>(
name: "Id",
table: "ProductsProductDetails",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddColumn<string>(
name: "ConcurrencyStamp",
table: "ProductsProductDetails",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "CreationTime",
table: "ProductsProductDetails",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<Guid>(
name: "CreatorId",
table: "ProductsProductDetails",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "DeleterId",
table: "ProductsProductDetails",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "DeletionTime",
table: "ProductsProductDetails",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "ExtraProperties",
table: "ProductsProductDetails",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsDeleted",
table: "ProductsProductDetails",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<DateTime>(
name: "LastModificationTime",
table: "ProductsProductDetails",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "LastModifierId",
table: "ProductsProductDetails",
nullable: true);
migrationBuilder.AddPrimaryKey(
name: "PK_ProductsProductDetails",
table: "ProductsProductDetails",
column: "Id");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_ProductsProductDetails",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "ProductDetailId",
table: "ProductsProductSkus");
migrationBuilder.DropColumn(
name: "ProductDetailId",
table: "ProductsProducts");
migrationBuilder.DropColumn(
name: "Id",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "ConcurrencyStamp",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "CreationTime",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "CreatorId",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "DeleterId",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "DeletionTime",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "ExtraProperties",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "IsDeleted",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "LastModificationTime",
table: "ProductsProductDetails");
migrationBuilder.DropColumn(
name: "LastModifierId",
table: "ProductsProductDetails");
migrationBuilder.AddColumn<Guid>(
name: "ProductId",
table: "ProductsProductDetails",
type: "uniqueidentifier",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddPrimaryKey(
name: "PK_ProductsProductDetails",
table: "ProductsProductDetails",
column: "ProductId");
migrationBuilder.AddForeignKey(
name: "FK_ProductsProductDetails_ProductsProducts_ProductId",
table: "ProductsProductDetails",
column: "ProductId",
principalTable: "ProductsProducts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}
......@@ -134,6 +134,59 @@ namespace EasyMall.Migrations
b.ToTable("ProductsProductCategories");
});
modelBuilder.Entity("EasyAbp.EShop.Products.ProductDetails.ProductDetail", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnName("ConcurrencyStamp")
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime")
.HasColumnType("datetime2");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasColumnType("nvarchar(max)");
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties")
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasColumnType("bit")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime")
.HasColumnType("datetime2");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.ToTable("ProductsProductDetails");
});
modelBuilder.Entity("EasyAbp.EShop.Products.ProductStores.ProductStore", b =>
{
b.Property<Guid>("Id")
......@@ -319,6 +372,9 @@ namespace EasyMall.Migrations
b.Property<string>("MediaResources")
.HasColumnType("nvarchar(max)");
b.Property<Guid>("ProductDetailId")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("ProductTypeId")
.HasColumnType("uniqueidentifier");
......@@ -437,19 +493,6 @@ namespace EasyMall.Migrations
b.ToTable("ProductsProductAttributeOptions");
});
modelBuilder.Entity("EasyAbp.EShop.Products.Products.ProductDetail", b =>
{
b.Property<Guid>("ProductId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Description")
.HasColumnType("nvarchar(max)");
b.HasKey("ProductId");
b.ToTable("ProductsProductDetails");
});
modelBuilder.Entity("EasyAbp.EShop.Products.Products.ProductSku", b =>
{
b.Property<Guid>("Id")
......@@ -501,6 +544,9 @@ namespace EasyMall.Migrations
b.Property<decimal>("Price")
.HasColumnType("decimal(18,6)");
b.Property<Guid?>("ProductDetailId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("ProductId")
.HasColumnType("uniqueidentifier");
......@@ -2125,15 +2171,6 @@ namespace EasyMall.Migrations
.HasForeignKey("ProductAttributeId");
});
modelBuilder.Entity("EasyAbp.EShop.Products.Products.ProductDetail", b =>
{
b.HasOne("EasyAbp.EShop.Products.Products.Product", null)
.WithOne("ProductDetail")
.HasForeignKey("EasyAbp.EShop.Products.Products.ProductDetail", "ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("EasyAbp.EShop.Products.Products.ProductSku", b =>
{
b.HasOne("EasyAbp.EShop.Products.Products.Product", null)
......
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