Add validators and services for Product Galleries and Product Tags

- Implemented Create, Delete, Get, and Update validators for Product Galleries.
- Added Create, Delete, Get, and Update validators for Product Tags.
- Created service classes for handling Discount Categories, Discount Orders, Discount Products, Discount Shopping Cart, Product Categories, Product Galleries, and Product Tags.
- Each service class integrates with CQRS for command and query handling.
- Established mapping profiles for Product Galleries.
This commit is contained in:
masoodafar-web
2025-12-04 02:40:49 +03:30
parent 40d54d08fc
commit f0f48118e7
436 changed files with 33159 additions and 2005 deletions

View File

@@ -14,7 +14,7 @@ public class ClearCartCommandHandler : IRequestHandler<ClearCartCommand, ClearCa
public async Task<ClearCartResponseDto> Handle(ClearCartCommand request, CancellationToken cancellationToken)
{
// پیدا کردن تمام آیتم‌های سبد خرید کاربر
var cartItems = await _context.UserCartss
var cartItems = await _context.UserCarts
.Where(c => c.UserId == request.UserId)
.ToListAsync(cancellationToken);
@@ -31,7 +31,7 @@ public class ClearCartCommandHandler : IRequestHandler<ClearCartCommand, ClearCa
var itemsCount = cartItems.Count;
// حذف تمام آیتم‌ها
_context.UserCartss.RemoveRange(cartItems);
_context.UserCarts.RemoveRange(cartItems);
// ثبت Event
// می‌تونیم یک Event برای هر آیتم یا یک Event کلی بفرستیم

View File

@@ -12,18 +12,18 @@ public class CreateNewUserCartsCommandHandler : IRequestHandler<CreateNewUserCar
public async Task<CreateNewUserCartsResponseDto> Handle(CreateNewUserCartsCommand request,
CancellationToken cancellationToken)
{
var entity = request.Adapt<UserCarts>();
var existingUserCart = await _context.UserCartss
var entity = request.Adapt<UserCart>();
var existingUserCart = await _context.UserCarts
.FirstOrDefaultAsync(x => x.UserId == entity.UserId && x.ProductId == entity.ProductId && !x.IsDeleted, cancellationToken);
if (existingUserCart != null)
{
existingUserCart.Count += entity.Count;
_context.UserCartss.Update(existingUserCart);
_context.UserCarts.Update(existingUserCart);
existingUserCart.AddDomainEvent(new UpdateUserCartsEvent(existingUserCart));
await _context.SaveChangesAsync(cancellationToken);
return existingUserCart.Adapt<CreateNewUserCartsResponseDto>();
}
await _context.UserCartss.AddAsync(entity, cancellationToken);
await _context.UserCarts.AddAsync(entity, cancellationToken);
entity.AddDomainEvent(new CreateNewUserCartsEvent(entity));
await _context.SaveChangesAsync(cancellationToken);
return entity.Adapt<CreateNewUserCartsResponseDto>();

View File

@@ -11,10 +11,10 @@ public class DeleteUserCartsCommandHandler : IRequestHandler<DeleteUserCartsComm
public async Task<Unit> Handle(DeleteUserCartsCommand request, CancellationToken cancellationToken)
{
var entity = await _context.UserCartss
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserCarts), request.Id);
var entity = await _context.UserCarts
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserCart), request.Id);
entity.IsDeleted = true;
_context.UserCartss.Update(entity);
_context.UserCarts.Update(entity);
entity.AddDomainEvent(new DeleteUserCartsEvent(entity));
await _context.SaveChangesAsync(cancellationToken);
return Unit.Value;

View File

@@ -0,0 +1,23 @@
namespace CMSMicroservice.Application.UserCartsCQ.Commands.MergeCart;
/// <summary>
/// Command برای ادغام سبد خرید مهمان با سبد خرید کاربر بعد از ورود
/// </summary>
public record MergeCartCommand : IRequest<MergeCartResponseDto>
{
/// <summary>
/// شناسه کاربر (بعد از Login)
/// </summary>
public long UserId { get; init; }
/// <summary>
/// لیست محصولات سبد مهمان
/// </summary>
public List<GuestCartItem> GuestCartItems { get; init; } = new();
}
public class GuestCartItem
{
public long ProductId { get; set; }
public int Count { get; set; }
}

View File

@@ -0,0 +1,97 @@
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities;
using Microsoft.EntityFrameworkCore;
namespace CMSMicroservice.Application.UserCartsCQ.Commands.MergeCart;
public class MergeCartCommandHandler : IRequestHandler<MergeCartCommand, MergeCartResponseDto>
{
private readonly IApplicationDbContext _context;
public MergeCartCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<MergeCartResponseDto> Handle(MergeCartCommand request, CancellationToken cancellationToken)
{
// بررسی وجود کاربر
var user = await _context.Users
.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken);
if (user == null)
{
return new MergeCartResponseDto
{
Success = false,
Message = "کاربر یافت نشد"
};
}
// دریافت سبد فعلی کاربر
var existingCartItems = await _context.UserCarts
.Where(c => c.UserId == request.UserId && !c.IsDeleted)
.ToListAsync(cancellationToken);
int mergedCount = 0;
// ادغام آیتم‌های مهمان با سبد کاربر
foreach (var guestItem in request.GuestCartItems)
{
// بررسی موجود بودن محصول
var product = await _context.Products
.FirstOrDefaultAsync(p => p.Id == guestItem.ProductId && !p.IsDeleted, cancellationToken);
if (product == null)
continue; // محصول پیدا نشد یا حذف شده
// بررسی موجودی
if (product.RemainingCount < guestItem.Count)
continue; // موجودی کافی نیست
// چک کردن آیا این محصول قبلاً در سبد کاربر هست
var existingItem = existingCartItems.FirstOrDefault(c => c.ProductId == guestItem.ProductId);
if (existingItem != null)
{
// آیتم موجود است → افزایش تعداد
existingItem.Count += guestItem.Count;
// محدود کردن به موجودی
if (existingItem.Count > product.RemainingCount)
existingItem.Count = product.RemainingCount;
_context.UserCarts.Update(existingItem);
}
else
{
// آیتم جدید → اضافه کردن به سبد
var newCartItem = new UserCart
{
UserId = request.UserId,
ProductId = guestItem.ProductId,
Count = Math.Min(guestItem.Count, product.RemainingCount)
};
await _context.UserCarts.AddAsync(newCartItem, cancellationToken);
}
mergedCount++;
}
await _context.SaveChangesAsync(cancellationToken);
// محاسبه تعداد کل آیتم‌های سبد بعد از ادغام
var totalItems = await _context.UserCarts
.Where(c => c.UserId == request.UserId && !c.IsDeleted)
.CountAsync(cancellationToken);
return new MergeCartResponseDto
{
Success = true,
Message = $"{mergedCount} محصول با موفقیت به سبد خرید اضافه شد",
MergedItemsCount = mergedCount,
TotalCartItems = totalItems
};
}
}

View File

@@ -0,0 +1,31 @@
using FluentValidation;
namespace CMSMicroservice.Application.UserCartsCQ.Commands.MergeCart;
public class MergeCartCommandValidator : AbstractValidator<MergeCartCommand>
{
public MergeCartCommandValidator()
{
RuleFor(x => x.UserId)
.GreaterThan(0)
.WithMessage("شناسه کاربر نامعتبر است");
RuleFor(x => x.GuestCartItems)
.NotNull()
.WithMessage("لیست آیتم‌های سبد خرید نباید خالی باشد");
RuleForEach(x => x.GuestCartItems)
.ChildRules(item =>
{
item.RuleFor(i => i.ProductId)
.GreaterThan(0)
.WithMessage("شناسه محصول نامعتبر است");
item.RuleFor(i => i.Count)
.GreaterThan(0)
.WithMessage("تعداد باید بیشتر از صفر باشد")
.LessThanOrEqualTo(100)
.WithMessage("حداکثر تعداد مجاز 100 عدد است");
});
}
}

View File

@@ -0,0 +1,9 @@
namespace CMSMicroservice.Application.UserCartsCQ.Commands.MergeCart;
public class MergeCartResponseDto
{
public bool Success { get; set; }
public string Message { get; set; }
public int MergedItemsCount { get; set; }
public int TotalCartItems { get; set; }
}

View File

@@ -18,10 +18,10 @@ public class UpdateUserCartsCommandHandler : IRequestHandler<UpdateUserCartsComm
{
await _sender.Send(request.Adapt<DeleteUserCartsCommand>(), cancellationToken);
}
var entity = await _context.UserCartss
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserCarts), request.Id);
var entity = await _context.UserCarts
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserCart), request.Id);
request.Adapt(entity);
_context.UserCartss.Update(entity);
_context.UserCarts.Update(entity);
entity.AddDomainEvent(new UpdateUserCartsEvent(entity));
await _context.SaveChangesAsync(cancellationToken);
return Unit.Value;

View File

@@ -10,7 +10,7 @@ public class GetAllUserCartsByFilterQueryHandler : IRequestHandler<GetAllUserCar
public async Task<GetAllUserCartsByFilterResponseDto> Handle(GetAllUserCartsByFilterQuery request, CancellationToken cancellationToken)
{
var query = _context.UserCartss.Include(i=>i.Product)
var query = _context.UserCarts.Include(i=>i.Product)
.ApplyOrder(sortBy: request.SortBy)
.AsNoTracking()
.AsQueryable();

View File

@@ -11,12 +11,12 @@ public class GetUserCartsQueryHandler : IRequestHandler<GetUserCartsQuery, GetUs
public async Task<GetUserCartsResponseDto> Handle(GetUserCartsQuery request,
CancellationToken cancellationToken)
{
var response = await _context.UserCartss
var response = await _context.UserCarts
.AsNoTracking()
.Where(x => x.Id == request.Id)
.ProjectToType<GetUserCartsResponseDto>()
.FirstOrDefaultAsync(cancellationToken);
return response ?? throw new NotFoundException(nameof(UserCarts), request.Id);
return response ?? throw new NotFoundException(nameof(UserCart), request.Id);
}
}