feat: add club membership filters and activation details to network tree
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 2m13s

This commit is contained in:
masoodafar-web
2025-12-14 02:56:04 +03:30
parent 6ae1b0cd70
commit cf75f14003
6 changed files with 199 additions and 14 deletions
@@ -14,4 +14,14 @@ public record GetNetworkTreeQuery : IRequest<NetworkTreeDto?>
/// تعداد سطوح (Depth) که می‌خواهیم نمایش دهیم (پیش‌فرض: 3)
/// </summary>
public int MaxDepth { get; init; } = 3;
/// <summary>
/// فیلتر براساس وضعیت فعال بودن باشگاه مشتریان
/// </summary>
public bool? IsClubActive { get; init; }
/// <summary>
/// فیلتر براساس شماره هفته فعالسازی (مثال: 2025-W05)
/// </summary>
public string? ActivationWeekNumber { get; init; }
}
@@ -20,11 +20,11 @@ public class GetNetworkTreeQueryHandler : IRequestHandler<GetNetworkTreeQuery, N
return null;
}
var tree = await BuildTree(rootUser.Id, request.MaxDepth, 0, cancellationToken);
var tree = await BuildTree(rootUser.Id, request.MaxDepth, 0, cancellationToken, request);
return tree;
}
private async Task<NetworkTreeDto> BuildTree(long userId, int maxDepth, int currentDepth, CancellationToken cancellationToken)
private async Task<NetworkTreeDto> BuildTree(long userId, int maxDepth, int currentDepth, CancellationToken cancellationToken, GetNetworkTreeQuery request)
{
var user = await _context.Users
.AsNoTracking()
@@ -35,6 +35,25 @@ public class GetNetworkTreeQueryHandler : IRequestHandler<GetNetworkTreeQuery, N
throw new NotFoundException(nameof(User), userId);
}
// دریافت اطلاعات باشگاه مشتریان
var clubMembership = await _context.ClubMemberships
.AsNoTracking()
.FirstOrDefaultAsync(x => x.UserId == userId && x.IsDeleted == false, cancellationToken);
// محاسبه شماره هفته فعال‌سازی
string? activationWeekNumber = null;
if (clubMembership?.ActivatedAt != null)
{
var activatedAt = clubMembership.ActivatedAt.Value;
var year = activatedAt.Year;
var jan1 = new DateTime(year, 1, 1);
var daysToFirstSaturday = (7 - (int)jan1.DayOfWeek + 7) % 7;
if (jan1.DayOfWeek == DayOfWeek.Saturday) daysToFirstSaturday = 0;
var firstSaturday = jan1.AddDays(daysToFirstSaturday);
var weekNum = activatedAt < firstSaturday ? 1 : ((activatedAt - firstSaturday).Days / 7) + 1;
activationWeekNumber = $"{year}-W{weekNum:D2}";
}
var node = new NetworkTreeDto
{
UserId = user.Id,
@@ -42,7 +61,11 @@ public class GetNetworkTreeQueryHandler : IRequestHandler<GetNetworkTreeQuery, N
FirstName = user.FirstName,
LastName = user.LastName,
LegPosition = user.LegPosition,
CurrentDepth = currentDepth
CurrentDepth = currentDepth,
ClubActivatedAt = clubMembership?.ActivatedAt,
IsClubActive = clubMembership?.IsActive ?? false,
ActivationWeekNumber = activationWeekNumber,
UserCreated = user.Created
};
// اگر به حداکثر عمق رسیدیم، دیگر فرزندان را نمی‌خوانیم
@@ -52,27 +75,138 @@ public class GetNetworkTreeQueryHandler : IRequestHandler<GetNetworkTreeQuery, N
}
// پیدا کردن فرزند چپ
var leftChild = await _context.Users
var leftChildQuery = _context.Users
.AsNoTracking()
.FirstOrDefaultAsync(x => x.NetworkParentId == userId && x.LegPosition == NetworkLeg.Left,
cancellationToken);
.Where(x => x.NetworkParentId == userId && x.LegPosition == NetworkLeg.Left);
// اعمال فیلتر IsClubActive
if (request.IsClubActive.HasValue)
{
var activeUserIds = await _context.ClubMemberships
.AsNoTracking()
.Where(cm => cm.IsActive == request.IsClubActive.Value && cm.IsDeleted == false)
.Select(cm => cm.UserId)
.ToListAsync(cancellationToken);
leftChildQuery = leftChildQuery.Where(u => activeUserIds.Contains(u.Id));
}
// اعمال فیلتر ActivationWeekNumber
if (!string.IsNullOrEmpty(request.ActivationWeekNumber))
{
var (startDate, endDate) = ParseWeekNumber(request.ActivationWeekNumber);
if (startDate.HasValue && endDate.HasValue)
{
var weekUserIds = await _context.ClubMemberships
.AsNoTracking()
.Where(cm => cm.IsDeleted == false
&& cm.ActivatedAt != null
&& cm.ActivatedAt >= startDate.Value
&& cm.ActivatedAt < endDate.Value)
.Select(cm => cm.UserId)
.ToListAsync(cancellationToken);
leftChildQuery = leftChildQuery.Where(u => weekUserIds.Contains(u.Id));
}
}
var leftChild = await leftChildQuery.FirstOrDefaultAsync(cancellationToken);
if (leftChild != null)
{
node.LeftChild = await BuildTree(leftChild.Id, maxDepth, currentDepth + 1, cancellationToken);
node.LeftChild = await BuildTree(leftChild.Id, maxDepth, currentDepth + 1, cancellationToken, request);
}
// پیدا کردن فرزند راست
var rightChild = await _context.Users
var rightChildQuery = _context.Users
.AsNoTracking()
.FirstOrDefaultAsync(x => x.NetworkParentId == userId && x.LegPosition == NetworkLeg.Right,
cancellationToken);
.Where(x => x.NetworkParentId == userId && x.LegPosition == NetworkLeg.Right);
// اعمال فیلتر IsClubActive
if (request.IsClubActive.HasValue)
{
var activeUserIds = await _context.ClubMemberships
.AsNoTracking()
.Where(cm => cm.IsActive == request.IsClubActive.Value && cm.IsDeleted == false)
.Select(cm => cm.UserId)
.ToListAsync(cancellationToken);
rightChildQuery = rightChildQuery.Where(u => activeUserIds.Contains(u.Id));
}
// اعمال فیلتر ActivationWeekNumber
if (!string.IsNullOrEmpty(request.ActivationWeekNumber))
{
var (startDate, endDate) = ParseWeekNumber(request.ActivationWeekNumber);
if (startDate.HasValue && endDate.HasValue)
{
var weekUserIds = await _context.ClubMemberships
.AsNoTracking()
.Where(cm => cm.IsDeleted == false
&& cm.ActivatedAt != null
&& cm.ActivatedAt >= startDate.Value
&& cm.ActivatedAt < endDate.Value)
.Select(cm => cm.UserId)
.ToListAsync(cancellationToken);
rightChildQuery = rightChildQuery.Where(u => weekUserIds.Contains(u.Id));
}
}
var rightChild = await rightChildQuery.FirstOrDefaultAsync(cancellationToken);
if (rightChild != null)
{
node.RightChild = await BuildTree(rightChild.Id, maxDepth, currentDepth + 1, cancellationToken);
node.RightChild = await BuildTree(rightChild.Id, maxDepth, currentDepth + 1, cancellationToken, request);
}
return node;
}
/// <summary>
/// تبدیل شماره هفته (مثلاً 2025-W05) به تاریخ شروع و پایان هفته
/// </summary>
private static (DateTime? StartDate, DateTime? EndDate) ParseWeekNumber(string weekNumber)
{
try
{
// فرمت: YYYY-W##
var parts = weekNumber.Split('-');
if (parts.Length != 2 || !parts[1].StartsWith("W"))
return (null, null);
if (!int.TryParse(parts[0], out var year))
return (null, null);
if (!int.TryParse(parts[1].Substring(1), out var weekNum))
return (null, null);
// محاسبه اولین شنبه سال
var jan1 = new DateTime(year, 1, 1);
var daysToFirstSaturday = (7 - (int)jan1.DayOfWeek + 7) % 7;
if (jan1.DayOfWeek == DayOfWeek.Saturday)
daysToFirstSaturday = 0;
var firstSaturday = jan1.AddDays(daysToFirstSaturday);
// محاسبه تاریخ شروع هفته مورد نظر
DateTime startDate;
if (weekNum == 1)
{
startDate = firstSaturday;
}
else
{
startDate = firstSaturday.AddDays((weekNum - 1) * 7);
}
var endDate = startDate.AddDays(7);
return (startDate, endDate);
}
catch
{
return (null, null);
}
}
}
@@ -11,6 +11,27 @@ public class NetworkTreeDto
public string? LastName { get; set; }
public NetworkLeg? LegPosition { get; set; }
public int CurrentDepth { get; set; }
/// <summary>
/// تاریخ فعال‌سازی در باشگاه مشتریان
/// </summary>
public DateTime? ClubActivatedAt { get; set; }
/// <summary>
/// وضعیت فعال بودن در باشگاه مشتریان
/// </summary>
public bool IsClubActive { get; set; }
/// <summary>
/// شماره هفته فعال‌سازی
/// </summary>
public string? ActivationWeekNumber { get; set; }
/// <summary>
/// تاریخ ایجاد کاربر
/// </summary>
public DateTimeOffset UserCreated { get; set; }
public NetworkTreeDto? LeftChild { get; set; }
public NetworkTreeDto? RightChild { get; set; }
}