build: 升级目标框架到net10.0并完善模板配置
1. 将Hua.Cli.Tests、项目共享库、模块项目等所有项目的TargetFramework从net8.0/net9.0升级到net10.0 2. 完善dotnet-tools.json、模板配置文件,添加必要的构建和发布配置 3. 新增微服务、网关、应用程序的启动脚本和基础配置文件 4. 补充产品管理模块的领域、应用、Web层基础代码和多语言资源
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class CreateProductDto
|
||||
{
|
||||
[Required]
|
||||
[StringLength(ProductConsts.MaxCodeLength)]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[StringLength(ProductConsts.MaxNameLength)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(ProductConsts.MaxImageNameLength)]
|
||||
public string? ImageName { get; set; }
|
||||
|
||||
public float Price { get; set; }
|
||||
|
||||
public int StockCount { get; set; }
|
||||
}
|
||||
+12
-8
@@ -1,17 +1,21 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public interface IProductAppService :
|
||||
ICrudAppService<ProductDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateProductDto>
|
||||
public interface IProductAppService : IApplicationService
|
||||
{
|
||||
}
|
||||
Task<PagedResultDto<ProductDto>> GetListPagedAsync(PagedAndSortedResultRequestDto input);
|
||||
|
||||
public class CreateUpdateProductDto
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public decimal Price { get; set; }
|
||||
public int StockCount { get; set; }
|
||||
Task<ListResultDto<ProductDto>> GetListAsync();
|
||||
|
||||
Task<ProductDto> GetAsync(Guid id);
|
||||
|
||||
Task<ProductDto> CreateAsync(CreateProductDto input);
|
||||
|
||||
Task<ProductDto> UpdateAsync(Guid id, UpdateProductDto input);
|
||||
|
||||
Task DeleteAsync(Guid id);
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public interface IPublicProductAppService : IApplicationService
|
||||
{
|
||||
Task<ListResultDto<ProductDto>> GetListAsync();
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"culture": "cs",
|
||||
"texts": {
|
||||
"Permission:ProductManagement": "Správa produktů",
|
||||
"Permission:Products": "Produkty",
|
||||
"Permission:Edit": "Upravit",
|
||||
"Permission:Delete": "Smazat",
|
||||
"Permission:Create": "Vytvořit"
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"culture": "en",
|
||||
"texts": {
|
||||
"Permission:ProductManagement": "Product Management",
|
||||
"Permission:Products": "Products",
|
||||
"Permission:Edit": "Edit",
|
||||
"Permission:Delete": "Delete",
|
||||
"Permission:Create": "Create"
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"culture": "pl-PL",
|
||||
"texts": {
|
||||
"Permission:ProductManagement": "Zarządzanie produktami",
|
||||
"Permission:Products": "Produkty",
|
||||
"Permission:Edit": "Edytuj",
|
||||
"Permission:Delete": "Usuń",
|
||||
"Permission:Create": "Utwórz"
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"culture": "tr",
|
||||
"texts": {
|
||||
"Permission:ProductManagement": "Ürün Yönetimi",
|
||||
"Permission:Products": "Ürünler",
|
||||
"Permission:Edit": "Güncelle",
|
||||
"Permission:Delete": "Sil",
|
||||
"Permission:Create": "Oluştur"
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"culture": "vi",
|
||||
"texts": {
|
||||
"Permission:ProductManagement": "Quản lý sản phẩm",
|
||||
"Permission:Products": "Sản phẩm",
|
||||
"Permission:Edit": "Sửa",
|
||||
"Permission:Delete": "Xóa",
|
||||
"Permission:Create": "Tạo"
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -3,9 +3,11 @@ using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductDto : FullAuditedEntityDto<Guid>
|
||||
public class ProductDto : AuditedEntityDto<Guid>
|
||||
{
|
||||
public string Code { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public decimal Price { get; set; }
|
||||
public string? ImageName { get; set; }
|
||||
public float Price { get; set; }
|
||||
public int StockCount { get; set; }
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup><TargetFramework>netstandard2.0</TargetFramework></PropertyGroup>
|
||||
<PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.Ddd.Application" Version="9.0.0" />
|
||||
<ProjectReference Include="..\ProductManagement.Domain.Shared\ProductManagement.Domain.Shared.csproj" />
|
||||
|
||||
+5
-1
@@ -1,6 +1,10 @@
|
||||
using Volo.Abp.Application;
|
||||
using Volo.Abp.Modularity;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
[DependsOn(typeof(ProductManagementDomainSharedModule))]
|
||||
[DependsOn(
|
||||
typeof(ProductManagementDomainSharedModule),
|
||||
typeof(AbpDddApplicationContractsModule)
|
||||
)]
|
||||
public class ProductManagementApplicationContractsModule : AbpModule { }
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using ProductManagement.Localization;
|
||||
using Volo.Abp.Authorization.Permissions;
|
||||
using Volo.Abp.Localization;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductManagementPermissionDefinitionProvider : PermissionDefinitionProvider
|
||||
{
|
||||
public override void Define(IPermissionDefinitionContext context)
|
||||
{
|
||||
var productManagementGroup = context.AddGroup(ProductManagementPermissions.GroupName, L("Permission:ProductManagement"));
|
||||
|
||||
var products = productManagementGroup.AddPermission(ProductManagementPermissions.Products.Default, L("Permission:Products"));
|
||||
products.AddChild(ProductManagementPermissions.Products.Update, L("Permission:Edit"));
|
||||
products.AddChild(ProductManagementPermissions.Products.Delete, L("Permission:Delete"));
|
||||
products.AddChild(ProductManagementPermissions.Products.Create, L("Permission:Create"));
|
||||
}
|
||||
|
||||
private static LocalizableString L(string name)
|
||||
{
|
||||
return LocalizableString.Create<ProductManagementResource>(name);
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
using Volo.Abp.Reflection;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductManagementPermissions
|
||||
{
|
||||
public const string GroupName = "ProductManagement";
|
||||
|
||||
public static class Products
|
||||
{
|
||||
public const string Default = GroupName + ".Product";
|
||||
public const string Delete = Default + ".Delete";
|
||||
public const string Update = Default + ".Update";
|
||||
public const string Create = Default + ".Create";
|
||||
}
|
||||
|
||||
public static string[] GetAll()
|
||||
{
|
||||
return ReflectionHelper.GetPublicConstantsRecursively(typeof(ProductManagementPermissions));
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using Volo.Abp.Settings;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductManagementSettingDefinitionProvider : SettingDefinitionProvider
|
||||
{
|
||||
public override void Define(ISettingDefinitionContext context)
|
||||
{
|
||||
context.Add(
|
||||
new SettingDefinition(
|
||||
ProductManagementSettings.MaxPageSize,
|
||||
"100",
|
||||
isVisibleToClients: true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
namespace ProductManagement;
|
||||
|
||||
public static class ProductManagementSettings
|
||||
{
|
||||
public const string GroupName = "ProductManagement";
|
||||
|
||||
/// <summary>
|
||||
/// Maximum allowed page size for paged list requests.
|
||||
/// </summary>
|
||||
public const string MaxPageSize = GroupName + ".MaxPageSize";
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class UpdateProductDto
|
||||
{
|
||||
[Required]
|
||||
[StringLength(ProductConsts.MaxNameLength)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(ProductConsts.MaxImageNameLength)]
|
||||
public string? ImageName { get; set; }
|
||||
|
||||
public float Price { get; set; }
|
||||
|
||||
public int StockCount { get; set; }
|
||||
}
|
||||
+88
-5
@@ -1,14 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductAppService :
|
||||
CrudAppService<Product, ProductDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateProductDto>,
|
||||
IProductAppService
|
||||
[Authorize(ProductManagementPermissions.Products.Default)]
|
||||
public class ProductAppService : ApplicationService, IProductAppService
|
||||
{
|
||||
public ProductAppService(IRepository<Product, Guid> repository)
|
||||
: base(repository) { }
|
||||
private readonly ProductManager _productManager;
|
||||
private readonly IRepository<Product, Guid> _productRepository;
|
||||
|
||||
public ProductAppService(ProductManager productManager, IRepository<Product, Guid> productRepository)
|
||||
{
|
||||
_productManager = productManager;
|
||||
_productRepository = productRepository;
|
||||
}
|
||||
|
||||
public async Task<PagedResultDto<ProductDto>> GetListPagedAsync(PagedAndSortedResultRequestDto input)
|
||||
{
|
||||
await NormalizeMaxResultCountAsync(input);
|
||||
|
||||
var queryable = await _productRepository.GetQueryableAsync();
|
||||
var products = await queryable
|
||||
.OrderBy(input.Sorting ?? "Name")
|
||||
.Skip(input.SkipCount)
|
||||
.Take(input.MaxResultCount)
|
||||
.ToListAsync();
|
||||
|
||||
var totalCount = await _productRepository.GetCountAsync();
|
||||
var dtos = ObjectMapper.Map<List<Product>, List<ProductDto>>(products);
|
||||
|
||||
return new PagedResultDto<ProductDto>(totalCount, dtos);
|
||||
}
|
||||
|
||||
public async Task<ListResultDto<ProductDto>> GetListAsync()
|
||||
{
|
||||
var products = await _productRepository.GetListAsync();
|
||||
var productList = ObjectMapper.Map<List<Product>, List<ProductDto>>(products);
|
||||
return new ListResultDto<ProductDto>(productList);
|
||||
}
|
||||
|
||||
public async Task<ProductDto> GetAsync(Guid id)
|
||||
{
|
||||
var product = await _productRepository.GetAsync(id);
|
||||
return ObjectMapper.Map<Product, ProductDto>(product);
|
||||
}
|
||||
|
||||
[Authorize(ProductManagementPermissions.Products.Create)]
|
||||
public async Task<ProductDto> CreateAsync(CreateProductDto input)
|
||||
{
|
||||
var product = await _productManager.CreateAsync(
|
||||
input.Code,
|
||||
input.Name,
|
||||
input.Price,
|
||||
input.StockCount,
|
||||
input.ImageName
|
||||
);
|
||||
|
||||
return ObjectMapper.Map<Product, ProductDto>(product);
|
||||
}
|
||||
|
||||
[Authorize(ProductManagementPermissions.Products.Update)]
|
||||
public async Task<ProductDto> UpdateAsync(Guid id, UpdateProductDto input)
|
||||
{
|
||||
var product = await _productRepository.GetAsync(id);
|
||||
|
||||
product.SetName(input.Name);
|
||||
product.SetPrice(input.Price);
|
||||
product.SetStockCount(input.StockCount);
|
||||
product.SetImageName(input.ImageName);
|
||||
|
||||
return ObjectMapper.Map<Product, ProductDto>(product);
|
||||
}
|
||||
|
||||
[Authorize(ProductManagementPermissions.Products.Delete)]
|
||||
public async Task DeleteAsync(Guid id)
|
||||
{
|
||||
await _productRepository.DeleteAsync(id);
|
||||
}
|
||||
|
||||
private async Task NormalizeMaxResultCountAsync(PagedAndSortedResultRequestDto input)
|
||||
{
|
||||
var maxPageSize = (await SettingProvider.GetOrNullAsync(ProductManagementSettings.MaxPageSize))?.To<int>();
|
||||
if (maxPageSize.HasValue && input.MaxResultCount > maxPageSize.Value)
|
||||
{
|
||||
input.MaxResultCount = maxPageSize.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup>
|
||||
<PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.AutoMapper" Version="9.0.0" />
|
||||
<ProjectReference Include="..\ProductManagement.Application.Contracts\ProductManagement.Application.Contracts.csproj" />
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using AutoMapper;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductManagementApplicationAutoMapperProfile : Profile
|
||||
{
|
||||
public ProductManagementApplicationAutoMapperProfile()
|
||||
{
|
||||
CreateMap<Product, ProductDto>();
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class PublicProductAppService : ApplicationService, IPublicProductAppService
|
||||
{
|
||||
private readonly IRepository<Product, Guid> _productRepository;
|
||||
|
||||
public PublicProductAppService(IRepository<Product, Guid> productRepository)
|
||||
{
|
||||
_productRepository = productRepository;
|
||||
}
|
||||
|
||||
public async Task<ListResultDto<ProductDto>> GetListAsync()
|
||||
{
|
||||
return new ListResultDto<ProductDto>(
|
||||
ObjectMapper.Map<List<Product>, List<ProductDto>>(
|
||||
await _productRepository.GetListAsync()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
using Volo.Abp.Localization;
|
||||
|
||||
namespace ProductManagement.Localization;
|
||||
|
||||
[LocalizationResourceName("ProductManagement")]
|
||||
public class ProductManagementResource
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace ProductManagement;
|
||||
|
||||
public static class ProductConsts
|
||||
{
|
||||
public const int MaxCodeLength = 32;
|
||||
public const int MaxNameLength = 256;
|
||||
public const int MaxImageNameLength = 128;
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup><TargetFramework>netstandard2.0</TargetFramework></PropertyGroup>
|
||||
<PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.Localization" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
namespace ProductManagement;
|
||||
|
||||
public static class ProductManagementDomainErrorCodes
|
||||
{
|
||||
//Add your business exception error codes here...
|
||||
}
|
||||
+12
-2
@@ -1,7 +1,17 @@
|
||||
using Volo.Abp.Modularity;
|
||||
using ProductManagement.Localization;
|
||||
using Volo.Abp.Localization;
|
||||
using Volo.Abp.Modularity;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
[DependsOn(typeof(AbpLocalizationModule))]
|
||||
public class ProductManagementDomainSharedModule : AbpModule { }
|
||||
public class ProductManagementDomainSharedModule : AbpModule
|
||||
{
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
Configure<AbpLocalizationOptions>(options =>
|
||||
{
|
||||
options.Resources.Add<ProductManagementResource>("en");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using Volo.Abp.Domain.Entities.Events.Distributed;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
[Serializable]
|
||||
public class ProductStockCountChangedEto : EtoBase
|
||||
{
|
||||
public Guid Id { get; }
|
||||
|
||||
public int OldCount { get; set; }
|
||||
|
||||
public int CurrentCount { get; set; }
|
||||
|
||||
private ProductStockCountChangedEto()
|
||||
{
|
||||
}
|
||||
|
||||
public ProductStockCountChangedEto(Guid id, int oldCount, int currentCount)
|
||||
{
|
||||
Id = id;
|
||||
OldCount = oldCount;
|
||||
CurrentCount = currentCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"culture": "cs",
|
||||
"texts": {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"culture": "en",
|
||||
"texts": {
|
||||
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"culture": "pl-PL",
|
||||
"texts": {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"culture":"vi","texts":{}}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"culture": "vi",
|
||||
"texts": {
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,120 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Volo.Abp;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class Product : FullAuditedAggregateRoot<Guid>
|
||||
public class Product : AuditedAggregateRoot<Guid>
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public decimal Price { get; set; }
|
||||
public int StockCount { get; set; }
|
||||
[NotNull]
|
||||
public string Code { get; private set; }
|
||||
|
||||
[NotNull]
|
||||
public string Name { get; private set; }
|
||||
|
||||
public float Price { get; private set; }
|
||||
|
||||
public int StockCount { get; private set; }
|
||||
|
||||
public string? ImageName { get; private set; }
|
||||
|
||||
private Product()
|
||||
{
|
||||
}
|
||||
|
||||
internal Product(
|
||||
Guid id,
|
||||
[NotNull] string code,
|
||||
[NotNull] string name,
|
||||
float price = 0.0f,
|
||||
int stockCount = 0,
|
||||
string? imageName = null)
|
||||
{
|
||||
Check.NotNullOrWhiteSpace(code, nameof(code));
|
||||
|
||||
if (code.Length >= ProductConsts.MaxCodeLength)
|
||||
{
|
||||
throw new ArgumentException($"Product code can not be longer than {ProductConsts.MaxCodeLength}");
|
||||
}
|
||||
|
||||
Id = id;
|
||||
Code = code;
|
||||
SetName(Check.NotNullOrWhiteSpace(name, nameof(name)));
|
||||
SetPrice(price);
|
||||
SetImageName(imageName);
|
||||
SetStockCountInternal(stockCount, triggerEvent: false);
|
||||
}
|
||||
|
||||
public Product SetName([NotNull] string name)
|
||||
{
|
||||
Check.NotNullOrWhiteSpace(name, nameof(name));
|
||||
|
||||
if (name.Length >= ProductConsts.MaxNameLength)
|
||||
{
|
||||
throw new ArgumentException($"Product name can not be longer than {ProductConsts.MaxNameLength}");
|
||||
}
|
||||
|
||||
Name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Product SetImageName([CanBeNull] string? imageName)
|
||||
{
|
||||
if (imageName == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
if (imageName.Length >= ProductConsts.MaxImageNameLength)
|
||||
{
|
||||
throw new ArgumentException($"Product image name can not be longer than {ProductConsts.MaxImageNameLength}");
|
||||
}
|
||||
|
||||
ImageName = imageName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Product SetPrice(float price)
|
||||
{
|
||||
if (price < 0.0f)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(price)} can not be less than 0.0!");
|
||||
}
|
||||
|
||||
Price = price;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Product SetStockCount(int stockCount)
|
||||
{
|
||||
return SetStockCountInternal(stockCount);
|
||||
}
|
||||
|
||||
private Product SetStockCountInternal(int stockCount, bool triggerEvent = true)
|
||||
{
|
||||
if (StockCount < 0)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(stockCount)} can not be less than 0!");
|
||||
}
|
||||
|
||||
if (StockCount == stockCount)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
if (triggerEvent)
|
||||
{
|
||||
AddDistributedEvent(
|
||||
new ProductStockCountChangedEto(
|
||||
Id,
|
||||
StockCount,
|
||||
stockCount
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
StockCount = stockCount;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using Volo.Abp;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductCodeAlreadyExistsException : BusinessException
|
||||
{
|
||||
public ProductCodeAlreadyExistsException(string productCode)
|
||||
: base("PM:000001", $"A product with code {productCode} has already exists!")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup>
|
||||
<PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.EntityFrameworkCore" Version="9.0.0" />
|
||||
<ProjectReference Include="..\ProductManagement.Domain.Shared\ProductManagement.Domain.Shared.csproj" />
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace ProductManagement;
|
||||
|
||||
public static class ProductManagementConsts
|
||||
{
|
||||
public const string DefaultDbTablePrefix = "Pm";
|
||||
|
||||
public const string? DefaultDbSchema = null;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using Volo.Abp.Domain.Services;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductManager : DomainService
|
||||
{
|
||||
private readonly IRepository<Product, Guid> _productRepository;
|
||||
|
||||
public ProductManager(IRepository<Product, Guid> productRepository)
|
||||
{
|
||||
_productRepository = productRepository;
|
||||
}
|
||||
|
||||
public async Task<Product> CreateAsync(
|
||||
[NotNull] string code,
|
||||
[NotNull] string name,
|
||||
float price = 0.0f,
|
||||
int stockCount = 0,
|
||||
string? imageName = null)
|
||||
{
|
||||
var existingProduct = await _productRepository.FirstOrDefaultAsync(p => p.Code == code);
|
||||
if (existingProduct != null)
|
||||
{
|
||||
throw new ProductCodeAlreadyExistsException(code);
|
||||
}
|
||||
|
||||
return await _productRepository.InsertAsync(
|
||||
new Product(
|
||||
GuidGenerator.Create(),
|
||||
code,
|
||||
name,
|
||||
price,
|
||||
stockCount,
|
||||
imageName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Volo.Abp.Data;
|
||||
using Volo.Abp.EntityFrameworkCore;
|
||||
|
||||
namespace ProductManagement.EntityFrameworkCore;
|
||||
|
||||
[ConnectionStringName("ProductManagement")]
|
||||
public interface IProductManagementDbContext : IEfCoreDbContext
|
||||
{
|
||||
DbSet<Product> Products { get; }
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup>
|
||||
<PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.EntityFrameworkCore.SqlServer" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
|
||||
|
||||
+3
-6
@@ -1,9 +1,10 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ProductManagement.EntityFrameworkCore;
|
||||
using Volo.Abp.EntityFrameworkCore;
|
||||
|
||||
namespace ProductManagement.EntityFrameworkCore;
|
||||
|
||||
public class ProductManagementDbContext : AbpDbContext<ProductManagementDbContext>
|
||||
public class ProductManagementDbContext : AbpDbContext<ProductManagementDbContext>, IProductManagementDbContext
|
||||
{
|
||||
public DbSet<Product> Products { get; set; }
|
||||
|
||||
@@ -13,10 +14,6 @@ public class ProductManagementDbContext : AbpDbContext<ProductManagementDbContex
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
builder.Entity<Product>(b =>
|
||||
{
|
||||
b.ToTable("PmProducts");
|
||||
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
|
||||
});
|
||||
builder.ConfigureProductManagement();
|
||||
}
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Volo.Abp;
|
||||
using Volo.Abp.EntityFrameworkCore.Modeling;
|
||||
|
||||
namespace ProductManagement.EntityFrameworkCore;
|
||||
|
||||
public static class ProductManagementDbContextModelCreatingExtensions
|
||||
{
|
||||
public static void ConfigureProductManagement(
|
||||
this ModelBuilder builder,
|
||||
Action<ProductManagementModelBuilderConfigurationOptions>? optionsAction = null)
|
||||
{
|
||||
Check.NotNull(builder, nameof(builder));
|
||||
|
||||
var options = new ProductManagementModelBuilderConfigurationOptions();
|
||||
|
||||
optionsAction?.Invoke(options);
|
||||
|
||||
builder.Entity<Product>(b =>
|
||||
{
|
||||
b.ToTable(options.TablePrefix + "Products", options.Schema);
|
||||
|
||||
b.ConfigureConcurrencyStamp();
|
||||
b.ConfigureExtraProperties();
|
||||
b.ConfigureAudited();
|
||||
|
||||
b.Property(x => x.Code).IsRequired().HasMaxLength(ProductConsts.MaxCodeLength);
|
||||
b.Property(x => x.Name).IsRequired().HasMaxLength(ProductConsts.MaxNameLength);
|
||||
b.Property(x => x.ImageName).HasMaxLength(ProductConsts.MaxImageNameLength);
|
||||
|
||||
b.HasIndex(q => q.Code);
|
||||
b.HasIndex(q => q.Name);
|
||||
});
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using JetBrains.Annotations;
|
||||
using Volo.Abp.EntityFrameworkCore.Modeling;
|
||||
|
||||
namespace ProductManagement.EntityFrameworkCore;
|
||||
|
||||
public class ProductManagementModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions
|
||||
{
|
||||
public ProductManagementModelBuilderConfigurationOptions(
|
||||
[NotNull] string tablePrefix = ProductManagementConsts.DefaultDbTablePrefix,
|
||||
[CanBeNull] string? schema = ProductManagementConsts.DefaultDbSchema)
|
||||
: base(tablePrefix, schema)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup>
|
||||
<PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.Http.Client" Version="9.0.0" />
|
||||
<ProjectReference Include="..\ProductManagement.Application.Contracts\ProductManagement.Application.Contracts.csproj" />
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup>
|
||||
<PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="9.0.0" />
|
||||
<ProjectReference Include="..\ProductManagement.Application.Contracts\ProductManagement.Application.Contracts.csproj" />
|
||||
|
||||
+5
-1
@@ -1,6 +1,10 @@
|
||||
using Volo.Abp.AspNetCore.Mvc;
|
||||
using Volo.Abp.Modularity;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
[DependsOn(typeof(ProductManagementApplicationContractsModule))]
|
||||
[DependsOn(
|
||||
typeof(ProductManagementApplicationContractsModule),
|
||||
typeof(AbpAspNetCoreMvcModule)
|
||||
)]
|
||||
public class ProductManagementHttpApiModule : AbpModule { }
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.AspNetCore.Mvc;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
[RemoteService]
|
||||
[Area("productManagement")]
|
||||
[Route("api/productManagement/products")]
|
||||
public class ProductsController : AbpController, IProductAppService
|
||||
{
|
||||
private readonly IProductAppService _productAppService;
|
||||
|
||||
public ProductsController(IProductAppService productAppService)
|
||||
{
|
||||
_productAppService = productAppService;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("")]
|
||||
public Task<PagedResultDto<ProductDto>> GetListPagedAsync(PagedAndSortedResultRequestDto input)
|
||||
{
|
||||
return _productAppService.GetListPagedAsync(input);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("all")]
|
||||
public Task<ListResultDto<ProductDto>> GetListAsync()
|
||||
{
|
||||
return _productAppService.GetListAsync();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("{id}")]
|
||||
public Task<ProductDto> GetAsync(Guid id)
|
||||
{
|
||||
return _productAppService.GetAsync(id);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public Task<ProductDto> CreateAsync(CreateProductDto input)
|
||||
{
|
||||
return _productAppService.CreateAsync(input);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
[Route("{id}")]
|
||||
public Task<ProductDto> UpdateAsync(Guid id, UpdateProductDto input)
|
||||
{
|
||||
return _productAppService.UpdateAsync(id, input);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Route("{id}")]
|
||||
public Task DeleteAsync(Guid id)
|
||||
{
|
||||
return _productAppService.DeleteAsync(id);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.AspNetCore.Mvc;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
[RemoteService]
|
||||
[Area("productManagement")]
|
||||
[Route("api/productManagement/public/products")]
|
||||
public class PublicProductsController : AbpController, IPublicProductAppService
|
||||
{
|
||||
private readonly IPublicProductAppService _publicProductAppService;
|
||||
|
||||
public PublicProductsController(IPublicProductAppService publicProductAppService)
|
||||
{
|
||||
_publicProductAppService = publicProductAppService;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public Task<ListResultDto<ProductDto>> GetListAsync()
|
||||
{
|
||||
return _publicProductAppService.GetListAsync();
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"culture": "cs",
|
||||
"texts": {
|
||||
"Menu:ProductManagement": "Správa produktů",
|
||||
"Menu:Products": "Produkty",
|
||||
"ProductManagement": "Správa produktů",
|
||||
"CreateANewProduct": "Vytvořit nový produkt",
|
||||
"Products": "Produkty",
|
||||
"StockCount": "Skladem",
|
||||
"Code": "Kód",
|
||||
"Name": "Název",
|
||||
"Price": "Cena",
|
||||
"ImageName": "Název obrázku",
|
||||
"ProductDeletionWarningMessage": "Opravdu chcete smazat tento produkt?"
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"culture": "en",
|
||||
"texts": {
|
||||
"Menu:ProductManagement": "Product Management",
|
||||
"Menu:Products": "Products",
|
||||
"ProductManagement": "Product Management",
|
||||
"CreateANewProduct": "Create A New Product",
|
||||
"Products": "Products",
|
||||
"StockCount": "Stock Count",
|
||||
"Code": "Code",
|
||||
"Name": "Name",
|
||||
"Price": "Price",
|
||||
"ImageName": "Image Name",
|
||||
"ProductDeletionWarningMessage": "Are you sure you want to delete this product?"
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"culture": "pl-PL",
|
||||
"texts": {
|
||||
"Menu:ProductManagement": "Zarządzanie produktami",
|
||||
"Menu:Products": "Produkty",
|
||||
"ProductManagement": "Zarządzanie produktami",
|
||||
"CreateANewProduct": "Utwórz nowy produkt",
|
||||
"Products": "Produkty",
|
||||
"StockCount": "Ilość na magazynie",
|
||||
"Code": "Kod",
|
||||
"Name": "Nazwa",
|
||||
"Price": "Cena",
|
||||
"ImageName": "Nazwa obrazka",
|
||||
"ProductDeletionWarningMessage": "Czy jesteś pewien, że chcesz usunąć ten produkt?"
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"culture": "tr",
|
||||
"texts": {
|
||||
"Menu:ProductManagement": "Ürün Yönetimi",
|
||||
"Menu:Products": "Ürünler",
|
||||
"ProductManagement": "Ürün Yönetimi",
|
||||
"CreateANewProduct": "Yeni Bir Ürün Oluştur",
|
||||
"Products": "Ürünler",
|
||||
"StockCount": "Stok Sayısı",
|
||||
"Code": "Kod",
|
||||
"Name": "İsim",
|
||||
"Price": "Fiyat",
|
||||
"ImageName": "Fotoğraf İsmi",
|
||||
"ProductDeletionWarningMessage": "Bu ürünü silmek istediğinize emin misiniz?"
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"culture": "vi",
|
||||
"texts": {
|
||||
"Menu:ProductManagement": "Quản lý sản phẩm",
|
||||
"Menu:Products": "Sản phẩm",
|
||||
"ProductManagement": "Quản lý sản phẩm",
|
||||
"CreateANewProduct": "Tạo một sản phẩm mới",
|
||||
"Products": "Sản phẩm",
|
||||
"StockCount": "Số chứng khoán",
|
||||
"Code": "Mã",
|
||||
"Name": "Tên",
|
||||
"Price": "Giá",
|
||||
"ImageName": "Tên ảnh",
|
||||
"ProductDeletionWarningMessage": "Bạn có chắc chắn muốn xóa sản phẩm này?"
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
@page
|
||||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
|
||||
@using Microsoft.AspNetCore.Mvc.Localization
|
||||
@using ProductManagement.Localization
|
||||
@model ProductManagement.Pages.ProductManagement.Products.CreateModel
|
||||
@inject IHtmlLocalizer<ProductManagementResource> L
|
||||
@{
|
||||
Layout = null;
|
||||
}
|
||||
|
||||
<abp-dynamic-form submit-button="false" abp-model="Product" asp-page="/ProductManagement/Products/Create">
|
||||
<abp-modal size="@(AbpModalSize.Large)">
|
||||
<abp-modal-header title="@L["Create"].Value"></abp-modal-header>
|
||||
<abp-modal-body>
|
||||
<abp-form-content />
|
||||
</abp-modal-body>
|
||||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)">
|
||||
</abp-modal-footer>
|
||||
</abp-modal>
|
||||
</abp-dynamic-form>
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
|
||||
|
||||
namespace ProductManagement.Pages.ProductManagement.Products;
|
||||
|
||||
public class CreateModel : AbpPageModel
|
||||
{
|
||||
private readonly IProductAppService _productAppService;
|
||||
|
||||
[BindProperty]
|
||||
public ProductCreateViewModel Product { get; set; } = new ProductCreateViewModel();
|
||||
|
||||
public CreateModel(IProductAppService productAppService)
|
||||
{
|
||||
_productAppService = productAppService;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync()
|
||||
{
|
||||
var createProductDto = ObjectMapper.Map<ProductCreateViewModel, CreateProductDto>(Product);
|
||||
|
||||
await _productAppService.CreateAsync(createProductDto);
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
public class ProductCreateViewModel
|
||||
{
|
||||
[Required]
|
||||
[StringLength(ProductConsts.MaxCodeLength)]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[StringLength(ProductConsts.MaxNameLength)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(ProductConsts.MaxImageNameLength)]
|
||||
public string? ImageName { get; set; }
|
||||
|
||||
public float Price { get; set; }
|
||||
|
||||
public int StockCount { get; set; }
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
@page
|
||||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
|
||||
@using Microsoft.AspNetCore.Mvc.Localization
|
||||
@using ProductManagement.Localization
|
||||
@model ProductManagement.Pages.ProductManagement.Products.EditModel
|
||||
@inject IHtmlLocalizer<ProductManagementResource> L
|
||||
@{
|
||||
Layout = null;
|
||||
}
|
||||
|
||||
<abp-dynamic-form submit-button="false" abp-model="Product" asp-page="/ProductManagement/Products/Edit">
|
||||
<abp-modal size="@(AbpModalSize.Large)">
|
||||
<abp-modal-header title="@L["Edit"].Value"></abp-modal-header>
|
||||
<abp-modal-body>
|
||||
<abp-form-content />
|
||||
</abp-modal-body>
|
||||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)">
|
||||
</abp-modal-footer>
|
||||
</abp-modal>
|
||||
</abp-dynamic-form>
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
|
||||
|
||||
namespace ProductManagement.Pages.ProductManagement.Products;
|
||||
|
||||
public class EditModel : AbpPageModel
|
||||
{
|
||||
private readonly IProductAppService _productAppService;
|
||||
|
||||
[BindProperty]
|
||||
public ProductEditViewModel Product { get; set; } = new ProductEditViewModel();
|
||||
|
||||
public EditModel(IProductAppService productAppService)
|
||||
{
|
||||
_productAppService = productAppService;
|
||||
}
|
||||
|
||||
public async Task<ActionResult> OnGetAsync(Guid productId)
|
||||
{
|
||||
var productDto = await _productAppService.GetAsync(productId);
|
||||
Product = ObjectMapper.Map<ProductDto, ProductEditViewModel>(productDto);
|
||||
return Page();
|
||||
}
|
||||
|
||||
public async Task OnPostAsync()
|
||||
{
|
||||
await _productAppService.UpdateAsync(Product.Id, new UpdateProductDto()
|
||||
{
|
||||
Name = Product.Name,
|
||||
Price = Product.Price,
|
||||
StockCount = Product.StockCount
|
||||
});
|
||||
}
|
||||
|
||||
public class ProductEditViewModel
|
||||
{
|
||||
[HiddenInput]
|
||||
[Required]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(ProductConsts.MaxNameLength)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(ProductConsts.MaxImageNameLength)]
|
||||
public string? ImageName { get; set; }
|
||||
|
||||
public float Price { get; set; }
|
||||
|
||||
public int StockCount { get; set; }
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
@page
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Mvc.Localization
|
||||
@using ProductManagement
|
||||
@using ProductManagement.Localization
|
||||
@model ProductManagement.Pages.ProductManagement.Products.IndexModel
|
||||
@using Volo.Abp.AspNetCore.Mvc.UI.Theming
|
||||
@inject IThemeManager ThemeManager
|
||||
@inject IAuthorizationService Authorization
|
||||
@inject IHtmlLocalizer<ProductManagementResource> L
|
||||
@{
|
||||
ViewBag.PageTitle = "Products";
|
||||
Layout = ThemeManager.CurrentTheme.GetApplicationLayout();
|
||||
}
|
||||
|
||||
@section scripts {
|
||||
<abp-script src="/Pages/ProductManagement/Products/index.js" />
|
||||
}
|
||||
|
||||
<abp-card>
|
||||
<abp-card-header>
|
||||
<abp-row>
|
||||
<abp-column size-md="_6">
|
||||
<h2>@L["Products"]</h2>
|
||||
</abp-column>
|
||||
<abp-column size-md="_6" class="text-right">
|
||||
@if (await Authorization.IsGrantedAsync(ProductManagementPermissions.Products.Create))
|
||||
{
|
||||
<abp-button icon="plus" text="@L["CreateANewProduct"].Value" button-type="Primary" id="CreateNewProductButtonId"></abp-button>
|
||||
}
|
||||
</abp-column>
|
||||
</abp-row>
|
||||
</abp-card-header>
|
||||
<abp-card-body>
|
||||
<abp-table striped-rows="true" id="ProductsTable" class="nowrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>@L["Actions"]</th>
|
||||
<th>@L["Code"]</th>
|
||||
<th>@L["Name"]</th>
|
||||
<th>@L["Price"]</th>
|
||||
<th>@L["StockCount"]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</abp-table>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
|
||||
|
||||
namespace ProductManagement.Pages.ProductManagement.Products;
|
||||
|
||||
public class IndexModel : AbpPageModel
|
||||
{
|
||||
public async Task OnGetAsync()
|
||||
{
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
$(function () {
|
||||
|
||||
var l = abp.localization.getResource('ProductManagement');
|
||||
var _createModal = new abp.ModalManager(abp.appPath + 'ProductManagement/Products/Create');
|
||||
var _editModal = new abp.ModalManager(abp.appPath + 'ProductManagement/Products/Edit');
|
||||
|
||||
var _dataTable = $('#ProductsTable').DataTable(abp.libs.datatables.normalizeConfiguration({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
paging: true,
|
||||
searching: false,
|
||||
autoWidth: false,
|
||||
scrollCollapse: true,
|
||||
order: [[1, "desc"]],
|
||||
ajax: abp.libs.datatables.createAjax(productManagement.products.getListPaged),
|
||||
columnDefs: [
|
||||
{
|
||||
rowAction: {
|
||||
items:
|
||||
[
|
||||
{
|
||||
text: l('Edit'),
|
||||
visible: abp.auth.isGranted('ProductManagement.Product.Update'),
|
||||
action: function (data) {
|
||||
_editModal.open({
|
||||
productId: data.record.id
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
text: l('Delete'),
|
||||
visible: abp.auth.isGranted('ProductManagement.Product.Delete'),
|
||||
confirmMessage: function (data) { return l('ProductDeletionWarningMessage'); },
|
||||
action: function (data) {
|
||||
productManagement.products
|
||||
.delete(data.record.id)
|
||||
.then(function () {
|
||||
_dataTable.ajax.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
target: 1,
|
||||
data: "code"
|
||||
},
|
||||
{
|
||||
target: 2,
|
||||
data: "name"
|
||||
},
|
||||
{
|
||||
target: 3,
|
||||
data: "price"
|
||||
},
|
||||
{
|
||||
target: 4,
|
||||
data: "stockCount"
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
$("#CreateNewProductButtonId").click(function () {
|
||||
_createModal.open();
|
||||
});
|
||||
|
||||
_createModal.onClose(function () {
|
||||
_dataTable.ajax.reload();
|
||||
});
|
||||
|
||||
_editModal.onResult(function () {
|
||||
_dataTable.ajax.reload();
|
||||
});
|
||||
|
||||
});
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
|
||||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
|
||||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using ProductManagement.Localization;
|
||||
using Volo.Abp.UI.Navigation;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductManagementMenuContributor : IMenuContributor
|
||||
{
|
||||
public async Task ConfigureMenuAsync(MenuConfigurationContext context)
|
||||
{
|
||||
if (context.Menu.Name == StandardMenus.Main)
|
||||
{
|
||||
await ConfigureMainMenu(context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ConfigureMainMenu(MenuConfigurationContext context)
|
||||
{
|
||||
var l = context.GetLocalizer<ProductManagementResource>();
|
||||
|
||||
var rootMenuItem = new ApplicationMenuItem("ProductManagement", l["Menu:ProductManagement"]);
|
||||
|
||||
if (await context.IsGrantedAsync(ProductManagementPermissions.Products.Default))
|
||||
{
|
||||
rootMenuItem.AddItem(new ApplicationMenuItem("Products", l["Menu:Products"], "/ProductManagement/Products"));
|
||||
}
|
||||
|
||||
context.Menu.AddItem(rootMenuItem);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
using AutoMapper;
|
||||
using ProductManagement.Pages.ProductManagement.Products;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
public class ProductManagementWebAutoMapperProfile : Profile
|
||||
{
|
||||
public ProductManagementWebAutoMapperProfile()
|
||||
{
|
||||
CreateMap<CreateModel.ProductCreateViewModel, CreateProductDto>();
|
||||
CreateMap<ProductDto, EditModel.ProductEditViewModel>();
|
||||
}
|
||||
}
|
||||
+55
-2
@@ -1,6 +1,59 @@
|
||||
using Localization.Resources.AbpUi;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ProductManagement.Localization;
|
||||
using Volo.Abp.AspNetCore.Mvc;
|
||||
using Volo.Abp.AspNetCore.Mvc.Localization;
|
||||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
|
||||
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
|
||||
using Volo.Abp.AutoMapper;
|
||||
using Volo.Abp.Localization;
|
||||
using Volo.Abp.Modularity;
|
||||
using Volo.Abp.UI.Navigation;
|
||||
using Volo.Abp.Validation.Localization;
|
||||
using Volo.Abp.VirtualFileSystem;
|
||||
|
||||
namespace ProductManagement;
|
||||
|
||||
[DependsOn(typeof(ProductManagementHttpApiModule))]
|
||||
public class ProductManagementWebModule : AbpModule { }
|
||||
[DependsOn(
|
||||
typeof(ProductManagementHttpApiModule),
|
||||
typeof(AbpAspNetCoreMvcUiThemeSharedModule),
|
||||
typeof(AbpAutoMapperModule)
|
||||
)]
|
||||
public class ProductManagementWebModule : AbpModule
|
||||
{
|
||||
public override void PreConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
|
||||
{
|
||||
options.AddAssemblyResource(typeof(ProductManagementResource), typeof(ProductManagementWebModule).Assembly);
|
||||
});
|
||||
}
|
||||
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
Configure<AbpNavigationOptions>(options =>
|
||||
{
|
||||
options.MenuContributors.Add(new ProductManagementMenuContributor());
|
||||
});
|
||||
|
||||
Configure<AbpVirtualFileSystemOptions>(options =>
|
||||
{
|
||||
options.FileSets.AddEmbedded<ProductManagementWebModule>("ProductManagement");
|
||||
});
|
||||
|
||||
Configure<AbpLocalizationOptions>(options =>
|
||||
{
|
||||
options.Resources
|
||||
.Get<ProductManagementResource>()
|
||||
.AddBaseTypes(
|
||||
typeof(AbpValidationResource),
|
||||
typeof(AbpUiResource)
|
||||
).AddVirtualJson("/Localization/Resources/ProductManagement");
|
||||
});
|
||||
|
||||
Configure<AbpAutoMapperOptions>(options =>
|
||||
{
|
||||
options.AddProfile<ProductManagementWebAutoMapperProfile>(validate: true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "https://localhost:44301",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"ProductManagement.Web": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:44301",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<RootNamespace />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ProductManagement.Application\ProductManagement.Application.csproj" />
|
||||
<ProjectReference Include="..\ProductManagement.Domain.Tests\ProductManagement.Domain.Tests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Shouldly;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using Xunit;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
public class ProductAppService_Tests : ProductManagementApplicationTestBase
|
||||
{
|
||||
private readonly IProductAppService _productAppService;
|
||||
private readonly IRepository<Product, Guid> _productRepository;
|
||||
private readonly ProductManagementTestData _testData;
|
||||
|
||||
public ProductAppService_Tests()
|
||||
{
|
||||
_productAppService = GetRequiredService<IProductAppService>();
|
||||
_productRepository = GetRequiredService<IRepository<Product, Guid>>();
|
||||
_testData = GetRequiredService<ProductManagementTestData>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetListPagedAsync()
|
||||
{
|
||||
var result = await _productAppService.GetListPagedAsync(new PagedAndSortedResultRequestDto());
|
||||
|
||||
result.Items.Count.ShouldBeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetListAsync()
|
||||
{
|
||||
var result = await _productAppService.GetListAsync();
|
||||
|
||||
result.Items.Count.ShouldBeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAsync()
|
||||
{
|
||||
var product = (await _productRepository.GetListAsync()).FirstOrDefault();
|
||||
|
||||
var result = await _productAppService.GetAsync(product.Id);
|
||||
|
||||
result.ShouldNotBeNull();
|
||||
result.Name.ShouldBe(_testData.ProductName1);
|
||||
result.Code.ShouldBe(_testData.ProductCode1);
|
||||
result.Price.ShouldBe(_testData.ProductPrice1);
|
||||
result.StockCount.ShouldBe(_testData.ProductStockCount1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAsync()
|
||||
{
|
||||
var result = await _productAppService.CreateAsync(new CreateProductDto()
|
||||
{
|
||||
Code = "Code",
|
||||
Name = "Name",
|
||||
Price = 15,
|
||||
StockCount = 14
|
||||
});
|
||||
|
||||
result.ShouldNotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAsync()
|
||||
{
|
||||
var product = (await _productRepository.GetListAsync()).FirstOrDefault();
|
||||
|
||||
var result = await _productAppService.UpdateAsync(product.Id, new UpdateProductDto()
|
||||
{
|
||||
Name = nameof(Product.Name),
|
||||
Price = 15,
|
||||
StockCount = 14
|
||||
});
|
||||
|
||||
result.ShouldNotBeNull();
|
||||
result.Name.ShouldBe(nameof(Product.Name));
|
||||
result.Price.ShouldBe(15);
|
||||
result.StockCount.ShouldBe(14);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteAsync()
|
||||
{
|
||||
var product = (await _productRepository.GetListAsync()).LastOrDefault();
|
||||
|
||||
await _productAppService.DeleteAsync(product.Id);
|
||||
|
||||
var result = await _productRepository.FindAsync(product.Id);
|
||||
|
||||
result.ShouldBeNull();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using ProductManagement.EntityFrameworkCore;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
public abstract class ProductManagementApplicationTestBase : ProductManagementTestBase<ProductManagementApplicationTestModule>
|
||||
{
|
||||
protected virtual void UsingDbContext(Action<IProductManagementDbContext> action)
|
||||
{
|
||||
using (var dbContext = GetRequiredService<IProductManagementDbContext>())
|
||||
{
|
||||
action.Invoke(dbContext);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual T UsingDbContext<T>(Func<IProductManagementDbContext, T> action)
|
||||
{
|
||||
using (var dbContext = GetRequiredService<IProductManagementDbContext>())
|
||||
{
|
||||
return action.Invoke(dbContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Volo.Abp.Modularity;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
[DependsOn(
|
||||
typeof(ProductManagementApplicationModule),
|
||||
typeof(ProductManagementDomainTestModule)
|
||||
)]
|
||||
public class ProductManagementApplicationTestModule : AbpModule
|
||||
{
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
context.Services.AddAlwaysAllowAuthorization();
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<RootNamespace />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ProductManagement.EntityFrameworkCore.Tests\ProductManagement.EntityFrameworkCore.Tests.csproj" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Volo.Abp.Uow;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
public abstract class ProductManagementDomainTestBase : ProductManagementTestBase<ProductManagementDomainTestModule>
|
||||
{
|
||||
#region WithUnitOfWork
|
||||
|
||||
protected virtual Task WithUnitOfWorkAsync(Func<Task> func)
|
||||
{
|
||||
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func);
|
||||
}
|
||||
|
||||
protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func<Task> action)
|
||||
{
|
||||
using (var scope = ServiceProvider.CreateScope())
|
||||
{
|
||||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
|
||||
|
||||
using (var uow = uowManager.Begin(options))
|
||||
{
|
||||
await action();
|
||||
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Task<TResult> WithUnitOfWorkAsync<TResult>(Func<Task<TResult>> func)
|
||||
{
|
||||
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func);
|
||||
}
|
||||
|
||||
protected virtual async Task<TResult> WithUnitOfWorkAsync<TResult>(AbpUnitOfWorkOptions options, Func<Task<TResult>> func)
|
||||
{
|
||||
using (var scope = ServiceProvider.CreateScope())
|
||||
{
|
||||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
|
||||
|
||||
using (var uow = uowManager.Begin(options))
|
||||
{
|
||||
var result = await func();
|
||||
await uow.CompleteAsync();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
using ProductManagement.EntityFrameworkCore;
|
||||
using Volo.Abp.Modularity;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
[DependsOn(
|
||||
typeof(ProductManagementEntityFrameworkCoreTestModule)
|
||||
)]
|
||||
public class ProductManagementDomainTestModule : AbpModule
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
using System.Threading.Tasks;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
public class ProductManager_Tests : ProductManagementDomainTestBase
|
||||
{
|
||||
private readonly ProductManager _productManager;
|
||||
|
||||
public ProductManager_Tests()
|
||||
{
|
||||
_productManager = GetRequiredService<ProductManager>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Create_A_Valid_Product()
|
||||
{
|
||||
//Act
|
||||
var product = await WithUnitOfWorkAsync(
|
||||
async () =>
|
||||
{
|
||||
return await _productManager.CreateAsync("P000837212", "My Product 837212", stockCount: 42);
|
||||
}
|
||||
);
|
||||
|
||||
//Assert
|
||||
product.Code.ShouldBe("P000837212");
|
||||
product.Name.ShouldBe("My Product 837212");
|
||||
product.Price.ShouldBe(0.0f);
|
||||
product.StockCount.ShouldBe(42);
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<RootNamespace />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ProductManagement.EntityFrameworkCore\ProductManagement.EntityFrameworkCore.csproj" />
|
||||
<ProjectReference Include="..\ProductManagement.TestBase\ProductManagement.TestBase.csproj" />
|
||||
<PackageReference Include="Volo.Abp.EntityFrameworkCore.Sqlite" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Volo.Abp.EntityFrameworkCore;
|
||||
using Volo.Abp.EntityFrameworkCore.Sqlite;
|
||||
using Volo.Abp.Modularity;
|
||||
|
||||
namespace ProductManagement.EntityFrameworkCore
|
||||
{
|
||||
[DependsOn(
|
||||
typeof(ProductManagementTestBaseModule),
|
||||
typeof(ProductManagementEntityFrameworkCoreModule),
|
||||
typeof(AbpEntityFrameworkCoreSqliteModule)
|
||||
)]
|
||||
public class ProductManagementEntityFrameworkCoreTestModule : AbpModule
|
||||
{
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
var sqliteConnection = CreateDatabaseAndGetConnection();
|
||||
|
||||
Configure<AbpDbContextOptions>(options =>
|
||||
{
|
||||
options.Configure(abpDbContextConfigurationContext =>
|
||||
{
|
||||
abpDbContextConfigurationContext.DbContextOptions.UseSqlite(sqliteConnection);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static SqliteConnection CreateDatabaseAndGetConnection()
|
||||
{
|
||||
var connection = new SqliteConnection("Data Source=:memory:");
|
||||
connection.Open();
|
||||
|
||||
new ProductManagementDbContext(
|
||||
new DbContextOptionsBuilder<ProductManagementDbContext>().UseSqlite(connection).Options
|
||||
).GetService<IRelationalDatabaseCreator>().CreateTables();
|
||||
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<RootNamespace />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Volo.Abp.Autofac" Version="9.0.0" />
|
||||
<PackageReference Include="Volo.Abp.Authorization" Version="9.0.0" />
|
||||
<PackageReference Include="Volo.Abp.TestBase" Version="9.0.0" />
|
||||
<ProjectReference Include="..\..\src\ProductManagement.Domain\ProductManagement.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="NSubstitute" Version="4.2.2" />
|
||||
<PackageReference Include="Shouldly" Version="3.0.2" />
|
||||
<PackageReference Include="xunit" Version="2.6.0" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using Volo.Abp;
|
||||
using Volo.Abp.Modularity;
|
||||
using Volo.Abp.Testing;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
public abstract class ProductManagementTestBase<TStartupModule> : AbpIntegratedTest<TStartupModule>
|
||||
where TStartupModule : IAbpModule
|
||||
{
|
||||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
|
||||
{
|
||||
options.UseAutofac();
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Volo.Abp;
|
||||
using Volo.Abp.Authorization;
|
||||
using Volo.Abp.Autofac;
|
||||
using Volo.Abp.Modularity;
|
||||
using Volo.Abp.Uow;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
[DependsOn(
|
||||
typeof(AbpAutofacModule),
|
||||
typeof(AbpTestBaseModule),
|
||||
typeof(AbpAuthorizationModule),
|
||||
typeof(ProductManagementDomainModule)
|
||||
)]
|
||||
public class ProductManagementTestBaseModule : AbpModule
|
||||
{
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
context.Services.AddAlwaysAllowAuthorization();
|
||||
|
||||
Configure<AbpUnitOfWorkDefaultOptions>(options =>
|
||||
{
|
||||
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled;
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnApplicationInitialization(ApplicationInitializationContext context)
|
||||
{
|
||||
SeedTestData(context);
|
||||
}
|
||||
|
||||
private static void SeedTestData(ApplicationInitializationContext context)
|
||||
{
|
||||
using (var scope = context.ServiceProvider.CreateScope())
|
||||
{
|
||||
scope.ServiceProvider
|
||||
.GetRequiredService<ProductManagementTestDataBuilder>()
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using Volo.Abp.DependencyInjection;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
public class ProductManagementTestData : ISingletonDependency
|
||||
{
|
||||
public string ProductCode1 { get; } = "ProductCode1";
|
||||
|
||||
public string ProductName1 { get; } = "ProductName1";
|
||||
|
||||
public float ProductPrice1 { get; } = 20;
|
||||
|
||||
public int ProductStockCount1 { get; } = 100;
|
||||
|
||||
public string ProductCode2 { get; } = "ProductCode2";
|
||||
|
||||
public string ProductName2 { get; } = "ProductName2";
|
||||
|
||||
public float ProductPrice2 { get; } = 30;
|
||||
|
||||
public int ProductStockCount2 { get; } = 110;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Threading;
|
||||
using Volo.Abp.Uow;
|
||||
|
||||
namespace ProductManagement
|
||||
{
|
||||
public class ProductManagementTestDataBuilder : ITransientDependency
|
||||
{
|
||||
private ProductManagementTestData _testData;
|
||||
private readonly ProductManager _productManager;
|
||||
|
||||
public ProductManagementTestDataBuilder(
|
||||
ProductManagementTestData testData,
|
||||
ProductManager productManager)
|
||||
{
|
||||
_testData = testData;
|
||||
_productManager = productManager;
|
||||
}
|
||||
|
||||
public void Build()
|
||||
{
|
||||
AsyncHelper.RunSync(BuildAsync);
|
||||
}
|
||||
|
||||
[UnitOfWork]
|
||||
public virtual async Task BuildAsync()
|
||||
{
|
||||
await _productManager.CreateAsync(_testData.ProductCode1, _testData.ProductName1, _testData.ProductPrice1, _testData.ProductStockCount1);
|
||||
await _productManager.CreateAsync(_testData.ProductCode2, _testData.ProductName2, _testData.ProductPrice2, _testData.ProductStockCount2);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user