feat: Add ClubMembershipCQ - Phase 3 Application Layer
- Implemented 3 Commands with handlers and validators: * ActivateClubMembership: Create/reactivate membership * DeactivateClubMembership: Deactivate existing membership * AssignClubFeature: Assign features to club members - Implemented 3 Queries with handlers, validators, and DTOs: * GetClubMembership: Retrieve single membership by UserId * GetAllClubMemberships: List with filtering and pagination * GetClubMembershipHistory: Audit trail with full history - All operations include history tracking via ClubMembershipHistory - Property names aligned with Domain entity definitions - 21 new files, ~600 lines of code - Build successful with 0 errors
This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
||||
namespace CMSMicroservice.Application.ClubMembershipCQ.Queries.GetAllClubMemberships;
|
||||
|
||||
/// <summary>
|
||||
/// Query برای دریافت لیست عضویتهای باشگاه
|
||||
/// </summary>
|
||||
public record GetAllClubMembershipsQuery : IRequest<GetAllClubMembershipsResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// موقعیت صفحهبندی
|
||||
/// </summary>
|
||||
public PaginationState? PaginationState { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// مرتبسازی بر اساس
|
||||
/// </summary>
|
||||
public string? SortBy { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// فیلتر
|
||||
/// </summary>
|
||||
public GetAllClubMembershipsFilter? Filter { get; init; }
|
||||
}
|
||||
|
||||
public class GetAllClubMembershipsFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// فیلتر بر اساس شناسه کاربر
|
||||
/// </summary>
|
||||
public long? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// فقط عضویتهای فعال
|
||||
/// </summary>
|
||||
public bool? IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// فیلتر بر اساس تاریخ فعالسازی (از)
|
||||
/// </summary>
|
||||
public DateTimeOffset? ActivationDateFrom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// فیلتر بر اساس تاریخ فعالسازی (تا)
|
||||
/// </summary>
|
||||
public DateTimeOffset? ActivationDateTo { get; set; }
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
namespace CMSMicroservice.Application.ClubMembershipCQ.Queries.GetAllClubMemberships;
|
||||
|
||||
public class GetAllClubMembershipsQueryHandler : IRequestHandler<GetAllClubMembershipsQuery, GetAllClubMembershipsResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public GetAllClubMembershipsQueryHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetAllClubMembershipsResponseDto> Handle(GetAllClubMembershipsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.ClubMemberships
|
||||
.ApplyOrder(sortBy: request.SortBy)
|
||||
.AsNoTracking()
|
||||
.AsQueryable();
|
||||
|
||||
if (request.Filter is not null)
|
||||
{
|
||||
query = query
|
||||
.Where(x => request.Filter.UserId == null || x.UserId == request.Filter.UserId)
|
||||
.Where(x => request.Filter.IsActive == null || x.IsActive == request.Filter.IsActive)
|
||||
.Where(x => request.Filter.ActivationDateFrom == null || x.ActivatedAt >= request.Filter.ActivationDateFrom)
|
||||
.Where(x => request.Filter.ActivationDateTo == null || x.ActivatedAt <= request.Filter.ActivationDateTo);
|
||||
}
|
||||
|
||||
var meta = await query.GetMetaData(request.PaginationState, cancellationToken);
|
||||
|
||||
var models = await query
|
||||
.PaginatedListAsync(paginationState: request.PaginationState)
|
||||
.Select(x => new GetAllClubMembershipsResponseModel
|
||||
{
|
||||
Id = x.Id,
|
||||
UserId = x.UserId,
|
||||
IsActive = x.IsActive,
|
||||
ActivatedAt = x.ActivatedAt,
|
||||
InitialContribution = x.InitialContribution,
|
||||
TotalEarned = x.TotalEarned,
|
||||
Created = x.Created,
|
||||
LastModified = x.LastModified
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return new GetAllClubMembershipsResponseDto
|
||||
{
|
||||
MetaData = meta,
|
||||
Models = models
|
||||
};
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
namespace CMSMicroservice.Application.ClubMembershipCQ.Queries.GetAllClubMemberships;
|
||||
|
||||
public class GetAllClubMembershipsQueryValidator : AbstractValidator<GetAllClubMembershipsQuery>
|
||||
{
|
||||
public GetAllClubMembershipsQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.Filter.UserId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه کاربر معتبر نیست")
|
||||
.When(x => x.Filter?.UserId != null);
|
||||
|
||||
RuleFor(x => x.Filter.ActivationDateTo)
|
||||
.GreaterThanOrEqualTo(x => x.Filter.ActivationDateFrom)
|
||||
.WithMessage("تاریخ پایان باید بعد از تاریخ شروع باشد")
|
||||
.When(x => x.Filter?.ActivationDateFrom != null && x.Filter?.ActivationDateTo != null);
|
||||
}
|
||||
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(
|
||||
ValidationContext<GetAllClubMembershipsQuery>.CreateWithOptions(
|
||||
(GetAllClubMembershipsQuery)model,
|
||||
x => x.IncludeProperties(propertyName)));
|
||||
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
namespace CMSMicroservice.Application.ClubMembershipCQ.Queries.GetAllClubMemberships;
|
||||
|
||||
public class GetAllClubMembershipsResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public List<GetAllClubMembershipsResponseModel> Models { get; set; }
|
||||
}
|
||||
|
||||
public class GetAllClubMembershipsResponseModel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long UserId { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public DateTime? ActivatedAt { get; set; }
|
||||
public long InitialContribution { get; set; }
|
||||
public long TotalEarned { get; set; }
|
||||
public DateTimeOffset Created { get; set; }
|
||||
public DateTimeOffset? LastModified { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user