Browse Source

Make Product entities belong to a store. #110

pull/112/head
gdlcf88 6 years ago
parent
commit
d5f62f8e56
  1. 2
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs
  2. 2
      modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs
  3. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Permissions/ProductsPermissionDefinitionProvider.cs
  4. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Permissions/ProductsPermissions.cs
  5. 5
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductDetails/Dtos/CreateUpdateProductDetailDto.cs
  6. 10
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductDetails/Dtos/GetProductDetailListInput.cs
  7. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductDetails/Dtos/ProductDetailDto.cs
  8. 3
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductDetails/IProductDetailAppService.cs
  9. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductInventories/Dtos/UpdateProductInventoryDto.cs
  10. 12
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/CreateUpdateProductDto.cs
  11. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/ProductDto.cs
  12. 3
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/ProductSkuDto.cs
  13. 14
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/IProductAppService.cs
  14. 80
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/ProductDetails/ProductDetailAppService.cs
  15. 27
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/ProductInventories/ProductInventoryAppService.cs
  16. 143
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/Products/ProductAppService.cs
  17. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp.EShop.Products.Domain.Shared.csproj
  18. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/EShopProductsDomainSharedModule.cs
  19. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/cs.json
  20. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/en.json
  21. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/pl.json
  22. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/pt-BR.json
  23. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/sl.json
  24. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/tr.json
  25. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/vi.json
  26. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/zh-Hans.json
  27. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/zh-Hant.json
  28. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProduct.cs
  29. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductEto.cs
  30. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp.EShop.Products.Domain.csproj
  31. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/EShopProductsDomainModule.cs
  32. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductDetails/ProductDetail.cs
  33. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductHistories/IProductHistoryRecorder.cs
  34. 6
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductHistories/ProductHistoryRecorder.cs
  35. 12
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductStores/IProductStoreRepository.cs
  36. 33
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductStores/ProductStore.cs
  37. 8
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs
  38. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductPriceProvider.cs
  39. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductDiscountProvider.cs
  40. 8
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductInventoryProvider.cs
  41. 12
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductManager.cs
  42. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductPriceProvider.cs
  43. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductRepository.cs
  44. 6
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderCreatedEventHandler.cs
  45. 6
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderPaidEventHandler.cs
  46. 7
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/Product.cs
  47. 43
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductManager.cs
  48. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductSku.cs
  49. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/EntityFrameworkCore/EShopProductsEntityFrameworkCoreModule.cs
  50. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/EntityFrameworkCore/IProductsDbContext.cs
  51. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/EntityFrameworkCore/ProductsDbContext.cs
  52. 8
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/EntityFrameworkCore/ProductsDbContextModelCreatingExtensions.cs
  53. 29
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/ProductStores/ProductStoreRepository.cs
  54. 13
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/Products/DuplicatedProductUniqueNameException.cs
  55. 52
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/Products/ProductRepository.cs
  56. 10
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.HttpApi/EasyAbp/EShop/Products/ProductDetails/ProductDetailController.cs
  57. 40
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.HttpApi/EasyAbp/EShop/Products/Products/ProductController.cs
  58. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/EasyAbp.EShop.Products.Web.csproj
  59. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Menus/ProductsMenuContributor.cs
  60. 19
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/CreateModal.cshtml.cs
  61. 19
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/EditModal.cshtml.cs
  62. 87
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/Index.cshtml
  63. 28
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/Index.cshtml.cs
  64. 10
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/CreateProductDetailViewModel.cs
  65. 74
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/CreateProductViewModel.cs
  66. 12
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/EditProductDetailViewModel.cs
  67. 11
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/EditProductViewModel.cs
  68. 28
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/ProductListFilterViewModel.cs
  69. 14
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/index.js
  70. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/ChangeInventoryModal.cshtml
  71. 5
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/ChangeInventoryModal.cshtml.cs
  72. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/CreateModal.cshtml
  73. 9
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/CreateModal.cshtml.cs
  74. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/EditModal.cshtml
  75. 8
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/EditModal.cshtml.cs
  76. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/Index.cshtml
  77. 5
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/Index.cshtml.cs
  78. 10
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/index.js
  79. 29
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/ProductsWebAutoMapperProfile.cs
  80. 2
      modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.Application.Tests/Products/ProductAppServiceTests.cs
  81. 23
      modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.Domain.Tests/ProductStores/ProductStoreDomainTests.cs
  82. 31
      modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.EntityFrameworkCore.Tests/EntityFrameworkCore/ProductStores/ProductStoreRepositoryTests.cs
  83. 3
      modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.TestBase/ProductsTestDataBuilder.cs
  84. 2
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/StoreOwners/Dtos/StoreOwnerDto.cs
  85. 13
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/Stores/Dtos/GetStoreListInput.cs
  86. 2
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/Stores/IStoreAppService.cs
  87. 1
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp.EShop.Stores.Application.csproj
  88. 4
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/EShopStoresApplicationModule.cs
  89. 42
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerAppService.cs
  90. 43
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/Stores/StoreAppService.cs
  91. 4
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/StoresApplicationAutoMapperProfile.cs
  92. 6
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain.Shared/EasyAbp/EShop/Stores/StoresConsts.cs
  93. 3
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain/EasyAbp/EShop/Stores/Stores/IStoreRepository.cs
  94. 11
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.EntityFrameworkCore/EasyAbp/EShop/Stores/Stores/StoreRepository.cs
  95. 4
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.HttpApi/EasyAbp/EShop/Stores/Stores/StoreController.cs
  96. 8
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/EShopStoresWebModule.cs
  97. 1
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/EasyAbp.EShop.Stores.Web.csproj
  98. 12
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/Pages/EShop/Stores/StoreOwners/StoreOwner/Index.js
  99. 17
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/Pages/EShop/Stores/StoreOwners/StoreOwner/ViewModels/CreateStoreOwnerViewModel.cs
  100. 2
      plugins/Baskets/src/EasyAbp.EShop.Plugins.Baskets.Application.Contracts/EasyAbp/EShop/Plugins/Baskets/BasketItems/Dtos/CreateBasketItemDto.cs

2
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs

@ -120,7 +120,7 @@ namespace EasyAbp.EShop.Orders.Orders
foreach (var productId in productIds.Distinct().ToList()) foreach (var productId in productIds.Distinct().ToList())
{ {
dict.Add(productId, await _productAppService.GetAsync(productId, storeId)); dict.Add(productId, await _productAppService.GetAsync(productId));
} }
return dict; return dict;

2
modules/EasyAbp.EShop.Orders/test/EasyAbp.EShop.Orders.Application.Tests/Orders/OrderAppServiceTests.cs

@ -25,7 +25,7 @@ namespace EasyAbp.EShop.Orders.Orders
protected override void AfterAddApplication(IServiceCollection services) protected override void AfterAddApplication(IServiceCollection services)
{ {
var productAppService = Substitute.For<IProductAppService>(); var productAppService = Substitute.For<IProductAppService>();
productAppService.GetAsync(OrderTestData.Product1Id, OrderTestData.Store1Id).Returns(Task.FromResult(new ProductDto productAppService.GetAsync(OrderTestData.Product1Id).Returns(Task.FromResult(new ProductDto
{ {
CreationTime = DateTime.Now, CreationTime = DateTime.Now,
IsPublished = true, IsPublished = true,

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Permissions/ProductsPermissionDefinitionProvider.cs

@ -13,6 +13,7 @@ namespace EasyAbp.EShop.Products.Permissions
var categories = moduleGroup.AddPermission(ProductsPermissions.Categories.Default, L("Permission:Category")); var categories = moduleGroup.AddPermission(ProductsPermissions.Categories.Default, L("Permission:Category"));
categories.AddChild(ProductsPermissions.Categories.CrossStore, L("Permission:CrossStore")); categories.AddChild(ProductsPermissions.Categories.CrossStore, L("Permission:CrossStore"));
categories.AddChild(ProductsPermissions.Categories.Manage, L("Permission:Manage"));
categories.AddChild(ProductsPermissions.Categories.Create, L("Permission:Create")); categories.AddChild(ProductsPermissions.Categories.Create, L("Permission:Create"));
categories.AddChild(ProductsPermissions.Categories.Update, L("Permission:Update")); categories.AddChild(ProductsPermissions.Categories.Update, L("Permission:Update"));
categories.AddChild(ProductsPermissions.Categories.Delete, L("Permission:Delete")); categories.AddChild(ProductsPermissions.Categories.Delete, L("Permission:Delete"));
@ -20,6 +21,7 @@ namespace EasyAbp.EShop.Products.Permissions
var product = moduleGroup.AddPermission(ProductsPermissions.Products.Default, L("Permission:Product")); var product = moduleGroup.AddPermission(ProductsPermissions.Products.Default, L("Permission:Product"));
product.AddChild(ProductsPermissions.Products.CrossStore, L("Permission:CrossStore")); product.AddChild(ProductsPermissions.Products.CrossStore, L("Permission:CrossStore"));
product.AddChild(ProductsPermissions.Products.Manage, L("Permission:Manage"));
product.AddChild(ProductsPermissions.Products.Create, L("Permission:Create")); product.AddChild(ProductsPermissions.Products.Create, L("Permission:Create"));
product.AddChild(ProductsPermissions.Products.Update, L("Permission:Update")); product.AddChild(ProductsPermissions.Products.Update, L("Permission:Update"));
product.AddChild(ProductsPermissions.Products.Delete, L("Permission:Delete")); product.AddChild(ProductsPermissions.Products.Delete, L("Permission:Delete"));

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Permissions/ProductsPermissions.cs

@ -10,6 +10,7 @@ namespace EasyAbp.EShop.Products.Permissions
{ {
public const string Default = GroupName + ".Category"; public const string Default = GroupName + ".Category";
public const string CrossStore = Default + ".CrossStore"; public const string CrossStore = Default + ".CrossStore";
public const string Manage = Default + ".Manage";
public const string Delete = Default + ".Delete"; public const string Delete = Default + ".Delete";
public const string Update = Default + ".Update"; public const string Update = Default + ".Update";
public const string Create = Default + ".Create"; public const string Create = Default + ".Create";
@ -20,6 +21,7 @@ namespace EasyAbp.EShop.Products.Permissions
{ {
public const string Default = GroupName + ".Product"; public const string Default = GroupName + ".Product";
public const string CrossStore = Default + ".CrossStore"; public const string CrossStore = Default + ".CrossStore";
public const string Manage = Default + ".Manage";
public const string Delete = Default + ".Delete"; public const string Delete = Default + ".Delete";
public const string Update = Default + ".Update"; public const string Update = Default + ".Update";
public const string Create = Default + ".Create"; public const string Create = Default + ".Create";

5
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductDetails/Dtos/CreateUpdateProductDetailDto.cs

@ -7,11 +7,8 @@ namespace EasyAbp.EShop.Products.ProductDetails.Dtos
[Serializable] [Serializable]
public class CreateUpdateProductDetailDto : ExtensibleObject public class CreateUpdateProductDetailDto : ExtensibleObject
{ {
/// <summary>
/// This property is for product management permission checking
/// </summary>
[DisplayName("ProductDetailStoreId")] [DisplayName("ProductDetailStoreId")]
public Guid StoreId { get; set; } public Guid? StoreId { get; set; }
[DisplayName("ProductDetailDescription")] [DisplayName("ProductDetailDescription")]
public string Description { get; set; } public string Description { get; set; }

10
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductDetails/Dtos/GetProductDetailListInput.cs

@ -0,0 +1,10 @@
using System;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Products.ProductDetails.Dtos
{
public class GetProductDetailListInput : PagedAndSortedResultRequestDto
{
public Guid? StoreId { get; set; }
}
}

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductDetails/Dtos/ProductDetailDto.cs

@ -6,6 +6,8 @@ namespace EasyAbp.EShop.Products.ProductDetails.Dtos
[Serializable] [Serializable]
public class ProductDetailDto : ExtensibleEntityDto<Guid> public class ProductDetailDto : ExtensibleEntityDto<Guid>
{ {
public Guid? StoreId { get; set; }
public string Description { get; set; } public string Description { get; set; }
} }
} }

3
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductDetails/IProductDetailAppService.cs

@ -10,10 +10,9 @@ namespace EasyAbp.EShop.Products.ProductDetails
ICrudAppService< ICrudAppService<
ProductDetailDto, ProductDetailDto,
Guid, Guid,
PagedAndSortedResultRequestDto, GetProductDetailListInput,
CreateUpdateProductDetailDto, CreateUpdateProductDetailDto,
CreateUpdateProductDetailDto> CreateUpdateProductDetailDto>
{ {
Task DeleteAsync(Guid id, Guid storeId);
} }
} }

4
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/ProductInventories/Dtos/UpdateProductInventoryDto.cs

@ -9,9 +9,7 @@ namespace EasyAbp.EShop.Products.ProductInventories.Dtos
public Guid ProductId { get; set; } public Guid ProductId { get; set; }
public Guid ProductSkuId { get; set; } public Guid ProductSkuId { get; set; }
public Guid? StoreId { get; set; }
/// <summary> /// <summary>
/// Reduce inventory if the value is less than 0 /// Reduce inventory if the value is less than 0
/// </summary> /// </summary>

12
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/CreateUpdateProductDto.cs

@ -3,24 +3,22 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using EasyAbp.EShop.Stores.Stores;
using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Products.Products.Dtos namespace EasyAbp.EShop.Products.Products.Dtos
{ {
[Serializable] [Serializable]
public class CreateUpdateProductDto : ExtensibleObject public class CreateUpdateProductDto : ExtensibleObject, IMultiStore
{ {
[DisplayName("ProductStoreId")]
public Guid StoreId { get; set; }
[DisplayName("ProductProductGroupName")] [DisplayName("ProductProductGroupName")]
public string ProductGroupName { get; set; } public string ProductGroupName { get; set; }
[DisplayName("ProductDetailId")] [DisplayName("ProductDetailId")]
public Guid ProductDetailId { get; set; } 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>
[DisplayName("ProductStoreId")]
public Guid StoreId { get; set; }
[DisplayName("ProductCategory")] [DisplayName("ProductCategory")]
public ICollection<Guid> CategoryIds { get; set; } public ICollection<Guid> CategoryIds { get; set; }

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/ProductDto.cs

@ -8,6 +8,8 @@ namespace EasyAbp.EShop.Products.Products.Dtos
[Serializable] [Serializable]
public class ProductDto : ExtensibleFullAuditedEntityDto<Guid> public class ProductDto : ExtensibleFullAuditedEntityDto<Guid>
{ {
public Guid StoreId { get; set; }
public string ProductGroupName { get; set; } public string ProductGroupName { get; set; }
public string ProductGroupDisplayName { get; set; } public string ProductGroupDisplayName { get; set; }

3
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/Dtos/ProductSkuDto.cs

@ -16,9 +16,6 @@ namespace EasyAbp.EShop.Products.Products.Dtos
public decimal? OriginalPrice { get; set; } public decimal? OriginalPrice { get; set; }
/// <summary>
/// Price property in the ProductSku entity.
/// </summary>
public decimal Price { get; set; } public decimal Price { get; set; }
public decimal DiscountedPrice { get; set; } public decimal DiscountedPrice { get; set; }

14
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application.Contracts/EasyAbp/EShop/Products/Products/IProductAppService.cs

@ -14,17 +14,13 @@ namespace EasyAbp.EShop.Products.Products
CreateUpdateProductDto, CreateUpdateProductDto,
CreateUpdateProductDto> CreateUpdateProductDto>
{ {
Task DeleteAsync(Guid id, Guid storeId); Task<ProductDto> CreateSkuAsync(Guid productId, CreateProductSkuDto input);
Task<ProductDto> CreateSkuAsync(Guid productId, Guid storeId, CreateProductSkuDto input); Task<ProductDto> UpdateSkuAsync(Guid productId, Guid productSkuId, UpdateProductSkuDto input);
Task<ProductDto> UpdateSkuAsync(Guid productId, Guid productSkuId, Guid storeId, UpdateProductSkuDto input); Task<ProductDto> DeleteSkuAsync(Guid productId, Guid productSkuId);
Task<ProductDto> GetAsync(Guid id, Guid storeId); Task<ProductDto> GetByCodeAsync(Guid storeId, string code);
Task<ProductDto> GetByCodeAsync(string code, Guid storeId);
Task<ProductDto> DeleteSkuAsync(Guid productId, Guid productSkuId, Guid storeId);
Task<ListResultDto<ProductGroupDto>> GetProductGroupListAsync(); Task<ListResultDto<ProductGroupDto>> GetProductGroupListAsync();
} }

80
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/ProductDetails/ProductDetailAppService.cs

@ -1,16 +1,16 @@
using System; using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using EasyAbp.EShop.Products.Permissions; using EasyAbp.EShop.Products.Permissions;
using EasyAbp.EShop.Products.ProductDetails.Dtos; using EasyAbp.EShop.Products.ProductDetails.Dtos;
using EasyAbp.EShop.Products.Products; using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.ProductStores; using EasyAbp.EShop.Stores.Authorization;
using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
namespace EasyAbp.EShop.Products.ProductDetails namespace EasyAbp.EShop.Products.ProductDetails
{ {
public class ProductDetailAppService : CrudAppService<ProductDetail, ProductDetailDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateProductDetailDto, CreateUpdateProductDetailDto>, public class ProductDetailAppService : CrudAppService<ProductDetail, ProductDetailDto, Guid, GetProductDetailListInput, CreateUpdateProductDetailDto, CreateUpdateProductDetailDto>,
IProductDetailAppService IProductDetailAppService
{ {
protected override string CreatePolicyName { get; set; } = ProductsPermissions.Products.Create; protected override string CreatePolicyName { get; set; } = ProductsPermissions.Products.Create;
@ -20,26 +20,70 @@ namespace EasyAbp.EShop.Products.ProductDetails
protected override string GetListPolicyName { get; set; } = ProductsPermissions.Products.Default; protected override string GetListPolicyName { get; set; } = ProductsPermissions.Products.Default;
private readonly IProductRepository _productRepository; private readonly IProductRepository _productRepository;
private readonly IProductStoreRepository _productStoreRepository;
private readonly IProductDetailRepository _repository; private readonly IProductDetailRepository _repository;
public ProductDetailAppService( public ProductDetailAppService(
IProductRepository productRepository, IProductRepository productRepository,
IProductStoreRepository productStoreRepository,
IProductDetailRepository repository) : base(repository) IProductDetailRepository repository) : base(repository)
{ {
_productRepository = productRepository; _productRepository = productRepository;
_productStoreRepository = productStoreRepository;
_repository = repository; _repository = repository;
} }
protected override IQueryable<ProductDetail> CreateFilteredQuery(GetProductDetailListInput input)
{
return _repository.WhereIf(input.StoreId.HasValue, x => x.StoreId == input.StoreId.Value);
}
public override async Task<PagedResultDto<ProductDetailDto>> GetListAsync(GetProductDetailListInput input)
{
await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId, GetListPolicyName,
ProductsPermissions.Products.CrossStore);
var query = CreateFilteredQuery(input);
var totalCount = await AsyncExecuter.CountAsync(query);
query = ApplySorting(query, input);
query = ApplyPaging(query, input);
var productDetails = await AsyncExecuter.ToListAsync(query);
var entityDtos = await MapToGetListOutputDtosAsync(productDetails);
return new PagedResultDto<ProductDetailDto>(
totalCount,
entityDtos
);
}
public override async Task<ProductDetailDto> CreateAsync(CreateUpdateProductDetailDto input)
{
await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId, CreatePolicyName,
ProductsPermissions.Products.CrossStore);
var productDetail = await MapToEntityAsync(input);
TryToSetTenantId(productDetail);
await Repository.InsertAsync(productDetail, autoSave: true);
return await MapToGetOutputDtoAsync(productDetail);
}
public override async Task<ProductDetailDto> UpdateAsync(Guid id, CreateUpdateProductDetailDto input) public override async Task<ProductDetailDto> UpdateAsync(Guid id, CreateUpdateProductDetailDto input)
{ {
await CheckUpdatePolicyAsync(); await CheckUpdatePolicyAsync();
var product = await _productRepository.GetAsync(x => x.ProductDetailId == id); var product = await _productRepository.GetAsync(x => x.ProductDetailId == id);
await AuthorizationService.CheckMultiStorePolicyAsync(product.StoreId, UpdatePolicyName,
ProductsPermissions.Products.CrossStore);
await CheckStoreIsProductOwnerAsync(product.Id, input.StoreId); if (input.StoreId != product.StoreId)
{
await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId, UpdatePolicyName,
ProductsPermissions.Products.CrossStore);
}
var detail = await GetEntityByIdAsync(id); var detail = await GetEntityByIdAsync(id);
@ -50,32 +94,16 @@ namespace EasyAbp.EShop.Products.ProductDetails
return await MapToGetOutputDtoAsync(detail); return await MapToGetOutputDtoAsync(detail);
} }
public virtual async Task DeleteAsync(Guid id, Guid storeId) public override async Task DeleteAsync(Guid id)
{ {
await CheckDeletePolicyAsync(); await CheckDeletePolicyAsync();
var product = await _productRepository.GetAsync(x => x.ProductDetailId == id); var product = await _productRepository.GetAsync(x => x.ProductDetailId == id);
await CheckStoreIsProductOwnerAsync(product.Id, storeId); await AuthorizationService.CheckMultiStorePolicyAsync(product.StoreId, DeletePolicyName,
ProductsPermissions.Products.CrossStore);
await Repository.DeleteAsync(id); await Repository.DeleteAsync(id);
} }
[Obsolete("Should use DeleteAsync(Guid id, Guid storeId)")]
[RemoteService(false)]
public override Task DeleteAsync(Guid id)
{
throw new NotSupportedException();
}
protected virtual async Task CheckStoreIsProductOwnerAsync(Guid productId, Guid storeId)
{
var productStore = await _productStoreRepository.GetAsync(productId, storeId);
if (!productStore.IsOwner)
{
throw new StoreIsNotProductOwnerException(productId, storeId);
}
}
} }
} }

27
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/ProductInventories/ProductInventoryAppService.cs

@ -1,29 +1,27 @@
using EasyAbp.EShop.Products.Permissions; using EasyAbp.EShop.Products.Permissions;
using EasyAbp.EShop.Products.ProductInventories.Dtos; using EasyAbp.EShop.Products.ProductInventories.Dtos;
using EasyAbp.EShop.Products.Products; using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.ProductStores;
using EasyAbp.EShop.Stores.Authorization; using EasyAbp.EShop.Stores.Authorization;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Validation;
namespace EasyAbp.EShop.Products.ProductInventories namespace EasyAbp.EShop.Products.ProductInventories
{ {
public class ProductInventoryAppService : ApplicationService, IProductInventoryAppService public class ProductInventoryAppService : ApplicationService, IProductInventoryAppService
{ {
private readonly IProductRepository _productRepository;
private readonly IProductInventoryRepository _repository; private readonly IProductInventoryRepository _repository;
private readonly IProductStoreRepository _productStoreRepository;
private readonly DefaultProductInventoryProvider _productInventoryProvider; private readonly DefaultProductInventoryProvider _productInventoryProvider;
public ProductInventoryAppService( public ProductInventoryAppService(
IProductRepository productRepository,
IProductInventoryRepository repository, IProductInventoryRepository repository,
IProductStoreRepository productStoreRepository,
DefaultProductInventoryProvider productInventoryProvider) DefaultProductInventoryProvider productInventoryProvider)
{ {
_productRepository = productRepository;
_repository = repository; _repository = repository;
_productStoreRepository = productStoreRepository;
_productInventoryProvider = productInventoryProvider; _productInventoryProvider = productInventoryProvider;
} }
@ -44,13 +42,10 @@ namespace EasyAbp.EShop.Products.ProductInventories
public virtual async Task<ProductInventoryDto> UpdateAsync(UpdateProductInventoryDto input) public virtual async Task<ProductInventoryDto> UpdateAsync(UpdateProductInventoryDto input)
{ {
await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId, var product = await _productRepository.GetAsync(input.ProductId);
ProductsPermissions.ProductInventory.Update, ProductsPermissions.ProductInventory.CrossStore);
if (input.StoreId.HasValue) await AuthorizationService.CheckMultiStorePolicyAsync(product.StoreId,
{ ProductsPermissions.ProductInventory.Update, ProductsPermissions.ProductInventory.CrossStore);
await CheckStoreIsProductOwnerAsync(input.ProductId, input.StoreId.Value);
}
var productInventory = await _repository.FindAsync(x => x.ProductSkuId == input.ProductSkuId); var productInventory = await _repository.FindAsync(x => x.ProductSkuId == input.ProductSkuId);
@ -66,16 +61,6 @@ namespace EasyAbp.EShop.Products.ProductInventories
return ObjectMapper.Map<ProductInventory, ProductInventoryDto>(productInventory); return ObjectMapper.Map<ProductInventory, ProductInventoryDto>(productInventory);
} }
protected virtual async Task CheckStoreIsProductOwnerAsync(Guid productId, Guid storeId)
{
var productStore = await _productStoreRepository.GetAsync(productId, storeId);
if (!productStore.IsOwner)
{
throw new StoreIsNotProductOwnerException(productId, storeId);
}
}
protected virtual async Task ChangeInventoryAsync(ProductInventory productInventory, int changedInventory) protected virtual async Task ChangeInventoryAsync(ProductInventory productInventory, int changedInventory)
{ {

143
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/Products/ProductAppService.cs

@ -1,35 +1,31 @@
using EasyAbp.EShop.Products.Permissions; using EasyAbp.EShop.Products.Permissions;
using EasyAbp.EShop.Products.Products.Dtos; using EasyAbp.EShop.Products.Products.Dtos;
using EasyAbp.EShop.Products.ProductStores;
using EasyAbp.EShop.Stores.Authorization; using EasyAbp.EShop.Stores.Authorization;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using EasyAbp.EShop.Products.Options; using EasyAbp.EShop.Products.Options;
using EasyAbp.EShop.Stores.Stores;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace EasyAbp.EShop.Products.Products namespace EasyAbp.EShop.Products.Products
{ {
public class ProductAppService : CrudAppService<Product, ProductDto, Guid, GetProductListDto, CreateUpdateProductDto public class ProductAppService : MultiStoreCrudAppService<Product, ProductDto, Guid, GetProductListDto, CreateUpdateProductDto, CreateUpdateProductDto>, IProductAppService
, CreateUpdateProductDto>,
IProductAppService
{ {
protected override string CreatePolicyName { get; set; } = ProductsPermissions.Products.Create; protected override string CreatePolicyName { get; set; } = ProductsPermissions.Products.Create;
protected override string DeletePolicyName { get; set; } = ProductsPermissions.Products.Delete; protected override string DeletePolicyName { get; set; } = ProductsPermissions.Products.Delete;
protected override string UpdatePolicyName { get; set; } = ProductsPermissions.Products.Update; protected override string UpdatePolicyName { get; set; } = ProductsPermissions.Products.Update;
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;
protected override string CrossStorePolicyName { get; set; } = ProductsPermissions.Products.CrossStore;
private readonly IProductManager _productManager; private readonly IProductManager _productManager;
private readonly EShopProductsOptions _options; private readonly EShopProductsOptions _options;
private readonly IProductInventoryProvider _productInventoryProvider; private readonly IProductInventoryProvider _productInventoryProvider;
private readonly IAttributeOptionIdsSerializer _attributeOptionIdsSerializer; private readonly IAttributeOptionIdsSerializer _attributeOptionIdsSerializer;
private readonly IProductStoreRepository _productStoreRepository;
private readonly IProductRepository _repository; private readonly IProductRepository _repository;
public ProductAppService( public ProductAppService(
@ -37,22 +33,24 @@ namespace EasyAbp.EShop.Products.Products
IOptions<EShopProductsOptions> options, IOptions<EShopProductsOptions> options,
IProductInventoryProvider productInventoryProvider, IProductInventoryProvider productInventoryProvider,
IAttributeOptionIdsSerializer attributeOptionIdsSerializer, IAttributeOptionIdsSerializer attributeOptionIdsSerializer,
IProductStoreRepository productStoreRepository,
IProductRepository repository) : base(repository) IProductRepository repository) : base(repository)
{ {
_productManager = productManager; _productManager = productManager;
_options = options.Value; _options = options.Value;
_productInventoryProvider = productInventoryProvider; _productInventoryProvider = productInventoryProvider;
_attributeOptionIdsSerializer = attributeOptionIdsSerializer; _attributeOptionIdsSerializer = attributeOptionIdsSerializer;
_productStoreRepository = productStoreRepository;
_repository = repository; _repository = repository;
} }
protected override IQueryable<Product> CreateFilteredQuery(GetProductListDto input) protected override IQueryable<Product> CreateFilteredQuery(GetProductListDto input)
{ {
var query = _repository.WithDetails(input.StoreId, input.CategoryId); var query = input.CategoryId.HasValue
? _repository.WithDetails(input.CategoryId.Value)
: _repository.WithDetails();
return input.ShowHidden ? query : query.Where(x => !x.IsHidden); return query
.Where(x => x.StoreId == input.StoreId)
.WhereIf(!input.ShowHidden, x => !x.IsHidden);
} }
protected override Product MapToEntity(CreateUpdateProductDto createInput) protected override Product MapToEntity(CreateUpdateProductDto createInput)
@ -64,20 +62,19 @@ namespace EasyAbp.EShop.Products.Products
public override async Task<ProductDto> CreateAsync(CreateUpdateProductDto input) public override async Task<ProductDto> CreateAsync(CreateUpdateProductDto input)
{ {
await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId, CreatePolicyName,
ProductsPermissions.Products.CrossStore);
var product = MapToEntity(input); var product = MapToEntity(input);
await CheckMultiStorePolicyAsync(product.StoreId, CreatePolicyName);
TryToSetTenantId(product); TryToSetTenantId(product);
await UpdateProductAttributesAsync(product, input); await UpdateProductAttributesAsync(product, input);
await _productManager.CreateAsync(product, input.StoreId, input.CategoryIds); await _productManager.CreateAsync(product, input.CategoryIds);
var dto = await MapToGetOutputDtoAsync(product); var dto = await MapToGetOutputDtoAsync(product);
await LoadDtoExtraDataAsync(product, dto, input.StoreId); await LoadDtoExtraDataAsync(product, dto);
await LoadDtosProductGroupDisplayNameAsync(new[] {dto}); await LoadDtosProductGroupDisplayNameAsync(new[] {dto});
return dto; return dto;
@ -85,13 +82,15 @@ namespace EasyAbp.EShop.Products.Products
public override async Task<ProductDto> UpdateAsync(Guid id, CreateUpdateProductDto input) public override async Task<ProductDto> UpdateAsync(Guid id, CreateUpdateProductDto input)
{ {
await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId, UpdatePolicyName,
ProductsPermissions.Products.CrossStore);
await CheckStoreIsProductOwnerAsync(id, input.StoreId);
var product = await GetEntityByIdAsync(id); var product = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(product.StoreId, UpdatePolicyName);
if (input.StoreId != product.StoreId)
{
await CheckMultiStorePolicyAsync(input.StoreId, UpdatePolicyName);
}
CheckProductIsNotStatic(product); CheckProductIsNotStatic(product);
MapToEntity(input, product); MapToEntity(input, product);
@ -102,22 +101,12 @@ namespace EasyAbp.EShop.Products.Products
var dto = await MapToGetOutputDtoAsync(product); var dto = await MapToGetOutputDtoAsync(product);
await LoadDtoExtraDataAsync(product, dto, input.StoreId); await LoadDtoExtraDataAsync(product, dto);
await LoadDtosProductGroupDisplayNameAsync(new[] {dto}); await LoadDtosProductGroupDisplayNameAsync(new[] {dto});
return dto; return dto;
} }
protected virtual async Task CheckStoreIsProductOwnerAsync(Guid productId, Guid storeId)
{
var productStore = await _productStoreRepository.GetAsync(productId, storeId);
if (!productStore.IsOwner)
{
throw new StoreIsNotProductOwnerException(productId, storeId);
}
}
protected virtual async Task UpdateProductAttributesAsync(Product product, CreateUpdateProductDto input) protected virtual async Task UpdateProductAttributesAsync(Product product, CreateUpdateProductDto input)
{ {
var isProductSkusEmpty = product.ProductSkus.IsNullOrEmpty(); var isProductSkusEmpty = product.ProductSkus.IsNullOrEmpty();
@ -191,21 +180,7 @@ namespace EasyAbp.EShop.Products.Products
product.ProductAttributes.RemoveAll(a => removedAttributeNames.Contains(a.DisplayName)); product.ProductAttributes.RemoveAll(a => removedAttributeNames.Contains(a.DisplayName));
} }
[Obsolete("Should use DeleteAsync(Guid id, Guid storeId)")] public override async Task<ProductDto> GetAsync(Guid id)
[RemoteService(false)]
public override Task DeleteAsync(Guid id)
{
throw new NotSupportedException();
}
[Obsolete("Should use GetAsync(Guid id, Guid storeId)")]
[RemoteService(false)]
public override Task<ProductDto> GetAsync(Guid id)
{
throw new NotSupportedException();
}
public virtual async Task<ProductDto> GetAsync(Guid id, Guid storeId)
{ {
await CheckGetPolicyAsync(); await CheckGetPolicyAsync();
@ -213,12 +188,12 @@ namespace EasyAbp.EShop.Products.Products
if (!product.IsPublished) if (!product.IsPublished)
{ {
await CheckStoreIsProductOwnerAsync(product.Id, storeId); await CheckMultiStorePolicyAsync(product.StoreId, ProductsPermissions.Products.Manage);
} }
var dto = await MapToGetOutputDtoAsync(product); var dto = await MapToGetOutputDtoAsync(product);
await LoadDtoExtraDataAsync(product, dto, storeId); await LoadDtoExtraDataAsync(product, dto);
await LoadDtosProductGroupDisplayNameAsync(new[] {dto}); await LoadDtosProductGroupDisplayNameAsync(new[] {dto});
return dto; return dto;
@ -236,7 +211,7 @@ namespace EasyAbp.EShop.Products.Products
return Task.CompletedTask; return Task.CompletedTask;
} }
public virtual async Task<ProductDto> GetByCodeAsync(string code, Guid storeId) public virtual async Task<ProductDto> GetByCodeAsync(Guid storeId, string code)
{ {
await CheckGetPolicyAsync(); await CheckGetPolicyAsync();
@ -244,12 +219,12 @@ namespace EasyAbp.EShop.Products.Products
if (!product.IsPublished) if (!product.IsPublished)
{ {
await CheckStoreIsProductOwnerAsync(product.Id, storeId); await CheckMultiStorePolicyAsync(product.StoreId, ProductsPermissions.Products.Manage);
} }
var dto = await MapToGetOutputDtoAsync(product); var dto = await MapToGetOutputDtoAsync(product);
await LoadDtoExtraDataAsync(product, dto, storeId); await LoadDtoExtraDataAsync(product, dto);
await LoadDtosProductGroupDisplayNameAsync(new[] {dto}); await LoadDtosProductGroupDisplayNameAsync(new[] {dto});
return dto; return dto;
@ -289,7 +264,7 @@ namespace EasyAbp.EShop.Products.Products
{ {
var productDto = await MapToGetListOutputDtoAsync(product); var productDto = await MapToGetListOutputDtoAsync(product);
await LoadDtoExtraDataAsync(product, productDto, input.StoreId); await LoadDtoExtraDataAsync(product, productDto);
items.Add(productDto); items.Add(productDto);
} }
@ -299,10 +274,9 @@ namespace EasyAbp.EShop.Products.Products
return new PagedResultDto<ProductDto>(totalCount, items); return new PagedResultDto<ProductDto>(totalCount, items);
} }
protected virtual async Task<ProductDto> LoadDtoInventoryDataAsync(Product product, ProductDto productDto, protected virtual async Task<ProductDto> LoadDtoInventoryDataAsync(Product product, ProductDto productDto)
Guid storeId)
{ {
var inventoryDataDict = await _productInventoryProvider.GetInventoryDataDictionaryAsync(product, storeId); var inventoryDataDict = await _productInventoryProvider.GetInventoryDataDictionaryAsync(product);
productDto.Sold = 0; productDto.Sold = 0;
@ -318,21 +292,21 @@ namespace EasyAbp.EShop.Products.Products
return productDto; return productDto;
} }
protected virtual async Task<ProductDto> LoadDtoExtraDataAsync(Product product, ProductDto productDto, Guid storeId) protected virtual async Task<ProductDto> LoadDtoExtraDataAsync(Product product, ProductDto productDto)
{ {
await LoadDtoInventoryDataAsync(product, productDto, storeId); await LoadDtoInventoryDataAsync(product, productDto);
await LoadDtoPriceDataAsync(product, productDto, storeId); await LoadDtoPriceDataAsync(product, productDto);
return productDto; return productDto;
} }
protected virtual async Task<ProductDto> LoadDtoPriceDataAsync(Product product, ProductDto productDto, Guid storeId) protected virtual async Task<ProductDto> LoadDtoPriceDataAsync(Product product, ProductDto productDto)
{ {
foreach (var productSku in product.ProductSkus) foreach (var productSku in product.ProductSkus)
{ {
var productSkuDto = productDto.ProductSkus.First(x => x.Id == productSku.Id); var productSkuDto = productDto.ProductSkus.First(x => x.Id == productSku.Id);
var priceDataModel = await _productManager.GetProductPriceAsync(product, productSku, storeId); var priceDataModel = await _productManager.GetProductPriceAsync(product, productSku);
productSkuDto.Price = priceDataModel.Price; productSkuDto.Price = priceDataModel.Price;
productSkuDto.DiscountedPrice = priceDataModel.DiscountedPrice; productSkuDto.DiscountedPrice = priceDataModel.DiscountedPrice;
@ -347,17 +321,14 @@ namespace EasyAbp.EShop.Products.Products
return productDto; return productDto;
} }
public async Task DeleteAsync(Guid id, Guid storeId) public override async Task DeleteAsync(Guid id)
{ {
await AuthorizationService.CheckMultiStorePolicyAsync(storeId, DeletePolicyName,
ProductsPermissions.Products.CrossStore);
var product = await GetEntityByIdAsync(id); var product = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(product.StoreId, DeletePolicyName);
CheckProductIsNotStatic(product); CheckProductIsNotStatic(product);
await CheckStoreIsProductOwnerAsync(id, storeId);
await _productManager.DeleteAsync(product); await _productManager.DeleteAsync(product);
} }
@ -369,15 +340,12 @@ namespace EasyAbp.EShop.Products.Products
} }
} }
public async Task<ProductDto> CreateSkuAsync(Guid productId, Guid storeId, CreateProductSkuDto input) public async Task<ProductDto> CreateSkuAsync(Guid productId, CreateProductSkuDto input)
{ {
await AuthorizationService.CheckMultiStorePolicyAsync(storeId, UpdatePolicyName,
ProductsPermissions.Products.CrossStore);
await CheckStoreIsProductOwnerAsync(productId, storeId);
var product = await GetEntityByIdAsync(productId); var product = await GetEntityByIdAsync(productId);
await CheckMultiStorePolicyAsync(product.StoreId, UpdatePolicyName);
CheckProductIsNotStatic(product); CheckProductIsNotStatic(product);
var sku = ObjectMapper.Map<CreateProductSkuDto, ProductSku>(input); var sku = ObjectMapper.Map<CreateProductSkuDto, ProductSku>(input);
@ -388,22 +356,18 @@ namespace EasyAbp.EShop.Products.Products
var dto = await MapToGetOutputDtoAsync(product); var dto = await MapToGetOutputDtoAsync(product);
await LoadDtoExtraDataAsync(product, dto, storeId); await LoadDtoExtraDataAsync(product, dto);
await LoadDtosProductGroupDisplayNameAsync(new[] {dto}); await LoadDtosProductGroupDisplayNameAsync(new[] {dto});
return dto; return dto;
} }
public async Task<ProductDto> UpdateSkuAsync(Guid productId, Guid productSkuId, Guid storeId, public async Task<ProductDto> UpdateSkuAsync(Guid productId, Guid productSkuId, UpdateProductSkuDto input)
UpdateProductSkuDto input)
{ {
await AuthorizationService.CheckMultiStorePolicyAsync(storeId, UpdatePolicyName,
ProductsPermissions.Products.CrossStore);
await CheckStoreIsProductOwnerAsync(productId, storeId);
var product = await GetEntityByIdAsync(productId); var product = await GetEntityByIdAsync(productId);
await CheckMultiStorePolicyAsync(product.StoreId, UpdatePolicyName);
CheckProductIsNotStatic(product); CheckProductIsNotStatic(product);
var sku = product.ProductSkus.Single(x => x.Id == productSkuId); var sku = product.ProductSkus.Single(x => x.Id == productSkuId);
@ -414,21 +378,18 @@ namespace EasyAbp.EShop.Products.Products
var dto = await MapToGetOutputDtoAsync(product); var dto = await MapToGetOutputDtoAsync(product);
await LoadDtoExtraDataAsync(product, dto, storeId); await LoadDtoExtraDataAsync(product, dto);
await LoadDtosProductGroupDisplayNameAsync(new[] {dto}); await LoadDtosProductGroupDisplayNameAsync(new[] {dto});
return dto; return dto;
} }
public async Task<ProductDto> DeleteSkuAsync(Guid productId, Guid productSkuId, Guid storeId) public async Task<ProductDto> DeleteSkuAsync(Guid productId, Guid productSkuId)
{ {
await AuthorizationService.CheckMultiStorePolicyAsync(storeId, UpdatePolicyName,
ProductsPermissions.Products.CrossStore);
await CheckStoreIsProductOwnerAsync(productId, storeId);
var product = await GetEntityByIdAsync(productId); var product = await GetEntityByIdAsync(productId);
await CheckMultiStorePolicyAsync(product.StoreId, UpdatePolicyName);
CheckProductIsNotStatic(product); CheckProductIsNotStatic(product);
var sku = product.ProductSkus.Single(x => x.Id == productSkuId); var sku = product.ProductSkus.Single(x => x.Id == productSkuId);
@ -437,7 +398,7 @@ namespace EasyAbp.EShop.Products.Products
var dto = await MapToGetOutputDtoAsync(product); var dto = await MapToGetOutputDtoAsync(product);
await LoadDtoExtraDataAsync(product, dto, storeId); await LoadDtoExtraDataAsync(product, dto);
await LoadDtosProductGroupDisplayNameAsync(new[] {dto}); await LoadDtosProductGroupDisplayNameAsync(new[] {dto});
return dto; return dto;

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp.EShop.Products.Domain.Shared.csproj

@ -11,6 +11,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="EasyAbp.Abp.Trees.Domain.Shared" Version="1.4.0" /> <PackageReference Include="EasyAbp.Abp.Trees.Domain.Shared" Version="1.4.0" />
<PackageReference Include="Volo.Abp.Validation" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.Validation" Version="$(AbpVersion)" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Domain.Shared\EasyAbp.EShop.Stores.Domain.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

4
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/EShopProductsDomainSharedModule.cs

@ -2,6 +2,7 @@
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using EasyAbp.EShop.Products.Localization; using EasyAbp.EShop.Products.Localization;
using EasyAbp.EShop.Stores;
using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Validation; using Volo.Abp.Validation;
using Volo.Abp.Validation.Localization; using Volo.Abp.Validation.Localization;
@ -11,7 +12,8 @@ namespace EasyAbp.EShop.Products
{ {
[DependsOn( [DependsOn(
typeof(AbpValidationModule), typeof(AbpValidationModule),
typeof(AbpTreesDomainSharedModule) typeof(AbpTreesDomainSharedModule),
typeof(EShopStoresDomainSharedModule)
)] )]
public class EShopProductsDomainSharedModule : AbpModule public class EShopProductsDomainSharedModule : AbpModule
{ {

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/cs.json

@ -5,7 +5,8 @@
"Menu:ProductManagement": "Products", "Menu:ProductManagement": "Products",
"Menu:Product": "Product", "Menu:Product": "Product",
"Product": "Product", "Product": "Product",
"ProductStore": "Store product", "ProductStoreId": "Store ID",
"ProductCategoryId": "Category ID",
"ProductProductGroupName": "Product group name", "ProductProductGroupName": "Product group name",
"ProductProductGroupDisplayName": "Product group", "ProductProductGroupDisplayName": "Product group",
"ProductDetailId": "Product detail ID", "ProductDetailId": "Product detail ID",
@ -13,10 +14,8 @@
"ProductDisplayName": "Display name", "ProductDisplayName": "Display name",
"ProductDisplayOrder": "Display order", "ProductDisplayOrder": "Display order",
"ProductSold": "Sold", "ProductSold": "Sold",
"ProductDetailProductId": "Product detail ID", "ProductDetailStoreId": "Store ID",
"ProductDetailProductSkuId": "Product SKU ID",
"ProductDetailDescription": "Description", "ProductDetailDescription": "Description",
"ProductDetailDisplayOrder": "Display order",
"ProductCategory": "Categories", "ProductCategory": "Categories",
"ProductAttribute": "Attribute", "ProductAttribute": "Attribute",
"ProductAttributeNames": "Attribute names", "ProductAttributeNames": "Attribute names",

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/en.json

@ -6,7 +6,8 @@
"ManageYourProfile": "Manage your profile", "ManageYourProfile": "Manage your profile",
"Menu:Product": "Product", "Menu:Product": "Product",
"Product": "Product", "Product": "Product",
"ProductStore": "Store product", "ProductStoreId": "Store ID",
"ProductCategoryId": "Category ID",
"ProductProductGroupName": "Product group name", "ProductProductGroupName": "Product group name",
"ProductProductGroupDisplayName": "Product group", "ProductProductGroupDisplayName": "Product group",
"ProductDetailId": "Product detail ID", "ProductDetailId": "Product detail ID",
@ -14,10 +15,8 @@
"ProductDisplayName": "Display name", "ProductDisplayName": "Display name",
"ProductDisplayOrder": "Display order", "ProductDisplayOrder": "Display order",
"ProductSold": "Sold", "ProductSold": "Sold",
"ProductDetailProductId": "Product detail ID", "ProductDetailStoreId": "Store ID",
"ProductDetailProductSkuId": "Product SKU ID",
"ProductDetailDescription": "Description", "ProductDetailDescription": "Description",
"ProductDetailDisplayOrder": "Display order",
"ProductCategory": "Categories", "ProductCategory": "Categories",
"ProductAttribute": "Attribute", "ProductAttribute": "Attribute",
"ProductAttributeNames": "Attribute names", "ProductAttributeNames": "Attribute names",

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/pl.json

@ -5,7 +5,8 @@
"Menu:ProductManagement": "Products", "Menu:ProductManagement": "Products",
"Menu:Product": "Product", "Menu:Product": "Product",
"Product": "Product", "Product": "Product",
"ProductStore": "Store product", "ProductStoreId": "Store ID",
"ProductCategoryId": "Category ID",
"ProductProductGroupName": "Product group name", "ProductProductGroupName": "Product group name",
"ProductProductGroupDisplayName": "Product group", "ProductProductGroupDisplayName": "Product group",
"ProductDetailId": "Product detail ID", "ProductDetailId": "Product detail ID",
@ -13,10 +14,8 @@
"ProductDisplayName": "Display name", "ProductDisplayName": "Display name",
"ProductDisplayOrder": "Display order", "ProductDisplayOrder": "Display order",
"ProductSold": "Sold", "ProductSold": "Sold",
"ProductDetailProductId": "Product detail ID", "ProductDetailStoreId": "Store ID",
"ProductDetailProductSkuId": "Product SKU ID",
"ProductDetailDescription": "Description", "ProductDetailDescription": "Description",
"ProductDetailDisplayOrder": "Display order",
"ProductCategory": "Categories", "ProductCategory": "Categories",
"ProductAttribute": "Attribute", "ProductAttribute": "Attribute",
"ProductAttributeNames": "Attribute names", "ProductAttributeNames": "Attribute names",

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/pt-BR.json

@ -5,7 +5,8 @@
"Menu:ProductManagement": "Products", "Menu:ProductManagement": "Products",
"Menu:Product": "Product", "Menu:Product": "Product",
"Product": "Product", "Product": "Product",
"ProductStore": "Store product", "ProductStoreId": "Store ID",
"ProductCategoryId": "Category ID",
"ProductProductGroupName": "Product group name", "ProductProductGroupName": "Product group name",
"ProductProductGroupDisplayName": "Product group", "ProductProductGroupDisplayName": "Product group",
"ProductDetailId": "Product detail ID", "ProductDetailId": "Product detail ID",
@ -13,10 +14,8 @@
"ProductDisplayName": "Display name", "ProductDisplayName": "Display name",
"ProductDisplayOrder": "Display order", "ProductDisplayOrder": "Display order",
"ProductSold": "Sold", "ProductSold": "Sold",
"ProductDetailProductId": "Product detail ID", "ProductDetailStoreId": "Store ID",
"ProductDetailProductSkuId": "Product SKU ID",
"ProductDetailDescription": "Description", "ProductDetailDescription": "Description",
"ProductDetailDisplayOrder": "Display order",
"ProductCategory": "Categories", "ProductCategory": "Categories",
"ProductAttribute": "Attribute", "ProductAttribute": "Attribute",
"ProductAttributeNames": "Attribute names", "ProductAttributeNames": "Attribute names",

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/sl.json

@ -6,7 +6,8 @@
"ManageYourProfile": "Upravljajte svojim profilom", "ManageYourProfile": "Upravljajte svojim profilom",
"Menu:Product": "Product", "Menu:Product": "Product",
"Product": "Product", "Product": "Product",
"ProductStore": "Store product", "ProductStoreId": "Store ID",
"ProductCategoryId": "Category ID",
"ProductProductGroupName": "Product group name", "ProductProductGroupName": "Product group name",
"ProductProductGroupDisplayName": "Product group", "ProductProductGroupDisplayName": "Product group",
"ProductDetailId": "Product detail ID", "ProductDetailId": "Product detail ID",
@ -14,10 +15,8 @@
"ProductDisplayName": "Display name", "ProductDisplayName": "Display name",
"ProductDisplayOrder": "Display order", "ProductDisplayOrder": "Display order",
"ProductSold": "Sold", "ProductSold": "Sold",
"ProductDetailProductId": "Product detail ID", "ProductDetailStoreId": "Store ID",
"ProductDetailProductSkuId": "Product SKU ID",
"ProductDetailDescription": "Description", "ProductDetailDescription": "Description",
"ProductDetailDisplayOrder": "Display order",
"ProductCategory": "Categories", "ProductCategory": "Categories",
"ProductAttribute": "Attribute", "ProductAttribute": "Attribute",
"ProductAttributeNames": "Attribute names", "ProductAttributeNames": "Attribute names",

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/tr.json

@ -6,7 +6,8 @@
"ManageYourProfile": "Profil y�netimi", "ManageYourProfile": "Profil y�netimi",
"Menu:Product": "Product", "Menu:Product": "Product",
"Product": "Product", "Product": "Product",
"ProductStore": "Store product", "ProductStoreId": "Store ID",
"ProductCategoryId": "Category ID",
"ProductProductGroupName": "Product group name", "ProductProductGroupName": "Product group name",
"ProductProductGroupDisplayName": "Product group", "ProductProductGroupDisplayName": "Product group",
"ProductDetailId": "Product detail ID", "ProductDetailId": "Product detail ID",
@ -14,10 +15,8 @@
"ProductDisplayName": "Display name", "ProductDisplayName": "Display name",
"ProductDisplayOrder": "Display order", "ProductDisplayOrder": "Display order",
"ProductSold": "Sold", "ProductSold": "Sold",
"ProductDetailProductId": "Product detail ID", "ProductDetailStoreId": "Store ID",
"ProductDetailProductSkuId": "Product SKU ID",
"ProductDetailDescription": "Description", "ProductDetailDescription": "Description",
"ProductDetailDisplayOrder": "Display order",
"ProductCategory": "Categories", "ProductCategory": "Categories",
"ProductAttribute": "Attribute", "ProductAttribute": "Attribute",
"ProductAttributeNames": "Attribute names", "ProductAttributeNames": "Attribute names",

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/vi.json

@ -5,7 +5,8 @@
"Menu:ProductManagement": "Products", "Menu:ProductManagement": "Products",
"Menu:Product": "Product", "Menu:Product": "Product",
"Product": "Product", "Product": "Product",
"ProductStore": "Store product", "ProductStoreId": "Store ID",
"ProductCategoryId": "Category ID",
"ProductProductGroupName": "Product group name", "ProductProductGroupName": "Product group name",
"ProductProductGroupDisplayName": "Product group", "ProductProductGroupDisplayName": "Product group",
"ProductDetailId": "Product detail ID", "ProductDetailId": "Product detail ID",
@ -13,10 +14,8 @@
"ProductDisplayName": "Display name", "ProductDisplayName": "Display name",
"ProductDisplayOrder": "Display order", "ProductDisplayOrder": "Display order",
"ProductSold": "Sold", "ProductSold": "Sold",
"ProductDetailProductId": "Product detail ID", "ProductDetailStoreId": "Store ID",
"ProductDetailProductSkuId": "Product SKU ID",
"ProductDetailDescription": "Description", "ProductDetailDescription": "Description",
"ProductDetailDisplayOrder": "Display order",
"ProductCategory": "Categories", "ProductCategory": "Categories",
"ProductAttribute": "Attribute", "ProductAttribute": "Attribute",
"ProductAttributeNames": "Attribute names", "ProductAttributeNames": "Attribute names",

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/zh-Hans.json

@ -6,7 +6,8 @@
"ManageYourProfile": "管理个人资料", "ManageYourProfile": "管理个人资料",
"Menu:Product": "商品", "Menu:Product": "商品",
"Product": "商品", "Product": "商品",
"ProductStore": "店铺商品", "ProductStoreId": "店铺 ID",
"ProductCategoryId": "类目 ID",
"ProductProductGroupName": "商品组", "ProductProductGroupName": "商品组",
"ProductProductGroupDisplayName": "商品组名称", "ProductProductGroupDisplayName": "商品组名称",
"ProductDetailId": "商品详情 ID", "ProductDetailId": "商品详情 ID",
@ -14,10 +15,8 @@
"ProductDisplayName": "商品名称", "ProductDisplayName": "商品名称",
"ProductDisplayOrder": "展示顺序", "ProductDisplayOrder": "展示顺序",
"ProductSold": "已售", "ProductSold": "已售",
"ProductDetailProductId": "商品 ID", "ProductDetailStoreId": "店铺 ID",
"ProductDetailProductSkuId": "商品 SKU ID",
"ProductDetailDescription": "内容", "ProductDetailDescription": "内容",
"ProductDetailDisplayOrder": "展示顺序",
"ProductCategory": "所属类目", "ProductCategory": "所属类目",
"ProductAttribute": "商品属性", "ProductAttribute": "商品属性",
"ProductAttributeNames": "商品属性", "ProductAttributeNames": "商品属性",

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Localization/Products/zh-Hant.json

@ -6,7 +6,8 @@
"ManageYourProfile": "管理個人資料", "ManageYourProfile": "管理個人資料",
"Menu:Product": "商品", "Menu:Product": "商品",
"Product": "商品", "Product": "商品",
"ProductStore": "店鋪商品", "ProductStoreId": "店鋪 ID",
"ProductCategoryId": "類目 ID",
"ProductProductGroupName": "商品組", "ProductProductGroupName": "商品組",
"ProductProductGroupDisplayName": "商品組名稱", "ProductProductGroupDisplayName": "商品組名稱",
"ProductDetailId": "商品詳情 ID", "ProductDetailId": "商品詳情 ID",
@ -14,10 +15,8 @@
"ProductDisplayName": "商品名稱", "ProductDisplayName": "商品名稱",
"ProductDisplayOrder": "展示順序", "ProductDisplayOrder": "展示順序",
"ProductSold": "已售", "ProductSold": "已售",
"ProductDetailProductId": "商品 ID", "ProductDetailStoreId": "店铺 ID",
"ProductDetailProductSkuId": "商品 SKU ID",
"ProductDetailDescription": "內容", "ProductDetailDescription": "內容",
"ProductDetailDisplayOrder": "展示順序",
"ProductCategory": "所屬類目", "ProductCategory": "所屬類目",
"ProductAttribute": "商品屬性", "ProductAttribute": "商品屬性",
"ProductAttributeNames": "商品屬性", "ProductAttributeNames": "商品屬性",

4
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/IProduct.cs

@ -1,10 +1,10 @@
using System; using System;
using System.Collections.Generic; using EasyAbp.EShop.Stores.Stores;
using Volo.Abp.Data; using Volo.Abp.Data;
namespace EasyAbp.EShop.Products.Products namespace EasyAbp.EShop.Products.Products
{ {
public interface IProduct : IHasExtraProperties public interface IProduct : IHasExtraProperties, IMultiStore
{ {
string ProductGroupName { get; } string ProductGroupName { get; }

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/Products/ProductEto.cs

@ -9,6 +9,8 @@ namespace EasyAbp.EShop.Products.Products
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid StoreId { get; set; }
public string ProductGroupName { get; set; } public string ProductGroupName { get; set; }
public Guid ProductDetailId { get; set; } public Guid ProductDetailId { get; set; }

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp.EShop.Products.Domain.csproj

@ -12,7 +12,6 @@
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Orders\src\EasyAbp.EShop.Orders.Domain.Shared\EasyAbp.EShop.Orders.Domain.Shared.csproj" /> <ProjectReference Include="..\..\..\EasyAbp.EShop.Orders\src\EasyAbp.EShop.Orders.Domain.Shared\EasyAbp.EShop.Orders.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Domain.Shared\EasyAbp.EShop.Stores.Domain.Shared.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Products.Domain.Shared\EasyAbp.EShop.Products.Domain.Shared.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Products.Domain.Shared\EasyAbp.EShop.Products.Domain.Shared.csproj" />
</ItemGroup> </ItemGroup>

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/EShopProductsDomainModule.cs

@ -12,7 +12,6 @@ namespace EasyAbp.EShop.Products
{ {
[DependsOn( [DependsOn(
typeof(EShopProductsDomainSharedModule), typeof(EShopProductsDomainSharedModule),
typeof(EShopStoresDomainSharedModule),
typeof(AbpTreesDomainModule) typeof(AbpTreesDomainModule)
)] )]
public class EShopProductsDomainModule : AbpModule public class EShopProductsDomainModule : AbpModule

4
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductDetails/ProductDetail.cs

@ -6,6 +6,8 @@ namespace EasyAbp.EShop.Products.ProductDetails
{ {
public class ProductDetail : FullAuditedAggregateRoot<Guid> public class ProductDetail : FullAuditedAggregateRoot<Guid>
{ {
public virtual Guid? StoreId { get; protected set; }
[CanBeNull] [CanBeNull]
public virtual string Description { get; protected set; } public virtual string Description { get; protected set; }
@ -13,8 +15,10 @@ namespace EasyAbp.EShop.Products.ProductDetails
public ProductDetail( public ProductDetail(
Guid id, Guid id,
Guid? storeId,
[CanBeNull] string description) : base(id) [CanBeNull] string description) : base(id)
{ {
StoreId = storeId;
Description = description; Description = description;
} }

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductHistories/IProductHistoryRecorder.cs

@ -4,7 +4,7 @@ using Volo.Abp.EventBus;
namespace EasyAbp.EShop.Products.ProductHistories namespace EasyAbp.EShop.Products.ProductHistories
{ {
public interface IProductHistoryRecorder : ILocalEventHandler<EntityChangedEventData<Product>> public interface IProductHistoryRecorder
{ {
} }

6
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductHistories/ProductHistoryRecorder.cs

@ -2,13 +2,17 @@
using EasyAbp.EShop.Products.Products; using EasyAbp.EShop.Products.Products;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.Json; using Volo.Abp.Json;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace EasyAbp.EShop.Products.ProductHistories namespace EasyAbp.EShop.Products.ProductHistories
{ {
public class ProductHistoryRecorder : IProductHistoryRecorder, ITransientDependency public class ProductHistoryRecorder :
ILocalEventHandler<EntityChangedEventData<Product>>,
IProductHistoryRecorder,
ITransientDependency
{ {
private readonly IGuidGenerator _guidGenerator; private readonly IGuidGenerator _guidGenerator;
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;

12
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductStores/IProductStoreRepository.cs

@ -1,12 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace EasyAbp.EShop.Products.ProductStores
{
public interface IProductStoreRepository : IRepository<ProductStore, Guid>
{
Task<ProductStore> GetAsync(Guid productId, Guid storeId, bool includeDetails = true, CancellationToken cancellationToken = default);
}
}

33
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/ProductStores/ProductStore.cs

@ -1,33 +0,0 @@
using System;
using EasyAbp.EShop.Stores.Stores;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace EasyAbp.EShop.Products.ProductStores
{
public class ProductStore : FullAuditedAggregateRoot<Guid>, IMultiTenant, IMultiStore
{
public virtual Guid? TenantId { get; protected set; }
public virtual Guid StoreId { get; protected set; }
public virtual Guid ProductId { get; protected set; }
public virtual bool IsOwner { get; protected set; }
protected ProductStore() {}
public ProductStore(
Guid id,
Guid? tenantId,
Guid storeId,
Guid productId,
bool isOwner) : base(id)
{
TenantId = tenantId;
StoreId = storeId;
ProductId = productId;
IsOwner = isOwner;
}
}
}

8
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs

@ -26,12 +26,12 @@ namespace EasyAbp.EShop.Products.Products
_productInventoryRepository = productInventoryRepository; _productInventoryRepository = productInventoryRepository;
} }
public virtual async Task<InventoryDataModel> GetInventoryDataAsync(Product product, ProductSku productSku, Guid storeId) public virtual async Task<InventoryDataModel> GetInventoryDataAsync(Product product, ProductSku productSku)
{ {
return await _productInventoryRepository.GetInventoryDataAsync(productSku.Id); return await _productInventoryRepository.GetInventoryDataAsync(productSku.Id);
} }
public virtual async Task<Dictionary<Guid, InventoryDataModel>> GetInventoryDataDictionaryAsync(Product product, Guid storeId) public virtual async Task<Dictionary<Guid, InventoryDataModel>> GetInventoryDataDictionaryAsync(Product product)
{ {
var dict = await _productInventoryRepository.GetInventoryDataDictionaryAsync(product.ProductSkus var dict = await _productInventoryRepository.GetInventoryDataDictionaryAsync(product.ProductSkus
.Select(sku => sku.Id).ToList()); .Select(sku => sku.Id).ToList());
@ -44,14 +44,14 @@ namespace EasyAbp.EShop.Products.Products
return dict; return dict;
} }
public virtual async Task<bool> TryIncreaseInventoryAsync(Product product, ProductSku productSku, Guid storeId, int quantity, bool decreaseSold) public virtual async Task<bool> TryIncreaseInventoryAsync(Product product, ProductSku productSku, int quantity, bool decreaseSold)
{ {
var productInventory = await _productInventoryRepository.GetAsync(x => x.ProductSkuId == productSku.Id); var productInventory = await _productInventoryRepository.GetAsync(x => x.ProductSkuId == productSku.Id);
return await TryIncreaseInventoryAsync(productInventory, quantity, decreaseSold); return await TryIncreaseInventoryAsync(productInventory, quantity, decreaseSold);
} }
public virtual async Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, Guid storeId, int quantity, bool increaseSold) public virtual async Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, int quantity, bool increaseSold)
{ {
var productInventory = await _productInventoryRepository.GetAsync(x => x.ProductSkuId == productSku.Id); var productInventory = await _productInventoryRepository.GetAsync(x => x.ProductSkuId == productSku.Id);

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductPriceProvider.cs

@ -6,7 +6,7 @@ namespace EasyAbp.EShop.Products.Products
{ {
public class DefaultProductPriceProvider : IProductPriceProvider, ITransientDependency public class DefaultProductPriceProvider : IProductPriceProvider, ITransientDependency
{ {
public virtual Task<decimal> GetPriceAsync(Product product, ProductSku productSku, Guid storeId) public virtual Task<decimal> GetPriceAsync(Product product, ProductSku productSku)
{ {
return Task.FromResult(productSku.Price); return Task.FromResult(productSku.Price);
} }

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductDiscountProvider.cs

@ -5,6 +5,6 @@ namespace EasyAbp.EShop.Products.Products
{ {
public interface IProductDiscountProvider public interface IProductDiscountProvider
{ {
Task<decimal> GetDiscountedPriceAsync(Product product, ProductSku productSku, Guid storeId, decimal currentPrice); Task<decimal> GetDiscountedPriceAsync(Product product, ProductSku productSku, decimal currentPrice);
} }
} }

8
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductInventoryProvider.cs

@ -6,12 +6,12 @@ namespace EasyAbp.EShop.Products.Products
{ {
public interface IProductInventoryProvider public interface IProductInventoryProvider
{ {
Task<InventoryDataModel> GetInventoryDataAsync(Product product, ProductSku productSku, Guid storeId); Task<InventoryDataModel> GetInventoryDataAsync(Product product, ProductSku productSku);
Task<Dictionary<Guid, InventoryDataModel>> GetInventoryDataDictionaryAsync(Product product, Guid storeId); Task<Dictionary<Guid, InventoryDataModel>> GetInventoryDataDictionaryAsync(Product product);
Task<bool> TryIncreaseInventoryAsync(Product product, ProductSku productSku, Guid storeId, int quantity, bool decreaseSold); Task<bool> TryIncreaseInventoryAsync(Product product, ProductSku productSku, int quantity, bool decreaseSold);
Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, Guid storeId, int quantity, bool increaseSold); Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, int quantity, bool increaseSold);
} }
} }

12
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductManager.cs

@ -7,7 +7,7 @@ namespace EasyAbp.EShop.Products.Products
{ {
public interface IProductManager : IDomainService public interface IProductManager : IDomainService
{ {
Task<Product> CreateAsync(Product product, Guid? storeId = null, IEnumerable<Guid> categoryIds = null); Task<Product> CreateAsync(Product product, IEnumerable<Guid> categoryIds = null);
Task<Product> UpdateAsync(Product product, IEnumerable<Guid> categoryIds = null); Task<Product> UpdateAsync(Product product, IEnumerable<Guid> categoryIds = null);
@ -21,14 +21,14 @@ namespace EasyAbp.EShop.Products.Products
Task<Product> DeleteSkuAsync(Product product, ProductSku productSku); Task<Product> DeleteSkuAsync(Product product, ProductSku productSku);
Task<bool> IsInventorySufficientAsync(Product product, ProductSku productSku, Guid storeId, int quantity); Task<bool> IsInventorySufficientAsync(Product product, ProductSku productSku, int quantity);
Task<InventoryDataModel> GetInventoryDataAsync(Product product, ProductSku productSku, Guid storeId); Task<InventoryDataModel> GetInventoryDataAsync(Product product, ProductSku productSku);
Task<bool> TryIncreaseInventoryAsync(Product product, ProductSku productSku, Guid storeId, int quantity, bool reduceSold); Task<bool> TryIncreaseInventoryAsync(Product product, ProductSku productSku, int quantity, bool reduceSold);
Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, Guid storeId, int quantity, bool increaseSold); Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, int quantity, bool increaseSold);
Task<PriceDataModel> GetProductPriceAsync(Product product, ProductSku productSku, Guid storeId); Task<PriceDataModel> GetProductPriceAsync(Product product, ProductSku productSku);
} }
} }

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductPriceProvider.cs

@ -5,6 +5,6 @@ namespace EasyAbp.EShop.Products.Products
{ {
public interface IProductPriceProvider public interface IProductPriceProvider
{ {
Task<decimal> GetPriceAsync(Product product, ProductSku productSku, Guid storeId); Task<decimal> GetPriceAsync(Product product, ProductSku productSku);
} }
} }

4
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/IProductRepository.cs

@ -6,8 +6,8 @@ namespace EasyAbp.EShop.Products.Products
{ {
public interface IProductRepository : IRepository<Product, Guid> public interface IProductRepository : IRepository<Product, Guid>
{ {
IQueryable<Product> GetQueryable(Guid storeId, Guid? categoryId = null); IQueryable<Product> GetQueryable(Guid categoryId);
IQueryable<Product> WithDetails(Guid storeId, Guid? categoryId = null); IQueryable<Product> WithDetails(Guid categoryId);
} }
} }

6
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderCreatedEventHandler.cs

@ -59,8 +59,7 @@ namespace EasyAbp.EShop.Products.Products
continue; continue;
} }
if (!await _productManager.IsInventorySufficientAsync(product, productSku, eventData.Entity.StoreId, if (!await _productManager.IsInventorySufficientAsync(product, productSku, orderLine.Quantity))
orderLine.Quantity))
{ {
await PublishResultEventAsync(eventData, false); await PublishResultEventAsync(eventData, false);
@ -78,8 +77,7 @@ namespace EasyAbp.EShop.Products.Products
foreach (var model in models) foreach (var model in models)
{ {
if (await _productManager.TryReduceInventoryAsync(model.Product, model.ProductSku, model.StoreId, if (await _productManager.TryReduceInventoryAsync(model.Product, model.ProductSku, model.Quantity, true))
model.Quantity, true))
{ {
continue; continue;
} }

6
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/OrderPaidEventHandler.cs

@ -58,8 +58,7 @@ namespace EasyAbp.EShop.Products.Products
continue; continue;
} }
if (!await _productManager.IsInventorySufficientAsync(product, productSku, eventData.Order.StoreId, if (!await _productManager.IsInventorySufficientAsync(product, productSku, orderLine.Quantity))
orderLine.Quantity))
{ {
await PublishResultEventAsync(eventData, false); await PublishResultEventAsync(eventData, false);
@ -77,8 +76,7 @@ namespace EasyAbp.EShop.Products.Products
foreach (var model in models) foreach (var model in models)
{ {
if (await _productManager.TryReduceInventoryAsync(model.Product, model.ProductSku, model.StoreId, if (await _productManager.TryReduceInventoryAsync(model.Product, model.ProductSku, model.Quantity, true))
model.Quantity, true))
{ {
continue; continue;
} }

7
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/Product.cs

@ -1,12 +1,15 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.Domain.Entities.Auditing;
namespace EasyAbp.EShop.Products.Products namespace EasyAbp.EShop.Products.Products
{ {
public class Product : FullAuditedAggregateRoot<Guid>, IProduct public class Product : FullAuditedAggregateRoot<Guid>, IProduct
{ {
public virtual Guid StoreId { get; protected set; }
[NotNull] [NotNull]
public virtual string ProductGroupName { get; protected set; } public virtual string ProductGroupName { get; protected set; }
@ -41,6 +44,7 @@ namespace EasyAbp.EShop.Products.Products
public Product( public Product(
Guid id, Guid id,
Guid storeId,
[NotNull] string productGroupName, [NotNull] string productGroupName,
Guid productDetailId, Guid productDetailId,
[CanBeNull] string code, [CanBeNull] string code,
@ -53,6 +57,7 @@ namespace EasyAbp.EShop.Products.Products
int displayOrder int displayOrder
) : base(id) ) : base(id)
{ {
StoreId = storeId;
ProductGroupName = productGroupName; ProductGroupName = productGroupName;
ProductDetailId = productDetailId; ProductDetailId = productDetailId;
UniqueName = code?.Trim(); UniqueName = code?.Trim();
@ -74,7 +79,7 @@ namespace EasyAbp.EShop.Products.Products
ProductSkus ??= new List<ProductSku>(); ProductSkus ??= new List<ProductSku>();
} }
public void TrimCode() public void TrimUniqueName()
{ {
UniqueName = UniqueName?.Trim(); UniqueName = UniqueName?.Trim();
} }

43
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductManager.cs

@ -4,7 +4,6 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using EasyAbp.EShop.Products.Options.ProductGroups; using EasyAbp.EShop.Products.Options.ProductGroups;
using EasyAbp.EShop.Products.ProductCategories; using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.ProductStores;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Domain.Services; using Volo.Abp.Domain.Services;
@ -13,7 +12,6 @@ namespace EasyAbp.EShop.Products.Products
public class ProductManager : DomainService, IProductManager public class ProductManager : DomainService, IProductManager
{ {
private readonly IProductRepository _productRepository; private readonly IProductRepository _productRepository;
private readonly IProductStoreRepository _productStoreRepository;
private readonly IProductPriceProvider _productPriceProvider; private readonly IProductPriceProvider _productPriceProvider;
private readonly IProductCategoryRepository _productCategoryRepository; private readonly IProductCategoryRepository _productCategoryRepository;
private readonly IProductInventoryProvider _productInventoryProvider; private readonly IProductInventoryProvider _productInventoryProvider;
@ -21,24 +19,21 @@ namespace EasyAbp.EShop.Products.Products
public ProductManager( public ProductManager(
IProductRepository productRepository, IProductRepository productRepository,
IProductStoreRepository productStoreRepository,
IProductPriceProvider productPriceProvider, IProductPriceProvider productPriceProvider,
IProductCategoryRepository productCategoryRepository, IProductCategoryRepository productCategoryRepository,
IProductInventoryProvider productInventoryProvider, IProductInventoryProvider productInventoryProvider,
IProductGroupConfigurationProvider productGroupConfigurationProvider) IProductGroupConfigurationProvider productGroupConfigurationProvider)
{ {
_productRepository = productRepository; _productRepository = productRepository;
_productStoreRepository = productStoreRepository;
_productPriceProvider = productPriceProvider; _productPriceProvider = productPriceProvider;
_productCategoryRepository = productCategoryRepository; _productCategoryRepository = productCategoryRepository;
_productInventoryProvider = productInventoryProvider; _productInventoryProvider = productInventoryProvider;
_productGroupConfigurationProvider = productGroupConfigurationProvider; _productGroupConfigurationProvider = productGroupConfigurationProvider;
} }
public virtual async Task<Product> CreateAsync(Product product, Guid? storeId = null, public virtual async Task<Product> CreateAsync(Product product, IEnumerable<Guid> categoryIds = null)
IEnumerable<Guid> categoryIds = null)
{ {
product.TrimCode(); product.TrimUniqueName();
await CheckProductGroupNameAsync(product); await CheckProductGroupNameAsync(product);
@ -50,11 +45,6 @@ namespace EasyAbp.EShop.Products.Products
await UpdateProductCategoriesAsync(product.Id, categoryIds); await UpdateProductCategoriesAsync(product.Id, categoryIds);
if (storeId.HasValue)
{
await AddProductToStoreAsync(product.Id, storeId.Value);
}
return product; return product;
} }
@ -153,12 +143,6 @@ namespace EasyAbp.EShop.Products.Products
return await _productRepository.UpdateAsync(product, true); return await _productRepository.UpdateAsync(product, true);
} }
protected virtual async Task AddProductToStoreAsync(Guid productId, Guid storeId)
{
await _productStoreRepository.InsertAsync(new ProductStore(GuidGenerator.Create(), CurrentTenant.Id,
storeId, productId, true), true);
}
protected virtual async Task CheckProductUniqueNameAsync(Product product) protected virtual async Task CheckProductUniqueNameAsync(Product product)
{ {
if (product.UniqueName.IsNullOrEmpty()) if (product.UniqueName.IsNullOrEmpty())
@ -201,38 +185,37 @@ namespace EasyAbp.EShop.Products.Products
} }
} }
public virtual async Task<bool> IsInventorySufficientAsync(Product product, ProductSku productSku, Guid storeId, int quantity) public virtual async Task<bool> IsInventorySufficientAsync(Product product, ProductSku productSku, int quantity)
{ {
var inventoryData = await _productInventoryProvider.GetInventoryDataAsync(product, productSku, storeId); var inventoryData = await _productInventoryProvider.GetInventoryDataAsync(product, productSku);
return product.InventoryStrategy == InventoryStrategy.NoNeed || inventoryData.Inventory - quantity >= 0; return product.InventoryStrategy == InventoryStrategy.NoNeed || inventoryData.Inventory - quantity >= 0;
} }
public virtual async Task<InventoryDataModel> GetInventoryDataAsync(Product product, ProductSku productSku, Guid storeId) public virtual async Task<InventoryDataModel> GetInventoryDataAsync(Product product, ProductSku productSku)
{ {
return await _productInventoryProvider.GetInventoryDataAsync(product, productSku, storeId); return await _productInventoryProvider.GetInventoryDataAsync(product, productSku);
} }
public virtual async Task<bool> TryIncreaseInventoryAsync(Product product, ProductSku productSku, Guid storeId, int quantity, bool reduceSold) public virtual async Task<bool> TryIncreaseInventoryAsync(Product product, ProductSku productSku, int quantity, bool reduceSold)
{ {
return await _productInventoryProvider.TryIncreaseInventoryAsync(product, productSku, storeId, quantity, reduceSold); return await _productInventoryProvider.TryIncreaseInventoryAsync(product, productSku, quantity, reduceSold);
} }
public virtual async Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, Guid storeId, int quantity, bool increaseSold) public virtual async Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, int quantity, bool increaseSold)
{ {
return await _productInventoryProvider.TryReduceInventoryAsync(product, productSku, storeId, quantity, return await _productInventoryProvider.TryReduceInventoryAsync(product, productSku, quantity, increaseSold);
increaseSold);
} }
public virtual async Task<PriceDataModel> GetProductPriceAsync(Product product, ProductSku productSku, Guid storeId) public virtual async Task<PriceDataModel> GetProductPriceAsync(Product product, ProductSku productSku)
{ {
var price = await _productPriceProvider.GetPriceAsync(product, productSku, storeId); var price = await _productPriceProvider.GetPriceAsync(product, productSku);
var discountedPrice = price; var discountedPrice = price;
foreach (var provider in ServiceProvider.GetServices<IProductDiscountProvider>()) foreach (var provider in ServiceProvider.GetServices<IProductDiscountProvider>())
{ {
discountedPrice = await provider.GetDiscountedPriceAsync(product, productSku, storeId, discountedPrice); discountedPrice = await provider.GetDiscountedPriceAsync(product, productSku, discountedPrice);
} }
return new PriceDataModel return new PriceDataModel

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductSku.cs

@ -64,7 +64,7 @@ namespace EasyAbp.EShop.Products.Products
this.SetDefaultsForExtraProperties(); this.SetDefaultsForExtraProperties();
} }
public void TrimCode() internal void TrimCode()
{ {
Name = Name?.Trim(); Name = Name?.Trim();
} }

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/EntityFrameworkCore/EShopProductsEntityFrameworkCoreModule.cs

@ -2,7 +2,6 @@ using EasyAbp.EShop.Products.ProductInventories;
using EasyAbp.Abp.Trees.EntityFrameworkCore; using EasyAbp.Abp.Trees.EntityFrameworkCore;
using EasyAbp.EShop.Products.ProductDetailHistories; using EasyAbp.EShop.Products.ProductDetailHistories;
using EasyAbp.EShop.Products.ProductHistories; using EasyAbp.EShop.Products.ProductHistories;
using EasyAbp.EShop.Products.ProductStores;
using EasyAbp.EShop.Products.ProductCategories; using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.Categories; using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.ProductDetails; using EasyAbp.EShop.Products.ProductDetails;
@ -31,7 +30,6 @@ namespace EasyAbp.EShop.Products.EntityFrameworkCore
options.AddRepository<Product, ProductRepository>(); options.AddRepository<Product, ProductRepository>();
options.AddRepository<ProductDetail, ProductDetailRepository>(); options.AddRepository<ProductDetail, ProductDetailRepository>();
options.AddRepository<ProductCategory, ProductCategoryRepository>(); options.AddRepository<ProductCategory, ProductCategoryRepository>();
options.AddRepository<ProductStore, ProductStoreRepository>();
options.AddRepository<ProductHistory, ProductHistoryRepository>(); options.AddRepository<ProductHistory, ProductHistoryRepository>();
options.AddRepository<ProductDetailHistory, ProductDetailHistoryRepository>(); options.AddRepository<ProductDetailHistory, ProductDetailHistoryRepository>();
options.AddRepository<ProductInventory, ProductInventoryRepository>(); options.AddRepository<ProductInventory, ProductInventoryRepository>();

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/EntityFrameworkCore/IProductsDbContext.cs

@ -5,7 +5,6 @@ using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Categories; using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.ProductCategories; using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.ProductDetails; using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductStores;
using EasyAbp.EShop.Products.ProductHistories; using EasyAbp.EShop.Products.ProductHistories;
using EasyAbp.EShop.Products.ProductDetailHistories; using EasyAbp.EShop.Products.ProductDetailHistories;
using EasyAbp.EShop.Products.ProductInventories; using EasyAbp.EShop.Products.ProductInventories;
@ -25,7 +24,6 @@ namespace EasyAbp.EShop.Products.EntityFrameworkCore
DbSet<ProductSku> ProductSkus { get; set; } DbSet<ProductSku> ProductSkus { get; set; }
DbSet<Category> Categories { get; set; } DbSet<Category> Categories { get; set; }
DbSet<ProductCategory> ProductCategories { get; set; } DbSet<ProductCategory> ProductCategories { get; set; }
DbSet<ProductStore> ProductStores { get; set; }
DbSet<ProductHistory> ProductHistories { get; set; } DbSet<ProductHistory> ProductHistories { get; set; }
DbSet<ProductDetailHistory> ProductDetailHistories { get; set; } DbSet<ProductDetailHistory> ProductDetailHistories { get; set; }
DbSet<ProductInventory> ProductInventories { get; set; } DbSet<ProductInventory> ProductInventories { get; set; }

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/EntityFrameworkCore/ProductsDbContext.cs

@ -5,7 +5,6 @@ using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Categories; using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.ProductCategories; using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.ProductDetails; using EasyAbp.EShop.Products.ProductDetails;
using EasyAbp.EShop.Products.ProductStores;
using EasyAbp.EShop.Products.ProductHistories; using EasyAbp.EShop.Products.ProductHistories;
using EasyAbp.EShop.Products.ProductDetailHistories; using EasyAbp.EShop.Products.ProductDetailHistories;
using EasyAbp.EShop.Products.ProductInventories; using EasyAbp.EShop.Products.ProductInventories;
@ -25,7 +24,6 @@ namespace EasyAbp.EShop.Products.EntityFrameworkCore
public DbSet<ProductSku> ProductSkus { get; set; } public DbSet<ProductSku> ProductSkus { get; set; }
public DbSet<Category> Categories { get; set; } public DbSet<Category> Categories { get; set; }
public DbSet<ProductCategory> ProductCategories { get; set; } public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductStore> ProductStores { get; set; }
public DbSet<ProductHistory> ProductHistories { get; set; } public DbSet<ProductHistory> ProductHistories { get; set; }
public DbSet<ProductDetailHistory> ProductDetailHistories { get; set; } public DbSet<ProductDetailHistory> ProductDetailHistories { get; set; }
public DbSet<ProductInventory> ProductInventories { get; set; } public DbSet<ProductInventory> ProductInventories { get; set; }

8
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/EntityFrameworkCore/ProductsDbContextModelCreatingExtensions.cs

@ -1,7 +1,6 @@
using EasyAbp.EShop.Products.ProductInventories; using EasyAbp.EShop.Products.ProductInventories;
using EasyAbp.EShop.Products.ProductDetailHistories; using EasyAbp.EShop.Products.ProductDetailHistories;
using EasyAbp.EShop.Products.ProductHistories; using EasyAbp.EShop.Products.ProductHistories;
using EasyAbp.EShop.Products.ProductStores;
using EasyAbp.EShop.Products.ProductCategories; using EasyAbp.EShop.Products.ProductCategories;
using EasyAbp.EShop.Products.Categories; using EasyAbp.EShop.Products.Categories;
using EasyAbp.EShop.Products.Products; using EasyAbp.EShop.Products.Products;
@ -103,13 +102,6 @@ namespace EasyAbp.EShop.Products.EntityFrameworkCore
/* Configure more properties here */ /* Configure more properties here */
}); });
builder.Entity<ProductStore>(b =>
{
b.ToTable(options.TablePrefix + "ProductStores", options.Schema);
b.ConfigureByConvention();
/* Configure more properties here */
});
builder.Entity<ProductHistory>(b => builder.Entity<ProductHistory>(b =>
{ {
b.ToTable(options.TablePrefix + "ProductHistories", options.Schema); b.ToTable(options.TablePrefix + "ProductHistories", options.Schema);

29
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/ProductStores/ProductStoreRepository.cs

@ -1,29 +0,0 @@
using EasyAbp.EShop.Products.EntityFrameworkCore;
using System;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace EasyAbp.EShop.Products.ProductStores
{
public class ProductStoreRepository : EfCoreRepository<IProductsDbContext, ProductStore, Guid>, IProductStoreRepository
{
public ProductStoreRepository(IDbContextProvider<IProductsDbContext> dbContextProvider) : base(dbContextProvider)
{
}
public virtual async Task<ProductStore> GetAsync(Guid productId, Guid storeId, bool includeDetails = true, CancellationToken cancellationToken = default)
{
var entity = await FindAsync(x => x.ProductId == productId && x.StoreId == storeId, includeDetails, cancellationToken);
if (entity == null)
{
throw new EntityNotFoundException(typeof(ProductStore), new { ProductId = productId, StoreId = storeId });
}
return entity;
}
}
}

13
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/Products/DuplicatedProductUniqueNameException.cs

@ -0,0 +1,13 @@
using Volo.Abp;
namespace EasyAbp.EShop.Products.Products
{
public class DuplicatedProductUniqueNameException : BusinessException
{
public DuplicatedProductUniqueNameException(string uniqueName) : base("DuplicatedProductUniqueName",
$"The product unique name \"{uniqueName}\" is duplicated.")
{
}
}
}

52
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.EntityFrameworkCore/EasyAbp/EShop/Products/Products/ProductRepository.cs

@ -1,5 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.EntityFrameworkCore; using EasyAbp.EShop.Products.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
@ -13,55 +15,45 @@ namespace EasyAbp.EShop.Products.Products
{ {
} }
public override IQueryable<Product> WithDetails() public override async Task<Product> UpdateAsync(Product entity, bool autoSave = false, CancellationToken cancellationToken = new CancellationToken())
{ {
return base.WithDetails() await CheckUniqueNameAsync(entity, cancellationToken);
.Include(x => x.ProductAttributes).ThenInclude(x => x.ProductAttributeOptions)
.Include(x => x.ProductSkus); return await base.UpdateAsync(entity, autoSave, cancellationToken);
} }
public IQueryable<Product> GetQueryable(Guid storeId, Guid? categoryId = null) public override async Task<Product> InsertAsync(Product entity, bool autoSave = false, CancellationToken cancellationToken = new CancellationToken())
{ {
var queryable = GetStoreQueryable(storeId); await CheckUniqueNameAsync(entity, cancellationToken);
if (categoryId.HasValue) return await base.InsertAsync(entity, autoSave, cancellationToken);
{
queryable = JoinProductCategories(queryable, categoryId.Value);
}
return queryable;
} }
public IQueryable<Product> WithDetails(Guid storeId, Guid? categoryId = null) protected virtual async Task CheckUniqueNameAsync(Product entity, CancellationToken cancellationToken = new CancellationToken())
{ {
var queryable = WithStoreDetails(storeId); if (await DbSet.AnyAsync(
x => x.StoreId == entity.StoreId && x.UniqueName == entity.UniqueName && x.Id != entity.Id,
if (categoryId.HasValue) cancellationToken))
{ {
queryable = JoinProductCategories(queryable, categoryId.Value); throw new DuplicatedProductUniqueNameException(entity.UniqueName);
} }
return queryable;
} }
protected virtual IQueryable<Product> GetStoreQueryable(Guid storeId) public override IQueryable<Product> WithDetails()
{ {
return JoinProductStores(GetQueryable(), storeId); return base.WithDetails()
.Include(x => x.ProductAttributes).ThenInclude(x => x.ProductAttributeOptions)
.Include(x => x.ProductSkus);
} }
protected virtual IQueryable<Product> WithStoreDetails(Guid storeId) public IQueryable<Product> GetQueryable(Guid categoryId)
{ {
return JoinProductStores(WithDetails(), storeId); return JoinProductCategories(DbSet, categoryId);
} }
protected virtual IQueryable<Product> JoinProductStores(IQueryable<Product> queryable, Guid storeId) public IQueryable<Product> WithDetails(Guid categoryId)
{ {
return queryable.Join( return JoinProductCategories(WithDetails(), categoryId);
DbContext.ProductStores.Where(productStore => productStore.StoreId == storeId),
product => product.Id,
productStore => productStore.ProductId,
(product, productStore) => product
);
} }
protected virtual IQueryable<Product> JoinProductCategories(IQueryable<Product> queryable, Guid categoryId) protected virtual IQueryable<Product> JoinProductCategories(IQueryable<Product> queryable, Guid categoryId)

10
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.HttpApi/EasyAbp/EShop/Products/ProductDetails/ProductDetailController.cs

@ -26,7 +26,7 @@ namespace EasyAbp.EShop.Products.ProductDetails
} }
[HttpGet] [HttpGet]
public Task<PagedResultDto<ProductDetailDto>> GetListAsync(PagedAndSortedResultRequestDto input) public Task<PagedResultDto<ProductDetailDto>> GetListAsync(GetProductDetailListInput input)
{ {
return _service.GetListAsync(input); return _service.GetListAsync(input);
} }
@ -50,13 +50,5 @@ namespace EasyAbp.EShop.Products.ProductDetails
{ {
return _service.DeleteAsync(id); return _service.DeleteAsync(id);
} }
[HttpDelete]
[Route("{id}/abandoned")]
[RemoteService(false)]
public Task DeleteAsync(Guid id, Guid storeId)
{
return _service.DeleteAsync(id, storeId);
}
} }
} }

40
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.HttpApi/EasyAbp/EShop/Products/Products/ProductController.cs

@ -18,14 +18,6 @@ namespace EasyAbp.EShop.Products.Products
_service = service; _service = service;
} }
[HttpGet]
[Route("{id}/abandoned")]
[RemoteService(false)]
public Task<ProductDto> GetAsync(Guid id)
{
return _service.GetAsync(id);
}
[HttpGet] [HttpGet]
public Task<PagedResultDto<ProductDto>> GetListAsync(GetProductListDto input) public Task<PagedResultDto<ProductDto>> GetListAsync(GetProductListDto input)
{ {
@ -46,53 +38,45 @@ namespace EasyAbp.EShop.Products.Products
} }
[HttpDelete] [HttpDelete]
[Route("{id}/abandoned")] [Route("{id}")]
[RemoteService(false)]
public Task DeleteAsync(Guid id) public Task DeleteAsync(Guid id)
{ {
return _service.DeleteAsync(id); return _service.DeleteAsync(id);
} }
[HttpDelete]
[Route("{id}")]
public Task DeleteAsync(Guid id, Guid storeId)
{
return _service.DeleteAsync(id, storeId);
}
[HttpPost] [HttpPost]
[Route("{id}/sku")] [Route("{id}/sku")]
public Task<ProductDto> CreateSkuAsync(Guid id, Guid storeId, CreateProductSkuDto input) public Task<ProductDto> CreateSkuAsync(Guid id, CreateProductSkuDto input)
{ {
return _service.CreateSkuAsync(id, storeId, input); return _service.CreateSkuAsync(id, input);
} }
[HttpPut] [HttpPut]
[Route("{id}/sku/{productSkuId}")] [Route("{id}/sku/{productSkuId}")]
public Task<ProductDto> UpdateSkuAsync(Guid id, Guid productSkuId, Guid storeId, UpdateProductSkuDto input) public Task<ProductDto> UpdateSkuAsync(Guid id, Guid productSkuId, UpdateProductSkuDto input)
{ {
return _service.UpdateSkuAsync(id, productSkuId, storeId, input); return _service.UpdateSkuAsync(id, productSkuId, input);
} }
[HttpGet] [HttpGet]
[Route("{id}")] [Route("{id}")]
public Task<ProductDto> GetAsync(Guid id, Guid storeId) public Task<ProductDto> GetAsync(Guid id)
{ {
return _service.GetAsync(id, storeId); return _service.GetAsync(id);
} }
[HttpGet] [HttpGet]
[Route("by-code/{storeId}")] [Route("by-code/{code}")]
public Task<ProductDto> GetByCodeAsync(string code, Guid storeId) public Task<ProductDto> GetByCodeAsync(Guid storeId, string code)
{ {
return _service.GetByCodeAsync(code, storeId); return _service.GetByCodeAsync(storeId, code);
} }
[HttpDelete] [HttpDelete]
[Route("{id}/sku/{productSkuId}")] [Route("{id}/sku/{productSkuId}")]
public Task<ProductDto> DeleteSkuAsync(Guid id, Guid productSkuId, Guid storeId) public Task<ProductDto> DeleteSkuAsync(Guid id, Guid productSkuId)
{ {
return _service.DeleteSkuAsync(id, productSkuId, storeId); return _service.DeleteSkuAsync(id, productSkuId);
} }
[HttpGet] [HttpGet]

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/EasyAbp.EShop.Products.Web.csproj

@ -14,7 +14,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared" Version="$(AbpVersion)" />
<PackageReference Include="EasyAbp.Abp.TagHelperPlus" Version="0.3.3" /> <PackageReference Include="EasyAbp.Abp.TagHelperPlus" Version="0.6.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

4
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Menus/ProductsMenuContributor.cs

@ -24,14 +24,14 @@ namespace EasyAbp.EShop.Products.Web.Menus
var productManagementMenuItem = new ApplicationMenuItem(ProductsMenus.Prefix, l["Menu:ProductManagement"]); var productManagementMenuItem = new ApplicationMenuItem(ProductsMenus.Prefix, l["Menu:ProductManagement"]);
if (await context.IsGrantedAsync(ProductsPermissions.Categories.Default)) if (await context.IsGrantedAsync(ProductsPermissions.Categories.Manage))
{ {
productManagementMenuItem.AddItem( productManagementMenuItem.AddItem(
new ApplicationMenuItem(ProductsMenus.Category, l["Menu:Category"], "/EShop/Products/Categories/Category") new ApplicationMenuItem(ProductsMenus.Category, l["Menu:Category"], "/EShop/Products/Categories/Category")
); );
} }
if (await context.IsGrantedAsync(ProductsPermissions.Products.Default)) if (await context.IsGrantedAsync(ProductsPermissions.Products.Manage))
{ {
productManagementMenuItem.AddItem( productManagementMenuItem.AddItem(
new ApplicationMenuItem(ProductsMenus.Product, l["Menu:Product"], "/EShop/Products/Products/Product") new ApplicationMenuItem(ProductsMenus.Product, l["Menu:Product"], "/EShop/Products/Products/Product")

19
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/CreateModal.cshtml.cs

@ -17,11 +17,8 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
{ {
public class CreateModalModel : ProductsPageModel public class CreateModalModel : ProductsPageModel
{ {
[BindProperty(SupportsGet = true)]
public Guid StoreId { get; set; }
[BindProperty] [BindProperty]
public CreateEditProductViewModel Product { get; set; } public CreateProductViewModel Product { get; set; }
public ICollection<SelectListItem> ProductGroups { get; set; } public ICollection<SelectListItem> ProductGroups { get; set; }
@ -41,7 +38,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
_service = service; _service = service;
} }
public virtual async Task OnGetAsync(Guid? categoryId) public virtual async Task OnGetAsync(Guid storeId, Guid? categoryId)
{ {
ProductGroups = ProductGroups =
(await _service.GetProductGroupListAsync()).Items (await _service.GetProductGroupListAsync()).Items
@ -52,12 +49,12 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
{ MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount }))?.Items { MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount }))?.Items
.Select(dto => new SelectListItem(dto.DisplayName, dto.Id.ToString())).ToList(); .Select(dto => new SelectListItem(dto.DisplayName, dto.Id.ToString())).ToList();
Product = new CreateEditProductViewModel Product = new CreateProductViewModel
{ {
StoreId = StoreId, StoreId = storeId,
ProductDetail = new CreateEditProductDetailViewModel ProductDetail = new CreateProductDetailViewModel
{ {
StoreId = StoreId StoreId = storeId
} }
}; };
@ -71,9 +68,9 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
{ {
var detail = await _productDetailAppService.CreateAsync( var detail = await _productDetailAppService.CreateAsync(
ObjectMapper ObjectMapper
.Map<CreateEditProductDetailViewModel, CreateUpdateProductDetailDto>(Product.ProductDetail)); .Map<CreateProductDetailViewModel, CreateUpdateProductDetailDto>(Product.ProductDetail));
var createDto = ObjectMapper.Map<CreateEditProductViewModel, CreateUpdateProductDto>(Product); var createDto = ObjectMapper.Map<CreateProductViewModel, CreateUpdateProductDto>(Product);
createDto.ProductDetailId = detail.Id; createDto.ProductDetailId = detail.Id;

19
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/EditModal.cshtml.cs

@ -24,7 +24,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
public Guid Id { get; set; } public Guid Id { get; set; }
[BindProperty] [BindProperty]
public CreateEditProductViewModel Product { get; set; } public EditProductViewModel Product { get; set; }
public ICollection<SelectListItem> ProductGroups { get; set; } public ICollection<SelectListItem> ProductGroups { get; set; }
@ -47,7 +47,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
_service = service; _service = service;
} }
public virtual async Task OnGetAsync(Guid storeId) public virtual async Task OnGetAsync()
{ {
ProductGroups = ProductGroups =
(await _service.GetProductGroupListAsync()).Items (await _service.GetProductGroupListAsync()).Items
@ -58,11 +58,11 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
{MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount}))?.Items {MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount}))?.Items
.Select(dto => new SelectListItem(dto.DisplayName, dto.Id.ToString())).ToList(); .Select(dto => new SelectListItem(dto.DisplayName, dto.Id.ToString())).ToList();
var productDto = await _service.GetAsync(Id, storeId); var productDto = await _service.GetAsync(Id);
var detailDto = await _productDetailAppService.GetAsync(productDto.ProductDetailId); var detailDto = await _productDetailAppService.GetAsync(productDto.ProductDetailId);
Product = ObjectMapper.Map<ProductDto, CreateEditProductViewModel>(productDto); Product = ObjectMapper.Map<ProductDto, EditProductViewModel>(productDto);
Product.CategoryIds = (await _productCategoryAppService.GetListAsync(new GetProductCategoryListDto Product.CategoryIds = (await _productCategoryAppService.GetListAsync(new GetProductCategoryListDto
{ {
@ -70,26 +70,23 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount
})).Items.Select(x => x.CategoryId).ToList(); })).Items.Select(x => x.CategoryId).ToList();
Product.ProductDetail = new CreateEditProductDetailViewModel Product.ProductDetail = new EditProductDetailViewModel
{ {
StoreId = storeId,
Description = detailDto.Description Description = detailDto.Description
}; };
Product.StoreId = storeId;
} }
public virtual async Task<IActionResult> OnPostAsync() public virtual async Task<IActionResult> OnPostAsync()
{ {
var product = await _service.GetAsync(Id, Product.StoreId); var product = await _service.GetAsync(Id);
var detail = await _productDetailAppService.GetAsync(product.ProductDetailId); var detail = await _productDetailAppService.GetAsync(product.ProductDetailId);
await _productDetailAppService.UpdateAsync(detail.Id, await _productDetailAppService.UpdateAsync(detail.Id,
ObjectMapper ObjectMapper
.Map<CreateEditProductDetailViewModel, CreateUpdateProductDetailDto>(Product.ProductDetail)); .Map<EditProductDetailViewModel, CreateUpdateProductDetailDto>(Product.ProductDetail));
var updateProductDto = ObjectMapper.Map<CreateEditProductViewModel, CreateUpdateProductDto>(Product); var updateProductDto = ObjectMapper.Map<EditProductViewModel, CreateUpdateProductDto>(Product);
updateProductDto.ProductDetailId = detail.Id; updateProductDto.ProductDetailId = detail.Id;

87
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/Index.cshtml

@ -22,37 +22,60 @@
<abp-style src="/Pages/EShop/Products/Products/Product/index.css"/> <abp-style src="/Pages/EShop/Products/Products/Product/index.css"/>
} }
<script> <script>
let storeId = '@Model.StoreId'; let storeId = '@Model.Filter.StoreId';
let categoryId = '@Model.CategoryId'; let categoryId = '@Model.Filter.CategoryId';
</script> </script>
<abp-card> @if (Model.Filter.StoreId == null)
<abp-card-header> {
<abp-row> <abp-dynamic-form abp-model="Filter" data-ajaxForm="true" asp-page="Index">
<abp-column size-md="_6"> <abp-card>
<abp-card-title>@L["Product"] - @Model.StoreName</abp-card-title> <abp-card-header>
</abp-column> <abp-row>
<abp-column size-md="_6" class="text-right"> <abp-column size-md="_6">
<abp-button id="NewProductButton" <abp-card-title>@L["Product"]</abp-card-title>
text="@L["CreateProduct"].Value" </abp-column>
icon="plus" </abp-row>
button-type="Primary" /> </abp-card-header>
</abp-column> <abp-card-body>
</abp-row> <abp-form-content></abp-form-content>
</abp-card-header> </abp-card-body>
<abp-card-body> <abp-modal-footer>
<abp-table striped-rows="true" id="ProductTable" class="nowrap"> <abp-button id="enter-button" button-type="Primary" text="Enter"/>
<thead> </abp-modal-footer>
<tr> </abp-card>
<th>@L["Actions"]</th> </abp-dynamic-form>
<th>@L["ProductProductGroupDisplayName"]</th> }
<th>@L["ProductUniqueName"]</th> else
<th>@L["ProductDisplayName"]</th> {
<th>@L["ProductInventoryStrategy"]</th> <abp-card>
<th>@L["ProductSold"]</th> <abp-card-header>
<th>@L["ProductIsPublished"]</th> <abp-row>
</tr> <abp-column size-md="_6">
</thead> <abp-card-title>@L["Product"] - @Model.StoreName</abp-card-title>
</abp-table> </abp-column>
</abp-card-body> <abp-column size-md="_6" class="text-right">
</abp-card> <abp-button id="NewProductButton"
text="@L["CreateProduct"].Value"
icon="plus"
button-type="Primary" />
</abp-column>
</abp-row>
</abp-card-header>
<abp-card-body>
<abp-table striped-rows="true" id="ProductTable" class="nowrap">
<thead>
<tr>
<th>@L["Actions"]</th>
<th>@L["ProductProductGroupDisplayName"]</th>
<th>@L["ProductUniqueName"]</th>
<th>@L["ProductDisplayName"]</th>
<th>@L["ProductInventoryStrategy"]</th>
<th>@L["ProductSold"]</th>
<th>@L["ProductIsPublished"]</th>
</tr>
</thead>
</abp-table>
</abp-card-body>
</abp-card>
}

28
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/Index.cshtml.cs

@ -1,10 +1,11 @@
using System;
using EasyAbp.EShop.Stores.StoreOwners; using EasyAbp.EShop.Stores.StoreOwners;
using EasyAbp.EShop.Stores.StoreOwners.Dtos; using EasyAbp.EShop.Stores.StoreOwners.Dtos;
using EasyAbp.EShop.Stores.Stores; using EasyAbp.EShop.Stores.Stores;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels;
namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
{ {
@ -14,13 +15,10 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
private readonly IStoreOwnerAppService _storeOwnerAppService; private readonly IStoreOwnerAppService _storeOwnerAppService;
[BindProperty(SupportsGet = true)] [BindProperty(SupportsGet = true)]
public Guid? StoreId { get; set; } public ProductListFilterViewModel Filter { get; set; }
[BindProperty(SupportsGet = true)]
public Guid? CategoryId { get; set; }
public string StoreName { get; set; } public string StoreName { get; set; }
public IndexModel(IStoreAppService storeAppService, public IndexModel(IStoreAppService storeAppService,
IStoreOwnerAppService storeOwnerAppService) IStoreOwnerAppService storeOwnerAppService)
{ {
@ -30,24 +28,10 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
public virtual async Task OnGetAsync() public virtual async Task OnGetAsync()
{ {
//TODO: Need to handle: when StoreId is empty, and current user owns multiple store if (Filter.StoreId.HasValue)
if (!StoreId.HasValue && CurrentUser.Id.HasValue)
{ {
var storeOwners = await _storeOwnerAppService.GetListAsync(new GetStoreOwnerListDto StoreName = (await _storeAppService.GetAsync(Filter.StoreId.Value)).Name;
{
OwnerUserId = CurrentUser.Id.Value,
});
StoreId = storeOwners.Items.FirstOrDefault()?.StoreId;
} }
if (!StoreId.HasValue)
{
var defaultStore = await _storeAppService.GetDefaultAsync();
StoreId = defaultStore.Id;
}
StoreName = (await _storeAppService.GetAsync(StoreId.Value)).Name;
} }
} }
} }

10
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/CreateEditProductDetailViewModel.cs → modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/CreateProductDetailViewModel.cs

@ -9,14 +9,10 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels
{ {
public class CreateEditProductDetailViewModel public class CreateProductDetailViewModel : EditProductDetailViewModel
{ {
[HiddenInput] [HiddenInput]
[Display(Name = "ProductStore")] [Display(Name = "ProductDetailStoreId")]
public Guid StoreId { get; set; } public Guid? StoreId { get; set; }
[TextArea(Rows = 4)]
[Display(Name = "ProductDetailDescription")]
public string Description { get; set; }
} }
} }

74
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/CreateProductViewModel.cs

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using EasyAbp.Abp.TagHelperPlus.EasySelector;
using EasyAbp.EShop.Products.Products;
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 CreateProductViewModel : IValidatableObject
{
[HiddenInput]
[Display(Name = "ProductStoreId")]
public Guid StoreId { get; set; }
[Required]
[SelectItems("ProductGroups")]
[Display(Name = "ProductProductGroupName")]
public string ProductGroupName { get; set; }
// [SelectItems("Categories")]
[EasySelector(
getListedDataSourceUrl: ProductsConsts.GetCategorySummaryListedDataSourceUrl,
getSingleDataSourceUrl: ProductsConsts.GetCategorySummarySingleDataSourceUrl,
keyPropertyName: "id",
textPropertyName: "displayName")]
[Display(Name = "ProductCategory")]
public List<Guid> CategoryIds { get; set; }
[Display(Name = "ProductUniqueName")]
public string UniqueName { get; set; }
[Required]
[Display(Name = "ProductDisplayName")]
public string DisplayName { get; set; }
public CreateProductDetailViewModel ProductDetail { get; set; }
[Required]
[Placeholder("ProductAttributeNamesPlaceholder")]
[Display(Name = "ProductAttributeNames")]
public string ProductAttributeNames { get; set; }
[Required]
[TextArea(Rows = 4)]
[Placeholder("ProductAttributeOptionNamesPlaceholder")]
[Display(Name = "ProductAttributeOptionNames")]
public string ProductAttributeOptionNames { get; set; }
[Display(Name = "ProductInventoryStrategy")]
public InventoryStrategy InventoryStrategy { get; set; }
[Display(Name = "ProductDisplayOrder")]
public int DisplayOrder { get; set; }
[Display(Name = "ProductMediaResources")]
public string MediaResources { get; set; }
[Display(Name = "ProductIsPublished")]
public bool IsPublished { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (StoreId != ProductDetail.StoreId)
{
yield return new ValidationResult(
"The StoreId should be same as the ProductDetail.StoreId.",
new[] {"StoreId"}
);
}
}
}
}

12
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/EditProductDetailViewModel.cs

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels
{
public class EditProductDetailViewModel
{
[TextArea(Rows = 4)]
[Display(Name = "ProductDetailDescription")]
public string Description { get; set; }
}
}

11
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/CreateEditProductViewModel.cs → modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/EditProductViewModel.cs

@ -1,21 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using EasyAbp.Abp.TagHelperPlus.EasySelector; using EasyAbp.Abp.TagHelperPlus.EasySelector;
using EasyAbp.EShop.Products.Products; using EasyAbp.EShop.Products.Products;
using EasyAbp.EShop.Products.Products.Dtos;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels
{ {
public class CreateEditProductViewModel public class EditProductViewModel
{ {
[HiddenInput]
[Display(Name = "ProductStore")]
public Guid StoreId { get; set; }
[Required] [Required]
[SelectItems("ProductGroups")] [SelectItems("ProductGroups")]
[Display(Name = "ProductProductGroupName")] [Display(Name = "ProductProductGroupName")]
@ -37,7 +30,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewM
[Display(Name = "ProductDisplayName")] [Display(Name = "ProductDisplayName")]
public string DisplayName { get; set; } public string DisplayName { get; set; }
public CreateEditProductDetailViewModel ProductDetail { get; set; } public EditProductDetailViewModel ProductDetail { get; set; }
[Required] [Required]
[Placeholder("ProductAttributeNamesPlaceholder")] [Placeholder("ProductAttributeNamesPlaceholder")]

28
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/ViewModels/ProductListFilterViewModel.cs

@ -0,0 +1,28 @@
using System;
using System.ComponentModel.DataAnnotations;
using EasyAbp.Abp.TagHelperPlus.EasySelector;
using EasyAbp.EShop.Stores;
namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product.ViewModels
{
public class ProductListFilterViewModel
{
[EasySelector(
getListedDataSourceUrl: StoresConsts.GetStoreListedDataSourceUrl + "?onlyManageable=true",
getSingleDataSourceUrl: StoresConsts.GetStoreSingleDataSourceUrl,
keyPropertyName: "id",
textPropertyName: "name",
runScriptOnWindowLoad: true)]
[Display(Name = "ProductStoreId")]
public Guid? StoreId { get; set; }
[EasySelector(
getListedDataSourceUrl: ProductsConsts.GetCategorySummaryListedDataSourceUrl,
getSingleDataSourceUrl: ProductsConsts.GetCategorySummarySingleDataSourceUrl,
keyPropertyName: "id",
textPropertyName: "displayName",
runScriptOnWindowLoad: true)]
[Display(Name = "ProductCategoryId")]
public Guid? CategoryId { get; set; }
}
}

14
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/index.js

@ -24,13 +24,13 @@ $(function () {
{ {
text: l('ProductSku'), text: l('ProductSku'),
action: function (data) { action: function (data) {
document.location.href = document.location.origin + '/EShop/Products/Products/ProductSku?ProductId=' + data.record.id + '&StoreId=' + storeId; document.location.href = document.location.origin + '/EShop/Products/Products/ProductSku?ProductId=' + data.record.id;
} }
}, },
{ {
text: l('Edit'), text: l('Edit'),
action: function (data) { action: function (data) {
editModal.open({ id: data.record.id, storeId: storeId }); editModal.open({ id: data.record.id });
} }
}, },
{ {
@ -39,7 +39,7 @@ $(function () {
return l('ProductDeletionConfirmationMessage', data.record.id); return l('ProductDeletionConfirmationMessage', data.record.id);
}, },
action: function (data) { action: function (data) {
service.delete(data.record.id, storeId) service.delete(data.record.id)
.then(function () { .then(function () {
abp.notify.info(l('SuccessfullyDeleted')); abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload(); dataTable.ajax.reload();
@ -70,4 +70,12 @@ $(function () {
e.preventDefault(); e.preventDefault();
createModal.open({ storeId: storeId, categoryId: categoryId }); createModal.open({ storeId: storeId, categoryId: categoryId });
}); });
$('#enter-button').click(function (e) {
e.preventDefault();
var storeId = $('#Filter_StoreId').val();
var categoryId = $('#Filter_CategoryId').val();
document.location.href = document.location.origin + document.location.pathname + '?storeId=' + storeId + "&categoryId=" + categoryId;
})
}); });

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/ChangeInventoryModal.cshtml

@ -13,7 +13,6 @@
<abp-modal-body> <abp-modal-body>
<abp-input asp-for="ProductId" /> <abp-input asp-for="ProductId" />
<abp-input asp-for="ProductSkuId" /> <abp-input asp-for="ProductSkuId" />
<abp-input asp-for="StoreId" />
<abp-form-content /> <abp-form-content />
</abp-modal-body> </abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>

5
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/ChangeInventoryModal.cshtml.cs

@ -16,10 +16,6 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
[HiddenInput] [HiddenInput]
[BindProperty(SupportsGet = true)] [BindProperty(SupportsGet = true)]
public Guid ProductSkuId { get; set; } public Guid ProductSkuId { get; set; }
[HiddenInput]
[BindProperty(SupportsGet = true)]
public Guid StoreId { get; set; }
[BindProperty] [BindProperty]
public ChangeProductInventoryViewModel ViewModel { get; set; } public ChangeProductInventoryViewModel ViewModel { get; set; }
@ -48,7 +44,6 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
{ {
ProductId = ProductId, ProductId = ProductId,
ProductSkuId = ProductSkuId, ProductSkuId = ProductSkuId,
StoreId = StoreId,
ChangedInventory = ViewModel.ProductInventoryChangeType == InventoryChangeType.IncreaseInventory ChangedInventory = ViewModel.ProductInventoryChangeType == InventoryChangeType.IncreaseInventory
? ViewModel.ChangedInventory ? ViewModel.ChangedInventory
: -ViewModel.ChangedInventory : -ViewModel.ChangedInventory

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/CreateModal.cshtml

@ -11,7 +11,6 @@
<abp-modal> <abp-modal>
<abp-modal-header title="@L["CreateProductSku"].Value"></abp-modal-header> <abp-modal-header title="@L["CreateProductSku"].Value"></abp-modal-header>
<abp-modal-body> <abp-modal-body>
<abp-input asp-for="StoreId" />
<abp-input asp-for="ProductId" /> <abp-input asp-for="ProductId" />
<abp-form-content/> <abp-form-content/>
@foreach (var attr in Model.Attributes) @foreach (var attr in Model.Attributes)

9
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/CreateModal.cshtml.cs

@ -14,10 +14,6 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
{ {
public class CreateModalModel : ProductsPageModel public class CreateModalModel : ProductsPageModel
{ {
[HiddenInput]
[BindProperty(SupportsGet = true)]
public Guid StoreId { get; set; }
[HiddenInput] [HiddenInput]
[BindProperty(SupportsGet = true)] [BindProperty(SupportsGet = true)]
public Guid ProductId { get; set; } public Guid ProductId { get; set; }
@ -43,7 +39,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
public virtual async Task OnGetAsync() public virtual async Task OnGetAsync()
{ {
var product = await _productAppService.GetAsync(ProductId, StoreId); var product = await _productAppService.GetAsync(ProductId);
Attributes = new Dictionary<string, ICollection<SelectListItem>>(); Attributes = new Dictionary<string, ICollection<SelectListItem>>();
@ -61,13 +57,12 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
createDto.AttributeOptionIds = SelectedAttributeOptionIdDict.Values.ToList(); createDto.AttributeOptionIds = SelectedAttributeOptionIdDict.Values.ToList();
var skuDto = await _productAppService.CreateSkuAsync(ProductId, StoreId, createDto); var skuDto = await _productAppService.CreateSkuAsync(ProductId, createDto);
await _productInventoryAppService.UpdateAsync(new UpdateProductInventoryDto await _productInventoryAppService.UpdateAsync(new UpdateProductInventoryDto
{ {
ProductId = ProductId, ProductId = ProductId,
ProductSkuId = skuDto.Id, ProductSkuId = skuDto.Id,
StoreId = StoreId,
ChangedInventory = ProductSku.Inventory ChangedInventory = ProductSku.Inventory
}); });

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/EditModal.cshtml

@ -11,7 +11,6 @@
<abp-modal> <abp-modal>
<abp-modal-header title="@L["EditProductSku"].Value"></abp-modal-header> <abp-modal-header title="@L["EditProductSku"].Value"></abp-modal-header>
<abp-modal-body> <abp-modal-body>
<abp-input asp-for="StoreId" />
<abp-input asp-for="ProductId" /> <abp-input asp-for="ProductId" />
<abp-input asp-for="ProductSkuId" /> <abp-input asp-for="ProductSkuId" />
<abp-form-content /> <abp-form-content />

8
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/EditModal.cshtml.cs

@ -12,10 +12,6 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
{ {
public class EditModalModel : ProductsPageModel public class EditModalModel : ProductsPageModel
{ {
[HiddenInput]
[BindProperty(SupportsGet = true)]
public Guid StoreId { get; set; }
[HiddenInput] [HiddenInput]
[BindProperty(SupportsGet = true)] [BindProperty(SupportsGet = true)]
public Guid ProductId { get; set; } public Guid ProductId { get; set; }
@ -36,7 +32,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
public virtual async Task OnGetAsync() public virtual async Task OnGetAsync()
{ {
var product = await _productAppService.GetAsync(ProductId, StoreId); var product = await _productAppService.GetAsync(ProductId);
ProductSku = ProductSku =
ObjectMapper.Map<ProductSkuDto, EditProductSkuViewModel>( ObjectMapper.Map<ProductSkuDto, EditProductSkuViewModel>(
@ -45,7 +41,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
public virtual async Task<IActionResult> OnPostAsync() public virtual async Task<IActionResult> OnPostAsync()
{ {
await _productAppService.UpdateSkuAsync(ProductId, ProductSkuId, StoreId, await _productAppService.UpdateSkuAsync(ProductId, ProductSkuId,
ObjectMapper.Map<EditProductSkuViewModel, UpdateProductSkuDto>(ProductSku)); ObjectMapper.Map<EditProductSkuViewModel, UpdateProductSkuDto>(ProductSku));
return NoContent(); return NoContent();

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/Index.cshtml

@ -25,7 +25,6 @@
<abp-style src="/Pages/EShop/Products/Products/ProductSku/index.css"/> <abp-style src="/Pages/EShop/Products/Products/ProductSku/index.css"/>
} }
<script> <script>
let storeId = '@Model.StoreId';
let productId = '@Model.ProductId'; let productId = '@Model.ProductId';
</script> </script>

5
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/Index.cshtml.cs

@ -10,9 +10,6 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
{ {
private readonly IProductAppService _productAppService; private readonly IProductAppService _productAppService;
[BindProperty(SupportsGet = true)]
public Guid StoreId { get; set; }
[BindProperty(SupportsGet = true)] [BindProperty(SupportsGet = true)]
public Guid ProductId { get; set; } public Guid ProductId { get; set; }
@ -25,7 +22,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.ProductSku
public virtual async Task OnGetAsync() public virtual async Task OnGetAsync()
{ {
ProductDisplayName = (await _productAppService.GetAsync(ProductId, StoreId)).DisplayName; ProductDisplayName = (await _productAppService.GetAsync(ProductId)).DisplayName;
} }
} }
} }

10
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/ProductSku/index.js

@ -14,7 +14,7 @@ $(function () {
order: [[1, "asc"]], order: [[1, "asc"]],
ajax: function (requestData, callback, settings) { ajax: function (requestData, callback, settings) {
if (callback) { if (callback) {
service.get(productId, storeId).then(function (result) { service.get(productId).then(function (result) {
callback({ callback({
recordsTotal: result.productSkus.length, recordsTotal: result.productSkus.length,
recordsFiltered: result.productSkus.length, recordsFiltered: result.productSkus.length,
@ -32,14 +32,14 @@ $(function () {
text: l('Edit'), text: l('Edit'),
visible: abp.auth.isGranted('EasyAbp.EShop.Products.Product.Update'), visible: abp.auth.isGranted('EasyAbp.EShop.Products.Product.Update'),
action: function (data) { action: function (data) {
editModal.open({ productId: productId, productSkuId: data.record.id, storeId: storeId }); editModal.open({ productId: productId, productSkuId: data.record.id });
} }
}, },
{ {
text: l('ProductInventory'), text: l('ProductInventory'),
visible: abp.auth.isGranted('EasyAbp.EShop.Products.ProductInventory.Update'), visible: abp.auth.isGranted('EasyAbp.EShop.Products.ProductInventory.Update'),
action: function (data) { action: function (data) {
changeInventoryModal.open({ productId: productId, productSkuId: data.record.id, storeId: storeId }); changeInventoryModal.open({ productId: productId, productSkuId: data.record.id });
} }
}, },
{ {
@ -49,7 +49,7 @@ $(function () {
return l('ProductDeletionConfirmationMessage', data.record.id); return l('ProductDeletionConfirmationMessage', data.record.id);
}, },
action: function (data) { action: function (data) {
service.deleteSku(productId, data.record.id, storeId) service.deleteSku(productId, data.record.id)
.then(function () { .then(function () {
abp.notify.info(l('SuccessfullyDeleted')); abp.notify.info(l('SuccessfullyDeleted'));
dataTable.ajax.reload(); dataTable.ajax.reload();
@ -81,7 +81,7 @@ $(function () {
$('#NewProductSkuButton').click(function (e) { $('#NewProductSkuButton').click(function (e) {
e.preventDefault(); e.preventDefault();
createModal.open({ storeId: storeId, productId: productId }); createModal.open({ productId: productId });
}); });
function fillProductSkusContentDescription(product) { function fillProductSkusContentDescription(product) {

29
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/ProductsWebAutoMapperProfile.cs

@ -19,10 +19,9 @@ namespace EasyAbp.EShop.Products.Web
/* You can configure your AutoMapper mapping configuration here. /* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations * Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */ * into multiple profile classes for a better organization. */
CreateMap<ProductDto, CreateEditProductViewModel>() CreateMap<ProductDto, EditProductViewModel>()
.Ignore(model => model.CategoryIds) .Ignore(model => model.CategoryIds)
.Ignore(model => model.ProductDetail) .Ignore(model => model.ProductDetail)
.Ignore(model => model.StoreId)
.ForSourceMember(dto => dto.Sold, opt => opt.DoNotValidate()) .ForSourceMember(dto => dto.Sold, opt => opt.DoNotValidate())
.ForSourceMember(dto => dto.ProductDetailId, opt => opt.DoNotValidate()) .ForSourceMember(dto => dto.ProductDetailId, opt => opt.DoNotValidate())
// .Ignore(x => x.ProductAttributes); // .Ignore(x => x.ProductAttributes);
@ -34,7 +33,7 @@ namespace EasyAbp.EShop.Products.Web
x.ProductAttributes x.ProductAttributes
.Select(a => a.ProductAttributeOptions.Select(o => o.DisplayName).JoinAsString(",")) .Select(a => a.ProductAttributeOptions.Select(o => o.DisplayName).JoinAsString(","))
.JoinAsString(Environment.NewLine))); .JoinAsString(Environment.NewLine)));
CreateMap<CreateEditProductViewModel, CreateUpdateProductDto>() CreateMap<CreateProductViewModel, CreateUpdateProductDto>()
.Ignore(dto => dto.ExtraProperties) .Ignore(dto => dto.ExtraProperties)
.Ignore(dto => dto.ProductDetailId) .Ignore(dto => dto.ProductDetailId)
.ForSourceMember(model => model.ProductDetail, opt => opt.DoNotValidate()) .ForSourceMember(model => model.ProductDetail, opt => opt.DoNotValidate())
@ -49,9 +48,27 @@ namespace EasyAbp.EShop.Products.Web
.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(o => .Split(",", StringSplitOptions.RemoveEmptyEntries).Select(o =>
new CreateUpdateProductAttributeOptionDto {DisplayName = o})) new CreateUpdateProductAttributeOptionDto {DisplayName = o}))
}))); })));
CreateMap<ProductDetailDto, CreateEditProductDetailViewModel>() CreateMap<EditProductViewModel, CreateUpdateProductDto>()
.Ignore(model => model.StoreId); .Ignore(dto => dto.StoreId)
CreateMap<CreateEditProductDetailViewModel, CreateUpdateProductDetailDto>() .Ignore(dto => dto.ExtraProperties)
.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) =>
new CreateUpdateProductAttributeDto
{
DisplayName = s,
ProductAttributeOptions = new List<CreateUpdateProductAttributeOptionDto>(
x.ProductAttributeOptionNames.SplitToLines(StringSplitOptions.RemoveEmptyEntries)[i]
.Split(",", StringSplitOptions.RemoveEmptyEntries).Select(o =>
new CreateUpdateProductAttributeOptionDto {DisplayName = o}))
})));
CreateMap<ProductDetailDto, CreateProductDetailViewModel>();
CreateMap<CreateProductDetailViewModel, CreateUpdateProductDetailDto>()
.Ignore(dto => dto.ExtraProperties);
CreateMap<EditProductDetailViewModel, CreateUpdateProductDetailDto>()
.Ignore(dto => dto.StoreId)
.Ignore(dto => dto.ExtraProperties); .Ignore(dto => dto.ExtraProperties);
CreateMap<ProductAttributeDto, CreateEditProductAttributeViewModel>(); CreateMap<ProductAttributeDto, CreateEditProductAttributeViewModel>();
CreateMap<CreateEditProductAttributeViewModel, CreateUpdateProductAttributeDto>() CreateMap<CreateEditProductAttributeViewModel, CreateUpdateProductAttributeDto>()

2
modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.Application.Tests/Products/ProductAppServiceTests.cs

@ -99,7 +99,7 @@ namespace EasyAbp.EShop.Products.Products
productAttributeOptionId = productAttribute.ProductAttributeOptions.First().Id; productAttributeOptionId = productAttribute.ProductAttributeOptions.First().Id;
}); });
var response = await _productAppService.CreateSkuAsync(productId, ProductsTestData.Store1Id, new CreateProductSkuDto var response = await _productAppService.CreateSkuAsync(productId, new CreateProductSkuDto
{ {
AttributeOptionIds = new List<Guid> {productAttributeOptionId}, AttributeOptionIds = new List<Guid> {productAttributeOptionId},
Currency = "CNY", Currency = "CNY",

23
modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.Domain.Tests/ProductStores/ProductStoreDomainTests.cs

@ -1,23 +0,0 @@
using System.Threading.Tasks;
using Shouldly;
using Xunit;
namespace EasyAbp.EShop.Products.ProductStores
{
public class ProductStoreDomainTests : ProductsDomainTestBase
{
public ProductStoreDomainTests()
{
}
[Fact]
public async Task Test1()
{
// Arrange
// Assert
// Assert
}
}
}

31
modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.EntityFrameworkCore.Tests/EntityFrameworkCore/ProductStores/ProductStoreRepositoryTests.cs

@ -1,31 +0,0 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.ProductStores;
using Volo.Abp.Domain.Repositories;
using Xunit;
namespace EasyAbp.EShop.Products.EntityFrameworkCore.ProductStores
{
public class ProductStoreRepositoryTests : ProductsEntityFrameworkCoreTestBase
{
private readonly IRepository<ProductStore, Guid> _productStoreRepository;
public ProductStoreRepositoryTests()
{
_productStoreRepository = GetRequiredService<IRepository<ProductStore, Guid>>();
}
[Fact]
public async Task Test1()
{
await WithUnitOfWorkAsync(async () =>
{
// Arrange
// Act
//Assert
});
}
}
}

3
modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.TestBase/ProductsTestDataBuilder.cs

@ -21,7 +21,8 @@ namespace EasyAbp.EShop.Products
public async Task BuildAsync() public async Task BuildAsync()
{ {
await _productDetailRepository.InsertAsync(new ProductDetail(ProductsTestData.ProductDetails1Id, "Product Details")); await _productDetailRepository.InsertAsync(new ProductDetail(ProductsTestData.ProductDetails1Id,
ProductsTestData.Store1Id, "Product details for store 1"));
} }
} }
} }

2
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/StoreOwners/Dtos/StoreOwnerDto.cs

@ -11,5 +11,7 @@ namespace EasyAbp.EShop.Stores.StoreOwners.Dtos
public Guid StoreId { get; set; } public Guid StoreId { get; set; }
public Guid OwnerUserId { get; set; } public Guid OwnerUserId { get; set; }
public string OwnerUserName { get; set; }
} }
} }

13
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/Stores/Dtos/GetStoreListInput.cs

@ -0,0 +1,13 @@
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Stores.Stores.Dtos
{
public class GetStoreListInput : PagedAndSortedResultRequestDto
{
/// <summary>
/// Store owner users can get stores that they owns.
/// Users who have the <code>EasyAbp.EShop.Stores.Store.CrossStore</code> permission can get all stores.
/// </summary>
public bool OnlyManageable { get; set; }
}
}

2
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/Stores/IStoreAppService.cs

@ -10,7 +10,7 @@ namespace EasyAbp.EShop.Stores.Stores
ICrudAppService< ICrudAppService<
StoreDto, StoreDto,
Guid, Guid,
PagedAndSortedResultRequestDto, GetStoreListInput,
CreateUpdateStoreDto, CreateUpdateStoreDto,
CreateUpdateStoreDto> CreateUpdateStoreDto>
{ {

1
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp.EShop.Stores.Application.csproj

@ -10,6 +10,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.Ddd.Application" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Users.Abstractions" Version="$(AbpVersion)" />
<ProjectReference Include="..\EasyAbp.EShop.Stores.Application.Contracts\EasyAbp.EShop.Stores.Application.Contracts.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Stores.Application.Contracts\EasyAbp.EShop.Stores.Application.Contracts.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Stores.Application.Shared\EasyAbp.EShop.Stores.Application.Shared.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Stores.Application.Shared\EasyAbp.EShop.Stores.Application.Shared.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Stores.Domain\EasyAbp.EShop.Stores.Domain.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Stores.Domain\EasyAbp.EShop.Stores.Domain.csproj" />

4
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/EShopStoresApplicationModule.cs

@ -2,6 +2,7 @@
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Application; using Volo.Abp.Application;
using Volo.Abp.Users;
namespace EasyAbp.EShop.Stores namespace EasyAbp.EShop.Stores
{ {
@ -10,8 +11,9 @@ namespace EasyAbp.EShop.Stores
typeof(EShopStoresApplicationSharedModule), typeof(EShopStoresApplicationSharedModule),
typeof(EShopStoresApplicationContractsModule), typeof(EShopStoresApplicationContractsModule),
typeof(AbpDddApplicationModule), typeof(AbpDddApplicationModule),
typeof(AbpUsersAbstractionModule),
typeof(AbpAutoMapperModule) typeof(AbpAutoMapperModule)
)] )]
public class EShopStoresApplicationModule : AbpModule public class EShopStoresApplicationModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)

42
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerAppService.cs

@ -4,6 +4,8 @@ using System.Threading.Tasks;
using EasyAbp.EShop.Stores.Permissions; using EasyAbp.EShop.Stores.Permissions;
using EasyAbp.EShop.Stores.StoreOwners.Dtos; using EasyAbp.EShop.Stores.StoreOwners.Dtos;
using EasyAbp.EShop.Stores.Stores; using EasyAbp.EShop.Stores.Stores;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Users;
namespace EasyAbp.EShop.Stores.StoreOwners namespace EasyAbp.EShop.Stores.StoreOwners
{ {
@ -18,10 +20,15 @@ namespace EasyAbp.EShop.Stores.StoreOwners
protected override string CrossStorePolicyName { get; set; } = StoresPermissions.Stores.CrossStore; protected override string CrossStorePolicyName { get; set; } = StoresPermissions.Stores.CrossStore;
private readonly IStoreOwnerRepository _repository; private readonly IStoreOwnerRepository _repository;
private readonly IExternalUserLookupServiceProvider _externalUserLookupServiceProvider;
public StoreOwnerAppService(IStoreOwnerRepository repository) : base(repository) public StoreOwnerAppService(
IStoreOwnerRepository repository,
IExternalUserLookupServiceProvider externalUserLookupServiceProvider)
: base(repository)
{ {
_repository = repository; _repository = repository;
_externalUserLookupServiceProvider = externalUserLookupServiceProvider;
} }
public override async Task<StoreOwnerDto> CreateAsync(CreateUpdateStoreOwnerDto input) public override async Task<StoreOwnerDto> CreateAsync(CreateUpdateStoreOwnerDto input)
@ -33,7 +40,38 @@ namespace EasyAbp.EShop.Stores.StoreOwners
return await base.CreateAsync(input); return await base.CreateAsync(input);
} }
public override async Task<StoreOwnerDto> GetAsync(Guid id)
{
var dto = await base.GetAsync(id);
var userData = await _externalUserLookupServiceProvider.FindByIdAsync(dto.OwnerUserId);
if (userData != null)
{
dto.OwnerUserName = userData.UserName;
}
return dto;
}
public override async Task<PagedResultDto<StoreOwnerDto>> GetListAsync(GetStoreOwnerListDto input)
{
var result = await base.GetListAsync(input);
foreach (var dto in result.Items)
{
var userData = await _externalUserLookupServiceProvider.FindByIdAsync(dto.OwnerUserId);
if (userData != null)
{
dto.OwnerUserName = userData.UserName;
}
}
return result;
}
protected override IQueryable<StoreOwner> CreateFilteredQuery(GetStoreOwnerListDto input) protected override IQueryable<StoreOwner> CreateFilteredQuery(GetStoreOwnerListDto input)
{ {
var queryable = Repository.AsQueryable(); var queryable = Repository.AsQueryable();

43
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/Stores/StoreAppService.cs

@ -1,15 +1,16 @@
using System; using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using EasyAbp.EShop.Stores.Permissions; using EasyAbp.EShop.Stores.Permissions;
using EasyAbp.EShop.Stores.Stores.Dtos; using EasyAbp.EShop.Stores.Stores.Dtos;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Users;
namespace EasyAbp.EShop.Stores.Stores namespace EasyAbp.EShop.Stores.Stores
{ {
public class StoreAppService : CrudAppService<Store, StoreDto, Guid, PagedAndSortedResultRequestDto, public class StoreAppService : CrudAppService<Store, StoreDto, Guid, GetStoreListInput, CreateUpdateStoreDto, CreateUpdateStoreDto>, IStoreAppService
CreateUpdateStoreDto, CreateUpdateStoreDto>,
IStoreAppService
{ {
protected override string CreatePolicyName { get; set; } = StoresPermissions.Stores.Create; protected override string CreatePolicyName { get; set; } = StoresPermissions.Stores.Create;
protected override string DeletePolicyName { get; set; } = StoresPermissions.Stores.Delete; protected override string DeletePolicyName { get; set; } = StoresPermissions.Stores.Delete;
@ -17,13 +18,47 @@ namespace EasyAbp.EShop.Stores.Stores
protected override string GetPolicyName { get; set; } = StoresPermissions.Stores.Default; protected override string GetPolicyName { get; set; } = StoresPermissions.Stores.Default;
protected override string GetListPolicyName { get; set; } = StoresPermissions.Stores.Default; protected override string GetListPolicyName { get; set; } = StoresPermissions.Stores.Default;
private readonly IPermissionChecker _permissionChecker;
private readonly IStoreRepository _repository; private readonly IStoreRepository _repository;
public StoreAppService(IStoreRepository repository) : base(repository) public StoreAppService(
IPermissionChecker permissionChecker,
IStoreRepository repository) : base(repository)
{ {
_permissionChecker = permissionChecker;
_repository = repository; _repository = repository;
} }
protected virtual async Task<IQueryable<Store>> CreateFilteredQueryAsync(GetStoreListInput input)
{
if (!input.OnlyManageable || await _permissionChecker.IsGrantedAsync(StoresPermissions.Stores.CrossStore))
{
return _repository.AsQueryable();
}
return _repository.GetQueryableOnlyOwnStore(CurrentUser.GetId());
}
public override async Task<PagedResultDto<StoreDto>> GetListAsync(GetStoreListInput input)
{
await CheckGetListPolicyAsync();
var query = await CreateFilteredQueryAsync(input);
var totalCount = await AsyncExecuter.CountAsync(query);
query = ApplySorting(query, input);
query = ApplyPaging(query, input);
var entities = await AsyncExecuter.ToListAsync(query);
var entityDtos = await MapToGetListOutputDtosAsync(entities);
return new PagedResultDto<StoreDto>(
totalCount,
entityDtos
);
}
public async Task<StoreDto> GetDefaultAsync() public async Task<StoreDto> GetDefaultAsync()
{ {
// Todo: need to be improved // Todo: need to be improved

4
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/StoresApplicationAutoMapperProfile.cs

@ -5,6 +5,7 @@ using EasyAbp.EShop.Stores.Stores;
using EasyAbp.EShop.Stores.Stores.Dtos; using EasyAbp.EShop.Stores.Stores.Dtos;
using EasyAbp.EShop.Stores.Transactions; using EasyAbp.EShop.Stores.Transactions;
using EasyAbp.EShop.Stores.Transactions.Dtos; using EasyAbp.EShop.Stores.Transactions.Dtos;
using Volo.Abp.AutoMapper;
using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectExtending;
namespace EasyAbp.EShop.Stores namespace EasyAbp.EShop.Stores
@ -19,7 +20,8 @@ namespace EasyAbp.EShop.Stores
CreateMap<Store, StoreDto>(); CreateMap<Store, StoreDto>();
CreateMap<CreateUpdateStoreDto, Store>(MemberList.Source); CreateMap<CreateUpdateStoreDto, Store>(MemberList.Source);
CreateMap<StoreOwner, StoreOwnerDto>(); CreateMap<StoreOwner, StoreOwnerDto>()
.Ignore(dto => dto.OwnerUserName);
CreateMap<CreateUpdateStoreOwnerDto, StoreOwner>(MemberList.Source); CreateMap<CreateUpdateStoreOwnerDto, StoreOwner>(MemberList.Source);
CreateMap<Transaction, TransactionDto>(); CreateMap<Transaction, TransactionDto>();

6
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain.Shared/EasyAbp/EShop/Stores/StoresConsts.cs

@ -5,5 +5,11 @@
public const string TransactionOrderCompletedActionName = "OrderCompleted"; public const string TransactionOrderCompletedActionName = "OrderCompleted";
public const string TransactionOrderRefundedActionName = "OrderRefunded"; public const string TransactionOrderRefundedActionName = "OrderRefunded";
public const string StoreRouteBase = "/api/e-shop/stores/store";
public const string GetStoreListedDataSourceUrl = StoreRouteBase;
public const string GetStoreSingleDataSourceUrl = StoreRouteBase + "/{id}";
} }
} }

3
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain/EasyAbp/EShop/Stores/Stores/IStoreRepository.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -8,5 +9,7 @@ namespace EasyAbp.EShop.Stores.Stores
public interface IStoreRepository : IRepository<Store, Guid> public interface IStoreRepository : IRepository<Store, Guid>
{ {
Task<Store> FindDefaultStoreAsync(CancellationToken cancellationToken = default); Task<Store> FindDefaultStoreAsync(CancellationToken cancellationToken = default);
IQueryable<Store> GetQueryableOnlyOwnStore(Guid userId);
} }
} }

11
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.EntityFrameworkCore/EasyAbp/EShop/Stores/Stores/StoreRepository.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using EasyAbp.EShop.Stores.EntityFrameworkCore; using EasyAbp.EShop.Stores.EntityFrameworkCore;
@ -18,5 +19,15 @@ namespace EasyAbp.EShop.Stores.Stores
{ {
return await WithDetails().FirstOrDefaultAsync(cancellationToken: cancellationToken); return await WithDetails().FirstOrDefaultAsync(cancellationToken: cancellationToken);
} }
public virtual IQueryable<Store> GetQueryableOnlyOwnStore(Guid userId)
{
return DbSet.Join(
DbContext.StoreOwners.Where(storeOwner => storeOwner.OwnerUserId == userId),
store => store.Id,
storeOwner => storeOwner.StoreId,
(store, storeOwner) => store
);
}
} }
} }

4
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.HttpApi/EasyAbp/EShop/Stores/Stores/StoreController.cs

@ -8,7 +8,7 @@ using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Stores.Stores namespace EasyAbp.EShop.Stores.Stores
{ {
[RemoteService(Name = "EasyAbpEShopStores")] [RemoteService(Name = "EasyAbpEShopStores")]
[Route("/api/e-shop/stores/store")] [Route(StoresConsts.StoreRouteBase)]
public class StoreController : StoresController, IStoreAppService public class StoreController : StoresController, IStoreAppService
{ {
private readonly IStoreAppService _service; private readonly IStoreAppService _service;
@ -26,7 +26,7 @@ namespace EasyAbp.EShop.Stores.Stores
} }
[HttpGet] [HttpGet]
public Task<PagedResultDto<StoreDto>> GetListAsync(PagedAndSortedResultRequestDto input) public Task<PagedResultDto<StoreDto>> GetListAsync(GetStoreListInput input)
{ {
return _service.GetListAsync(input); return _service.GetListAsync(input);
} }

8
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/EShopStoresWebModule.cs

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc.RazorPages; using EasyAbp.Abp.TagHelperPlus;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using EasyAbp.EShop.Stores.Localization; using EasyAbp.EShop.Stores.Localization;
using EasyAbp.EShop.Stores.Web.Menus; using EasyAbp.EShop.Stores.Web.Menus;
@ -16,8 +17,9 @@ namespace EasyAbp.EShop.Stores.Web
typeof(EShopStoresHttpApiModule), typeof(EShopStoresHttpApiModule),
typeof(AbpAspNetCoreMvcUiThemeSharedModule), typeof(AbpAspNetCoreMvcUiThemeSharedModule),
typeof(AbpAutoMapperModule), typeof(AbpAutoMapperModule),
typeof(AbpIdentityApplicationContractsModule) typeof(AbpIdentityApplicationContractsModule),
)] typeof(AbpTagHelperPlusModule)
)]
public class EShopStoresWebModule : AbpModule public class EShopStoresWebModule : AbpModule
{ {
public override void PreConfigureServices(ServiceConfigurationContext context) public override void PreConfigureServices(ServiceConfigurationContext context)

1
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/EasyAbp.EShop.Stores.Web.csproj

@ -12,6 +12,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="EasyAbp.Abp.TagHelperPlus" Version="0.6.0" />
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.Identity.Application.Contracts" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.Identity.Application.Contracts" Version="$(AbpVersion)" />

12
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/Pages/EShop/Stores/StoreOwners/StoreOwner/Index.js

@ -4,7 +4,6 @@ $(function () {
var service = easyAbp.eShop.stores.storeOwners.storeOwner; var service = easyAbp.eShop.stores.storeOwners.storeOwner;
var storeService = easyAbp.eShop.stores.stores.store; var storeService = easyAbp.eShop.stores.stores.store;
var userService = volo.abp.identity.identityUser;
var createModal = new abp.ModalManager(abp.appPath + 'EShop/Stores/StoreOwners/StoreOwner/CreateModal'); var createModal = new abp.ModalManager(abp.appPath + 'EShop/Stores/StoreOwners/StoreOwner/CreateModal');
var editModal = new abp.ModalManager(abp.appPath + 'EShop/Stores/StoreOwners/StoreOwner/EditModal'); var editModal = new abp.ModalManager(abp.appPath + 'EShop/Stores/StoreOwners/StoreOwner/EditModal');
@ -58,16 +57,7 @@ $(function () {
} }
}, },
{ {
data: "ownerUserId", data: "ownerUserName"
render: function (data, type, row, meta) {
var currentCell = $("#StoreOwnerTable").DataTable().cells({"row":meta.row, "column":meta.col}).nodes(0);
userService.get(data).then(
x=>{
$(currentCell).html(x.userName);
}
);
return '...';
}
} }
] ]
})); }));

17
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/Pages/EShop/Stores/StoreOwners/StoreOwner/ViewModels/CreateStoreOwnerViewModel.cs

@ -1,5 +1,6 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using EasyAbp.Abp.TagHelperPlus.EasySelector;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectExtending;
@ -7,11 +8,21 @@ namespace EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner.Vie
{ {
public class CreateEditStoreOwnerViewModel public class CreateEditStoreOwnerViewModel
{ {
[Required] [EasySelector(
getListedDataSourceUrl: StoresConsts.GetStoreListedDataSourceUrl + "?onlyManageable=true",
getSingleDataSourceUrl: StoresConsts.GetStoreSingleDataSourceUrl,
keyPropertyName: "id",
textPropertyName: "name")]
[Display(Name = "StoreOwnerStoreId")]
public Guid StoreId { get; set; } public Guid StoreId { get; set; }
[EasySelector(
[Required] getListedDataSourceUrl: "/api/identity/users",
getSingleDataSourceUrl: "/api/identity/users/{id}",
keyPropertyName: "id",
textPropertyName: "name",
alternativeTextPropertyName: "userName")]
[Display(Name = "StoreOwnerOwnerUserId")]
public Guid OwnerUserId { get; set; } public Guid OwnerUserId { get; set; }
} }
} }

2
plugins/Baskets/src/EasyAbp.EShop.Plugins.Baskets.Application.Contracts/EasyAbp/EShop/Plugins/Baskets/BasketItems/Dtos/CreateBasketItemDto.cs

@ -16,8 +16,6 @@ namespace EasyAbp.EShop.Plugins.Baskets.BasketItems.Dtos
/// </summary> /// </summary>
public Guid? UserId { get; set; } public Guid? UserId { get; set; }
public Guid StoreId { get; set; }
public Guid ProductId { get; set; } public Guid ProductId { get; set; }
public Guid ProductSkuId { get; set; } public Guid ProductSkuId { get; set; }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save