feat: Implement Discount Product and Shopping Cart functionalities

- Added UpdateDiscountProductCommandValidator for validating discount product updates.
- Created GetDiscountProductByIdQuery and its handler for retrieving discount product details by ID.
- Implemented GetDiscountProductsQuery and handler for fetching a list of discount products with filtering options.
- Developed AddToCartCommand and handler for adding products to the shopping cart.
- Implemented ClearCartCommand and handler for clearing the shopping cart.
- Created RemoveFromCartCommand and handler for removing items from the cart.
- Added UpdateCartItemCountCommand and handler for updating the quantity of items in the cart.
- Developed GetUserCartQuery and handler for retrieving the user's shopping cart details.
- Implemented Product Tag functionalities including assigning tags to products, creating, updating, and deleting tags.
- Added queries for fetching all tags and products by tag.
This commit is contained in:
masoodafar-web
2025-12-04 02:41:19 +03:30
parent c9dab944fa
commit 4f400eabc5
92 changed files with 2285 additions and 41 deletions
@@ -1,7 +1,7 @@
using System.IO;
using BackOffice.BFF.Application.Common.Interfaces;
using CMSMicroservice.Protobuf.Protos.ProductImages;
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
using Google.Protobuf;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
@@ -59,7 +59,7 @@ public class AddProductImageCommandHandler : IRequestHandler<AddProductImageComm
ImageThumbnailPath = thumbFileInfo.File
}, cancellationToken: cancellationToken);
var createGalleryResponse = await _context.ProductGallerys.CreateNewProductGallerysAsync(new CreateNewProductGallerysRequest
var createGalleryResponse = await _context.ProductGalleries.CreateNewProductGalleriesAsync(new CreateNewProductGalleriesRequest
{
ProductId = request.ProductId,
ProductImageId = createImageResponse.Id
@@ -1,5 +1,5 @@
using BackOffice.BFF.Application.Common.Interfaces;
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
namespace BackOffice.BFF.Application.ProductsCQ.Commands.RemoveProductImage;
@@ -14,7 +14,7 @@ public class RemoveProductImageCommandHandler : IRequestHandler<RemoveProductIma
public async Task<Unit> Handle(RemoveProductImageCommand request, CancellationToken cancellationToken)
{
await _context.ProductGallerys.DeleteProductGallerysAsync(new DeleteProductGallerysRequest
await _context.ProductGalleries.DeleteProductGalleriesAsync(new DeleteProductGalleriesRequest
{
Id = request.ProductGalleryId
}, cancellationToken: cancellationToken);
@@ -1,5 +1,5 @@
using BackOffice.BFF.Application.Common.Interfaces;
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateCategoryProducts;
@@ -17,9 +17,9 @@ public class UpdateCategoryProductsCommandHandler : IRequestHandler<UpdateCatego
var targetIds = request.ProductIds?.ToHashSet() ?? new HashSet<long>();
// load existing links for this category
var existingRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
var existingRequest = new CMSProductCategory.GetAllProductCategoryByFilterRequest
{
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
{
CategoryId = request.CategoryId
},
@@ -30,7 +30,7 @@ public class UpdateCategoryProductsCommandHandler : IRequestHandler<UpdateCatego
}
};
var existingResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
var existingResponse = await _context.ProductCategories.GetAllProductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
var existing = existingResponse.Models ?? new();
var existingIds = existing.Select(x => x.ProductId).ToHashSet();
@@ -40,19 +40,19 @@ public class UpdateCategoryProductsCommandHandler : IRequestHandler<UpdateCatego
foreach (var productId in toAdd)
{
var createRequest = new CMSPruductCategory.CreateNewPruductCategoryRequest
var createRequest = new CMSProductCategory.CreateNewProductCategoryRequest
{
ProductId = productId,
CategoryId = request.CategoryId
};
await _context.ProductCategories.CreateNewPruductCategoryAsync(createRequest, cancellationToken: cancellationToken);
await _context.ProductCategories.CreateNewProductCategoryAsync(createRequest, cancellationToken: cancellationToken);
}
foreach (var rel in toRemove)
{
await _context.ProductCategories.DeletePruductCategoryAsync(
new CMSPruductCategory.DeletePruductCategoryRequest { Id = rel.Id },
await _context.ProductCategories.DeleteProductCategoryAsync(
new CMSProductCategory.DeleteProductCategoryRequest { Id = rel.Id },
cancellationToken: cancellationToken);
}
@@ -1,5 +1,5 @@
using BackOffice.BFF.Application.Common.Interfaces;
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateProductCategories;
@@ -17,9 +17,9 @@ public class UpdateProductCategoriesCommandHandler : IRequestHandler<UpdateProdu
var targetIds = request.CategoryIds?.ToHashSet() ?? new HashSet<long>();
// Load existing product-category relations
var existingRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
var existingRequest = new CMSProductCategory.GetAllProductCategoryByFilterRequest
{
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
{
ProductId = request.ProductId
},
@@ -30,7 +30,7 @@ public class UpdateProductCategoriesCommandHandler : IRequestHandler<UpdateProdu
}
};
var existingResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
var existingResponse = await _context.ProductCategories.GetAllProductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
var existing = existingResponse.Models ?? new();
var existingIds = existing.Select(x => x.CategoryId).ToHashSet();
@@ -41,19 +41,19 @@ public class UpdateProductCategoriesCommandHandler : IRequestHandler<UpdateProdu
foreach (var categoryId in toAdd)
{
var createRequest = new CMSPruductCategory.CreateNewPruductCategoryRequest
var createRequest = new CMSProductCategory.CreateNewProductCategoryRequest
{
ProductId = request.ProductId,
CategoryId = categoryId
};
await _context.ProductCategories.CreateNewPruductCategoryAsync(createRequest, cancellationToken: cancellationToken);
await _context.ProductCategories.CreateNewProductCategoryAsync(createRequest, cancellationToken: cancellationToken);
}
foreach (var rel in toRemove)
{
await _context.ProductCategories.DeletePruductCategoryAsync(
new CMSPruductCategory.DeletePruductCategoryRequest { Id = rel.Id },
await _context.ProductCategories.DeleteProductCategoryAsync(
new CMSProductCategory.DeleteProductCategoryRequest { Id = rel.Id },
cancellationToken: cancellationToken);
}
@@ -1,6 +1,6 @@
using BackOffice.BFF.Application.Common.Interfaces;
using CMSCategory = CMSMicroservice.Protobuf.Protos.Category;
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
@@ -30,9 +30,9 @@ public class GetCategoriesQueryHandler : IRequestHandler<GetCategoriesQuery, Get
var categories = categoriesResponse.Models ?? new();
// Load existing product-category relations for this product
var productCategoryRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
var productCategoryRequest = new CMSProductCategory.GetAllProductCategoryByFilterRequest
{
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
{
ProductId = request.ProductId
},
@@ -43,7 +43,7 @@ public class GetCategoriesQueryHandler : IRequestHandler<GetCategoriesQuery, Get
}
};
var productCategoriesResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(productCategoryRequest, cancellationToken: cancellationToken);
var productCategoriesResponse = await _context.ProductCategories.GetAllProductCategoryByFilterAsync(productCategoryRequest, cancellationToken: cancellationToken);
var productCategories = productCategoriesResponse.Models ?? new();
var selectedIds = productCategories
@@ -1,5 +1,5 @@
using BackOffice.BFF.Application.Common.Interfaces;
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
using CMSMicroservice.Protobuf.Protos.ProductImages;
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery;
@@ -15,12 +15,12 @@ public class GetProductGalleryQueryHandler : IRequestHandler<GetProductGalleryQu
public async Task<GetProductGalleryResponseDto> Handle(GetProductGalleryQuery request, CancellationToken cancellationToken)
{
var galleryRequest = new GetAllProductGallerysByFilterRequest
var grpcRequest = new GetAllProductGalleriesByFilterRequest
{
Filter = new GetAllProductGallerysByFilterFilter()
Filter = new GetAllProductGalleriesByFilterFilter()
};
var galleryResponse = await _context.ProductGallerys.GetAllProductGallerysByFilterAsync(galleryRequest, cancellationToken: cancellationToken);
var galleryResponse = await _context.ProductGalleries.GetAllProductGalleriesByFilterAsync(grpcRequest, cancellationToken: cancellationToken);
// Filter by product id on client side because generated type may not support assigning Int64Value directly
var filteredModels = galleryResponse?.Models?.Where(x => x.ProductId == request.ProductId).ToList();
@@ -1,6 +1,6 @@
using BackOffice.BFF.Application.Common.Interfaces;
using CMSProducts = CMSMicroservice.Protobuf.Protos.Products;
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductsForCategory;
@@ -30,9 +30,9 @@ public class GetProductsForCategoryQueryHandler : IRequestHandler<GetProductsFor
var products = productsResponse.Models ?? new();
// Load links for this category
var linksRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
var linksRequest = new CMSProductCategory.GetAllProductCategoryByFilterRequest
{
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
{
CategoryId = request.CategoryId
},
@@ -43,7 +43,7 @@ public class GetProductsForCategoryQueryHandler : IRequestHandler<GetProductsFor
}
};
var linksResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(linksRequest, cancellationToken: cancellationToken);
var linksResponse = await _context.ProductCategories.GetAllProductCategoryByFilterAsync(linksRequest, cancellationToken: cancellationToken);
var links = linksResponse.Models ?? new();
var selectedProductIds = links.Select(l => l.ProductId).ToHashSet();