From bbf2712dd7796e775faa072921c4249288938ae4 Mon Sep 17 00:00:00 2001 From: duykasama Date: Fri, 16 Feb 2024 20:15:46 +0700 Subject: [PATCH 1/6] [Products mangement][Duy] Update products in response - Add Category - Add Prices --- Domus.Domain/Dtos/Products/DtoProduct.cs | 1 + Domus.Domain/Dtos/Products/DtoProductDetail.cs | 3 +++ Domus.Domain/Dtos/Products/DtoProductPrice.cs | 12 ++++++++++++ .../AutoMappings/AutoMapperConfiguration.cs | 1 + Domus.Service/Implementations/ProductService.cs | 4 ++-- 5 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 Domus.Domain/Dtos/Products/DtoProductPrice.cs diff --git a/Domus.Domain/Dtos/Products/DtoProduct.cs b/Domus.Domain/Dtos/Products/DtoProduct.cs index 5efa95c..1151665 100644 --- a/Domus.Domain/Dtos/Products/DtoProduct.cs +++ b/Domus.Domain/Dtos/Products/DtoProduct.cs @@ -12,6 +12,7 @@ public class DtoProduct public string? Description { get; set; } + [JsonPropertyName("category")] public DtoProductCategory ProductCategory { get; set; } = null!; [JsonPropertyName("details")] diff --git a/Domus.Domain/Dtos/Products/DtoProductDetail.cs b/Domus.Domain/Dtos/Products/DtoProductDetail.cs index 9c47967..d33ebb8 100644 --- a/Domus.Domain/Dtos/Products/DtoProductDetail.cs +++ b/Domus.Domain/Dtos/Products/DtoProductDetail.cs @@ -13,4 +13,7 @@ public class DtoProductDetail [JsonPropertyName("images")] public virtual ICollection ProductImages { get; set; } = new List(); + + [JsonPropertyName("prices")] + public virtual ICollection ProductPrices { get; set; } = new List(); } diff --git a/Domus.Domain/Dtos/Products/DtoProductPrice.cs b/Domus.Domain/Dtos/Products/DtoProductPrice.cs new file mode 100644 index 0000000..406c0ec --- /dev/null +++ b/Domus.Domain/Dtos/Products/DtoProductPrice.cs @@ -0,0 +1,12 @@ +namespace Domus.Domain.Dtos.Products; + +public class DtoProductPrice +{ + public double Price { get; set; } + + public string MonetaryUnit { get; set; } = null!; + + public double Quantity { get; set; } + + public string QuantityType { get; set; } = null!; +} diff --git a/Domus.Service/AutoMappings/AutoMapperConfiguration.cs b/Domus.Service/AutoMappings/AutoMapperConfiguration.cs index f66f251..40bcfcf 100644 --- a/Domus.Service/AutoMappings/AutoMapperConfiguration.cs +++ b/Domus.Service/AutoMappings/AutoMapperConfiguration.cs @@ -66,6 +66,7 @@ private static void CreateProductMaps(IMapperConfigurationExpression mapper) .ForMember(dest => dest.ProductAttributeValues, opt => opt.MapFrom((src) => src.ProductAttributeValues.Select(pav => new DtoProductAttributeValue { Name = pav.ProductAttribute.AttributeName, Value = pav.Value, ValueType = pav.ValueType }))); mapper.CreateMap(); mapper.CreateMap(); + mapper.CreateMap(); } private static void CreateServiceMaps(IMapperConfigurationExpression mapper) diff --git a/Domus.Service/Implementations/ProductService.cs b/Domus.Service/Implementations/ProductService.cs index ae49610..8e656de 100644 --- a/Domus.Service/Implementations/ProductService.cs +++ b/Domus.Service/Implementations/ProductService.cs @@ -60,7 +60,7 @@ public async Task DeleteProduct(Guid id) public async Task GetAllProducts() { - var products = await (await _productRepository.GetAllAsync()).ProjectTo(_mapper.ConfigurationProvider) + var products = await (await _productRepository.GetAllAsync()).ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); return new ServiceActionResult(true) { Data = products }; @@ -68,7 +68,7 @@ public async Task GetAllProducts() public async Task GetPaginatedProducts(BasePaginatedRequest request) { - var queryableProducts = (await _productRepository.GetAllAsync()).ProjectTo(_mapper.ConfigurationProvider); + var queryableProducts = (await _productRepository.GetAllAsync()).ProjectTo(_mapper.ConfigurationProvider); var paginatedResult = PaginationHelper.BuildPaginatedResult(queryableProducts, request.PageSize, request.PageIndex); return new ServiceActionResult(true) { Data = paginatedResult }; From 23749484360b28a8dcf05fda81bf352b832bc7e4 Mon Sep 17 00:00:00 2001 From: duykasama Date: Sat, 17 Feb 2024 10:42:31 +0700 Subject: [PATCH 2/6] [Products management][Duy] Make 'Product' entity inherit 'DeletableEntity' --- Domus.Domain/Entities/Product.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Domus.Domain/Entities/Product.cs b/Domus.Domain/Entities/Product.cs index d83f29b..098a6ea 100644 --- a/Domus.Domain/Entities/Product.cs +++ b/Domus.Domain/Entities/Product.cs @@ -2,7 +2,7 @@ namespace Domus.Domain.Entities; -public partial class Product : BaseEntity +public partial class Product : DeletableEntity { public Guid ProductCategoryId { get; set; } @@ -12,8 +12,6 @@ public partial class Product : BaseEntity public string? Description { get; set; } - public bool? IsDeleted { get; set; } - public string? ConcurrencyStamp { get; set; } public virtual ProductCategory ProductCategory { get; set; } = null!; From 259144164a1426f358a4a42e041a892e7750f2bf Mon Sep 17 00:00:00 2001 From: duykasama Date: Sat, 17 Feb 2024 10:47:01 +0700 Subject: [PATCH 3/6] Products management][Duy] Do not return deleted products --- Domus.Service/Implementations/ProductService.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Domus.Service/Implementations/ProductService.cs b/Domus.Service/Implementations/ProductService.cs index 8e656de..1b5bf10 100644 --- a/Domus.Service/Implementations/ProductService.cs +++ b/Domus.Service/Implementations/ProductService.cs @@ -47,7 +47,7 @@ public async Task CreateProduct(CreateProductRequest reques public async Task DeleteProduct(Guid id) { - var product = await _productRepository.GetAsync(p => p.Id == id); + var product = await _productRepository.GetAsync(p => !p.IsDeleted && p.Id == id); if (product is null) throw new ProductNotFoundException(); @@ -60,7 +60,9 @@ public async Task DeleteProduct(Guid id) public async Task GetAllProducts() { - var products = await (await _productRepository.GetAllAsync()).ProjectTo(_mapper.ConfigurationProvider) + var products = await (await _productRepository.GetAllAsync()) + .Where(p => !p.IsDeleted) + .ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); return new ServiceActionResult(true) { Data = products }; @@ -68,7 +70,9 @@ public async Task GetAllProducts() public async Task GetPaginatedProducts(BasePaginatedRequest request) { - var queryableProducts = (await _productRepository.GetAllAsync()).ProjectTo(_mapper.ConfigurationProvider); + var queryableProducts = (await _productRepository.GetAllAsync()) + .Where(p => !p.IsDeleted) + .ProjectTo(_mapper.ConfigurationProvider); var paginatedResult = PaginationHelper.BuildPaginatedResult(queryableProducts, request.PageSize, request.PageIndex); return new ServiceActionResult(true) { Data = paginatedResult }; @@ -77,8 +81,8 @@ public async Task GetPaginatedProducts(BasePaginatedRequest public async Task GetProduct(Guid id) { var product = await (await _productRepository.GetAllAsync()) + .Where(p => !p.IsDeleted && p.Id == id) .ProjectTo(_mapper.ConfigurationProvider) - .Where(p => p.Id == id) .FirstOrDefaultAsync() ?? throw new ProductNotFoundException(); return new ServiceActionResult(true) { Data = product }; @@ -86,7 +90,7 @@ public async Task GetProduct(Guid id) public async Task UpdateProduct(UpdateProductRequest request, Guid id) { - var product = await _productRepository.GetAsync(p => p.Id == id); + var product = await _productRepository.GetAsync(p => !p.IsDeleted && p.Id == id); if (product is null) throw new ProductNotFoundException(); if (!await _productCategoryRepository.ExistsAsync(c => c.Id == request.ProductCategoryId)) From 7f0012589296f66abe3c7c725b0dbbddde886a18 Mon Sep 17 00:00:00 2001 From: duykasama Date: Sat, 17 Feb 2024 11:27:05 +0700 Subject: [PATCH 4/6] [Refactor][Duy] Remove unnecessary usings --- Domus.Service/Implementations/ProductDetailService.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Domus.Service/Implementations/ProductDetailService.cs b/Domus.Service/Implementations/ProductDetailService.cs index afd4a90..e45d5ae 100644 --- a/Domus.Service/Implementations/ProductDetailService.cs +++ b/Domus.Service/Implementations/ProductDetailService.cs @@ -1,4 +1,3 @@ -using System.Collections; using AutoMapper; using AutoMapper.QueryableExtensions; using Domus.Common.Helpers; @@ -19,8 +18,6 @@ public class ProductDetailService : IProductDetailService private readonly IProductRepository _productRepository; private readonly IMapper _mapper; private readonly IUnitOfWork _unitOfWork; - private readonly IProductPriceRepository _productPriceRepository; - private readonly IProductAttributeValueRepository _productAttributeValueRepository; private readonly IProductAttributeRepository _productAttributeRepository; public ProductDetailService( @@ -28,16 +25,12 @@ public ProductDetailService( IMapper mapper, IUnitOfWork unitOfWork, IProductRepository productRepository, - IProductPriceRepository productPriceRepository, - IProductAttributeValueRepository productAttributeValueRepository, IProductAttributeRepository productAttributeRepository) { _productDetailRepository = productDetailRepository; _mapper = mapper; _unitOfWork = unitOfWork; _productRepository = productRepository; - _productPriceRepository = productPriceRepository; - _productAttributeValueRepository = productAttributeValueRepository; _productAttributeRepository = productAttributeRepository; } From bfa12ef9588c83af2619e29a39965770050b1f49 Mon Sep 17 00:00:00 2001 From: duykasama Date: Sat, 17 Feb 2024 11:28:25 +0700 Subject: [PATCH 5/6] [Products management][Duy] Add total quantity to products list --- Domus.Domain/Dtos/Products/DtoProduct.cs | 2 ++ Domus.Service/Implementations/ProductService.cs | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/Domus.Domain/Dtos/Products/DtoProduct.cs b/Domus.Domain/Dtos/Products/DtoProduct.cs index 1151665..eef78c6 100644 --- a/Domus.Domain/Dtos/Products/DtoProduct.cs +++ b/Domus.Domain/Dtos/Products/DtoProduct.cs @@ -12,6 +12,8 @@ public class DtoProduct public string? Description { get; set; } + public int TotalQuantity { get; set; } + [JsonPropertyName("category")] public DtoProductCategory ProductCategory { get; set; } = null!; diff --git a/Domus.Service/Implementations/ProductService.cs b/Domus.Service/Implementations/ProductService.cs index 1b5bf10..af79608 100644 --- a/Domus.Service/Implementations/ProductService.cs +++ b/Domus.Service/Implementations/ProductService.cs @@ -64,6 +64,11 @@ public async Task GetAllProducts() .Where(p => !p.IsDeleted) .ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); + + foreach (var product in products) + { + product.TotalQuantity = (int)product.ProductDetails.Sum(d => d.ProductPrices.Sum(p => p.Quantity)); + } return new ServiceActionResult(true) { Data = products }; } @@ -74,6 +79,14 @@ public async Task GetPaginatedProducts(BasePaginatedRequest .Where(p => !p.IsDeleted) .ProjectTo(_mapper.ConfigurationProvider); var paginatedResult = PaginationHelper.BuildPaginatedResult(queryableProducts, request.PageSize, request.PageIndex); + var products = await ((IQueryable)paginatedResult.Items!).ToListAsync(); + + foreach (var product in products) + { + product.TotalQuantity = (int)product.ProductDetails.Sum(d => d.ProductPrices.Sum(p => p.Quantity)); + } + + paginatedResult.Items = products; return new ServiceActionResult(true) { Data = paginatedResult }; } From 9d0e3cecfd204a63ba61bbd0c761c37368508479 Mon Sep 17 00:00:00 2001 From: duykasama Date: Sat, 17 Feb 2024 12:35:36 +0700 Subject: [PATCH 6/6] [Products management][Duy] Delete multiple products --- Domus.Api/Controllers/ProductsController.cs | 10 +++++++++- Domus.DAL/Implementations/ProductRepository.cs | 10 ++++++++++ Domus.DAL/Interfaces/IProductRepository.cs | 2 ++ Domus.Service/Implementations/ProductService.cs | 8 ++++++++ Domus.Service/Interfaces/IProductService.cs | 1 + 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Domus.Api/Controllers/ProductsController.cs b/Domus.Api/Controllers/ProductsController.cs index 9f15278..48261a5 100644 --- a/Domus.Api/Controllers/ProductsController.cs +++ b/Domus.Api/Controllers/ProductsController.cs @@ -12,7 +12,7 @@ namespace Domus.Api.Controllers; [Route("api/[controller]")] public class ProductsController : BaseApiController { - private IProductService _productService; + private readonly IProductService _productService; public ProductsController(IProductService productService) { @@ -69,4 +69,12 @@ public async Task DeleteProduct(Guid id) async () => await _productService.DeleteProduct(id).ConfigureAwait(false) ).ConfigureAwait(false); } + + [HttpDelete("multiple")] + public async Task DeleteMultipleProducts(IEnumerable ids) + { + return await ExecuteServiceLogic( + async () => await _productService.DeleteMultipleProducts(ids).ConfigureAwait(false) + ).ConfigureAwait(false); + } } diff --git a/Domus.DAL/Implementations/ProductRepository.cs b/Domus.DAL/Implementations/ProductRepository.cs index 218541f..9c6fdaa 100644 --- a/Domus.DAL/Implementations/ProductRepository.cs +++ b/Domus.DAL/Implementations/ProductRepository.cs @@ -1,11 +1,21 @@ +using System.Linq.Expressions; using Domus.DAL.Interfaces; using Domus.Domain.Entities; +using Microsoft.EntityFrameworkCore; namespace Domus.DAL.Implementations; public class ProductRepository : GenericRepository, IProductRepository { + private readonly DbSet _dbSet; public ProductRepository(IAppDbContext dbContext) : base(dbContext) { + _dbSet = dbContext.CreateSet(); + } + + public new async Task DeleteManyAsync(Expression> predicate) + { + var entities = _dbSet.Where(predicate); + await entities.ForEachAsync(p => p.IsDeleted = true); } } diff --git a/Domus.DAL/Interfaces/IProductRepository.cs b/Domus.DAL/Interfaces/IProductRepository.cs index dfefc6b..4e68fcb 100644 --- a/Domus.DAL/Interfaces/IProductRepository.cs +++ b/Domus.DAL/Interfaces/IProductRepository.cs @@ -1,3 +1,4 @@ +using System.Linq.Expressions; using Domus.Common.Interfaces; using Domus.Domain.Entities; @@ -5,4 +6,5 @@ namespace Domus.DAL.Interfaces; public interface IProductRepository : IGenericRepository, IAutoRegisterable { + new Task DeleteManyAsync(Expression> predicate); } diff --git a/Domus.Service/Implementations/ProductService.cs b/Domus.Service/Implementations/ProductService.cs index af79608..39943c4 100644 --- a/Domus.Service/Implementations/ProductService.cs +++ b/Domus.Service/Implementations/ProductService.cs @@ -115,4 +115,12 @@ public async Task UpdateProduct(UpdateProductRequest reques return new ServiceActionResult(true); } + + public async Task DeleteMultipleProducts(IEnumerable ids) + { + await _productRepository.DeleteManyAsync(p => !p.IsDeleted && ids.Contains(p.Id)); + await _unitOfWork.CommitAsync(); + + return new ServiceActionResult(true) { Detail = "Products deleted successfully"}; + } } diff --git a/Domus.Service/Interfaces/IProductService.cs b/Domus.Service/Interfaces/IProductService.cs index c80e356..6002626 100644 --- a/Domus.Service/Interfaces/IProductService.cs +++ b/Domus.Service/Interfaces/IProductService.cs @@ -13,4 +13,5 @@ public interface IProductService : IAutoRegisterable Task GetPaginatedProducts(BasePaginatedRequest request); Task GetProduct(Guid id); Task UpdateProduct(UpdateProductRequest request, Guid id); + Task DeleteMultipleProducts(IEnumerable ids); }