Implement product categories CRUD operations with CMS integration

This commit is contained in:
masoodafar-web
2025-11-27 04:50:35 +03:30
parent ad8d166476
commit bb8d35a1d1
4 changed files with 101 additions and 9 deletions

View File

@@ -8,6 +8,7 @@ using CMSMicroservice.Protobuf.Protos.Products;
using CMSMicroservice.Protobuf.Protos.ProductImages;
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
using CMSMicroservice.Protobuf.Protos.Category;
using CMSMicroservice.Protobuf.Protos.PruductCategory;
using FMSMicroservice.Protobuf.Protos.FileInfo;
namespace BackOffice.BFF.Application.Common.Interfaces;
@@ -24,6 +25,7 @@ public interface IApplicationContractContext
ProductGallerysContract.ProductGallerysContractClient ProductGallerys { get; }
RoleContract.RoleContractClient Roles { get; }
CategoryContract.CategoryContractClient Categories { get; }
PruductCategoryContract.PruductCategoryContractClient ProductCategories { get; }
UserAddressContract.UserAddressContractClient UserAddress { get; }
UserContract.UserContractClient Users { get; }
UserOrderContract.UserOrderContractClient UserOrders { get; }

View File

@@ -1,4 +1,5 @@
using BackOffice.BFF.Application.Common.Interfaces;
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateProductCategories;
@@ -13,9 +14,49 @@ public class UpdateProductCategoriesCommandHandler : IRequestHandler<UpdateProdu
public async Task<Unit> Handle(UpdateProductCategoriesCommand request, CancellationToken cancellationToken)
{
// Stub: until CMS Category services are available via the protobuf package,
// this handler is a no-op to keep the pipeline consistent.
await Task.CompletedTask;
var targetIds = request.CategoryIds?.ToHashSet() ?? new HashSet<long>();
// Load existing product-category relations
var existingRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
{
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
{
ProductId = request.ProductId
},
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
{
PageNumber = 1,
PageSize = 1000
}
};
var existingResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
var existing = existingResponse.Models ?? new();
var existingIds = existing.Select(x => x.CategoryId).ToHashSet();
// Determine which relations to add and which to remove
var toAdd = targetIds.Except(existingIds).ToList();
var toRemove = existing.Where(x => !targetIds.Contains(x.CategoryId)).ToList();
foreach (var categoryId in toAdd)
{
var createRequest = new CMSPruductCategory.CreateNewPruductCategoryRequest
{
ProductId = request.ProductId,
CategoryId = categoryId
};
await _context.ProductCategories.CreateNewPruductCategoryAsync(createRequest, cancellationToken: cancellationToken);
}
foreach (var rel in toRemove)
{
await _context.ProductCategories.DeletePruductCategoryAsync(
new CMSPruductCategory.DeletePruductCategoryRequest { Id = rel.Id },
cancellationToken: cancellationToken);
}
return Unit.Value;
}
}

View File

@@ -1,20 +1,67 @@
using BackOffice.BFF.Application.Common.Interfaces;
using CMSCategory = CMSMicroservice.Protobuf.Protos.Category;
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
public class GetCategoriesQueryHandler : IRequestHandler<GetCategoriesQuery, GetCategoriesResponseDto>
{
private readonly IApplicationContractContext _context;
public GetCategoriesQueryHandler(IApplicationContractContext context)
{
// context is currently unused; reserved for future CMS integration
_context = context;
}
public async Task<GetCategoriesResponseDto> Handle(GetCategoriesQuery request, CancellationToken cancellationToken)
{
// Stub implementation: returns empty list.
// When CMS protobuf package with Category support is available,
// this handler can be updated to call Category and PruductCategory services.
await Task.CompletedTask;
return new GetCategoriesResponseDto();
// Load all categories
var categoryRequest = new CMSCategory.GetAllCategoryByFilterRequest
{
Filter = new CMSCategory.GetAllCategoryByFilterFilter(),
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
{
PageNumber = 1,
PageSize = 1000
}
};
var categoriesResponse = await _context.Categories.GetAllCategoryByFilterAsync(categoryRequest, cancellationToken: cancellationToken);
var categories = categoriesResponse.Models ?? new();
// Load existing product-category relations for this product
var productCategoryRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
{
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
{
ProductId = request.ProductId
},
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
{
PageNumber = 1,
PageSize = 1000
}
};
var productCategoriesResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(productCategoryRequest, cancellationToken: cancellationToken);
var productCategories = productCategoriesResponse.Models ?? new();
var selectedIds = productCategories
.Select(pc => pc.CategoryId)
.ToHashSet();
var result = new GetCategoriesResponseDto
{
Items = categories
.Select(c => new CategoryItemDto
{
Id = c.Id,
Title = c.Title,
Selected = selectedIds.Contains(c.Id)
})
.ToList()
};
return result;
}
}

View File

@@ -9,6 +9,7 @@ using CMSMicroservice.Protobuf.Protos.Products;
using CMSMicroservice.Protobuf.Protos.ProductImages;
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
using CMSMicroservice.Protobuf.Protos.Category;
using CMSMicroservice.Protobuf.Protos.PruductCategory;
using FMSMicroservice.Protobuf.Protos.FileInfo;
using Microsoft.Extensions.DependencyInjection;
@@ -48,6 +49,7 @@ public class ApplicationContractContext : IApplicationContractContext
public ProductGallerysContract.ProductGallerysContractClient ProductGallerys => GetService<ProductGallerysContract.ProductGallerysContractClient>();
public RoleContract.RoleContractClient Roles => GetService<RoleContract.RoleContractClient>();
public CategoryContract.CategoryContractClient Categories => GetService<CategoryContract.CategoryContractClient>();
public PruductCategoryContract.PruductCategoryContractClient ProductCategories => GetService<PruductCategoryContract.PruductCategoryContractClient>();
public UserAddressContract.UserAddressContractClient UserAddress => GetService<UserAddressContract.UserAddressContractClient>();
public UserContract.UserContractClient Users => GetService<UserContract.UserContractClient>();
public UserOrderContract.UserOrderContractClient UserOrders => GetService<UserOrderContract.UserOrderContractClient>();