From 7e9110b70769f4c0d7237e4cebf117beaad106df Mon Sep 17 00:00:00 2001 From: DeepnaPooja Date: Tue, 8 Sep 2026 11:45:15 +0530 Subject: [PATCH] Enhance category and sub-category update requests to include IsActive flag and deletes and inactive categories --- .../Features/Category/CategoryDTOs.cs | 4 +-- .../Features/Category/CategoryService.cs | 35 ++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Distribution/Features/Category/CategoryDTOs.cs b/Distribution/Features/Category/CategoryDTOs.cs index 7c3f361..181fddc 100644 --- a/Distribution/Features/Category/CategoryDTOs.cs +++ b/Distribution/Features/Category/CategoryDTOs.cs @@ -1,9 +1,9 @@ namespace Distribution.Features.Category; public record CreateCategoryRequest(string Name); -public record UpdateCategoryRequest(string Name); +public record UpdateCategoryRequest(string Name, bool IsActive = true); public record CreateSubCategoryRequest(string Name); -public record UpdateSubCategoryRequest(string Name); +public record UpdateSubCategoryRequest(string Name, bool IsActive = true); public record SubCategoryResponse(Guid Id, string Name, bool IsActive, DateTime CreatedAt); public record CategorySummaryResponse(Guid Id, string Name, bool IsActive, DateTime CreatedAt); diff --git a/Distribution/Features/Category/CategoryService.cs b/Distribution/Features/Category/CategoryService.cs index 7dc6c2f..b6df026 100644 --- a/Distribution/Features/Category/CategoryService.cs +++ b/Distribution/Features/Category/CategoryService.cs @@ -4,18 +4,27 @@ namespace Distribution.Features.Category; public class CategoryService(ICategoryRepository categoryRepo, ISubCategoryRepository subCategoryRepo, IUnitOfWork uow) { - public async Task> GetAllAsync() => - (await categoryRepo.GetAllAsync()) - .Where(c => c.IsActive) - .Select(c => new CategorySummaryResponse(c.Id, c.Name, c.IsActive, c.CreatedAt)) - .ToList(); + public async Task> GetAllAsync() + { + // Deleted categories/sub-categories stay IsActive=false but remain visible showing + // Inactive — delete never removes the row, only marks it (same rule as Orders/Stores/Items). + var categoryList = await categoryRepo.GetAllAsync(); + var result = new List(); + foreach (var category in categoryList) + { + var subs = (await subCategoryRepo.GetByCategoryIdAsync(category.Id)) + .Select(s => new SubCategoryResponse(s.Id, s.Name, s.IsActive, s.CreatedAt)) + .ToList(); + result.Add(new CategoryResponse(category.Id, category.Name, category.IsActive, category.CreatedAt, subs)); + } + return result; + } public async Task GetByIdAsync(Guid id) { var category = await categoryRepo.GetByIdAsync(id); - if (category is null || !category.IsActive) return null; + if (category is null) return null; var subs = (await subCategoryRepo.GetByCategoryIdAsync(id)) - .Where(s => s.IsActive) .Select(s => new SubCategoryResponse(s.Id, s.Name, s.IsActive, s.CreatedAt)) .ToList(); return new CategoryResponse(category.Id, category.Name, category.IsActive, category.CreatedAt, subs); @@ -33,9 +42,10 @@ public class CategoryService(ICategoryRepository categoryRepo, ISubCategoryRepos public async Task UpdateAsync(Guid id, UpdateCategoryRequest request, CancellationToken ct = default) { var category = await categoryRepo.GetByIdAsync(id); - if (category is null || !category.IsActive) return null; + if (category is null) return null; if (category.ExternalErpId.HasValue) return null; category.Name = request.Name; + category.IsActive = request.IsActive; await uow.BeginAsync(ct); try { categoryRepo.Update(category); await uow.CommitAsync(ct); } catch { await uow.RollbackAsync(ct); throw; } @@ -44,11 +54,11 @@ public class CategoryService(ICategoryRepository categoryRepo, ISubCategoryRepos public async Task DeleteAsync(Guid id, CancellationToken ct = default) { + // Soft-delete only — never blocked by child sub-categories/items, same rule as + // Items/Stores/Orders. The row stays visible showing Inactive. var category = await categoryRepo.GetByIdAsync(id); if (category is null || !category.IsActive) return false; if (category.ExternalErpId.HasValue) return false; - if (await categoryRepo.HasActiveSubCategoriesAsync(id)) return false; - if (await categoryRepo.HasActiveItemsAsync(id)) return false; await uow.BeginAsync(ct); try { categoryRepo.Remove(category); await uow.CommitAsync(ct); } catch { await uow.RollbackAsync(ct); throw; } @@ -69,9 +79,10 @@ public class CategoryService(ICategoryRepository categoryRepo, ISubCategoryRepos public async Task UpdateSubCategoryAsync(Guid id, UpdateSubCategoryRequest request, CancellationToken ct = default) { var sub = await subCategoryRepo.GetByIdAsync(id); - if (sub is null || !sub.IsActive) return null; + if (sub is null) return null; if (sub.ExternalErpId.HasValue) return null; sub.Name = request.Name; + sub.IsActive = request.IsActive; await uow.BeginAsync(ct); try { subCategoryRepo.Update(sub); await uow.CommitAsync(ct); } catch { await uow.RollbackAsync(ct); throw; } @@ -80,10 +91,10 @@ public class CategoryService(ICategoryRepository categoryRepo, ISubCategoryRepos public async Task DeleteSubCategoryAsync(Guid id, CancellationToken ct = default) { + // Soft-delete only — never blocked by child items, same rule as the parent category. var sub = await subCategoryRepo.GetByIdAsync(id); if (sub is null || !sub.IsActive) return false; if (sub.ExternalErpId.HasValue) return false; - if (await subCategoryRepo.HasActiveItemsAsync(id)) return false; await uow.BeginAsync(ct); try { subCategoryRepo.Remove(sub); await uow.CommitAsync(ct); } catch { await uow.RollbackAsync(ct); throw; }