236 lines
9.1 KiB
C#
236 lines
9.1 KiB
C#
namespace CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetUserNetworkPosition;
|
|
|
|
public class GetUserNetworkPositionQueryHandler : IRequestHandler<GetUserNetworkPositionQuery, UserNetworkPositionDto?>
|
|
{
|
|
private readonly IApplicationDbContext _context;
|
|
|
|
public GetUserNetworkPositionQueryHandler(IApplicationDbContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
public async Task<UserNetworkPositionDto?> Handle(GetUserNetworkPositionQuery request, CancellationToken cancellationToken)
|
|
{
|
|
// واکشی اطلاعات اصلی کاربر
|
|
var user = await _context.Users
|
|
.AsNoTracking()
|
|
.Where(x => x.Id == request.UserId)
|
|
.Select(x => new
|
|
{
|
|
x.Id,
|
|
x.Mobile,
|
|
x.FirstName,
|
|
x.LastName,
|
|
x.Email,
|
|
x.NationalCode,
|
|
x.ReferralCode,
|
|
x.IsMobileVerified,
|
|
x.BirthDate,
|
|
x.NetworkParentId,
|
|
x.LegPosition,
|
|
x.HasReceivedDayaCredit,
|
|
x.DayaCreditReceivedAt,
|
|
x.PackagePurchaseMethod,
|
|
x.Created
|
|
})
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (user == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// اطلاعات والد
|
|
string? parentMobile = null;
|
|
string? parentFullName = null;
|
|
if (user.NetworkParentId.HasValue)
|
|
{
|
|
var parent = await _context.Users
|
|
.Where(x => x.Id == user.NetworkParentId)
|
|
.Select(x => new { x.Mobile, x.FirstName, x.LastName })
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (parent != null)
|
|
{
|
|
parentMobile = parent.Mobile;
|
|
parentFullName = $"{parent.FirstName} {parent.LastName}".Trim();
|
|
}
|
|
}
|
|
|
|
// شمارش فرزندان مستقیم
|
|
var directChildren = await _context.Users
|
|
.Where(x => x.NetworkParentId == request.UserId)
|
|
.Select(x => new { x.Id, x.LegPosition, x.FirstName, x.LastName, x.Mobile, x.Created })
|
|
.ToListAsync(cancellationToken);
|
|
|
|
var leftChild = directChildren.FirstOrDefault(x => x.LegPosition == NetworkLeg.Left);
|
|
var rightChild = directChildren.FirstOrDefault(x => x.LegPosition == NetworkLeg.Right);
|
|
|
|
// محاسبه تعداد کل اعضای هر شاخه (با استفاده از CTE برای عملکرد بهتر)
|
|
var leftLegCount = await GetLegMemberCountAsync(request.UserId, NetworkLeg.Left, cancellationToken);
|
|
var rightLegCount = await GetLegMemberCountAsync(request.UserId, NetworkLeg.Right, cancellationToken);
|
|
var totalNetworkSize = leftLegCount + rightLegCount;
|
|
|
|
// محاسبه حداکثر عمق شبکه
|
|
var maxDepth = await GetMaxNetworkDepthAsync(request.UserId, cancellationToken);
|
|
|
|
// آمار اعضای فعال/غیرفعال (کسانی که پکیج خریدهاند)
|
|
var allDescendantIds = await GetAllDescendantIdsAsync(request.UserId, cancellationToken);
|
|
var activeCount = await _context.Users
|
|
.CountAsync(x => allDescendantIds.Contains(x.Id) &&
|
|
x.PackagePurchaseMethod != PackagePurchaseMethod.None,
|
|
cancellationToken);
|
|
var inactiveCount = allDescendantIds.Count - activeCount;
|
|
|
|
// آمار کمیسیونهای کاربر
|
|
var commissionStats = await _context.UserCommissionPayouts
|
|
.Where(x => x.UserId == request.UserId)
|
|
.GroupBy(x => x.UserId)
|
|
.Select(g => new
|
|
{
|
|
TotalBalances = g.Sum(x => x.BalancesEarned),
|
|
TotalAmount = g.Sum(x => x.TotalAmount),
|
|
PaidAmount = g.Where(x => x.Status == CommissionPayoutStatus.Paid).Sum(x => x.TotalAmount),
|
|
PendingAmount = g.Where(x => x.Status == CommissionPayoutStatus.Pending).Sum(x => x.TotalAmount)
|
|
})
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
return new UserNetworkPositionDto
|
|
{
|
|
// اطلاعات اصلی
|
|
UserId = user.Id,
|
|
Mobile = user.Mobile,
|
|
FirstName = user.FirstName,
|
|
LastName = user.LastName,
|
|
Email = user.Email,
|
|
NationalCode = user.NationalCode,
|
|
ReferralCode = user.ReferralCode,
|
|
IsMobileVerified = user.IsMobileVerified,
|
|
BirthDate = user.BirthDate,
|
|
JoinedAt = user.Created,
|
|
|
|
// اطلاعات شبکه
|
|
NetworkParentId = user.NetworkParentId,
|
|
ParentMobile = parentMobile,
|
|
ParentFullName = parentFullName,
|
|
LegPosition = user.LegPosition,
|
|
IsInNetwork = user.NetworkParentId.HasValue,
|
|
|
|
// آمار فرزندان مستقیم
|
|
TotalChildren = directChildren.Count,
|
|
LeftChildCount = leftChild != null ? 1 : 0,
|
|
RightChildCount = rightChild != null ? 1 : 0,
|
|
|
|
// اطلاعات فرزند چپ
|
|
LeftChildId = leftChild?.Id,
|
|
LeftChildFullName = leftChild != null ? $"{leftChild.FirstName} {leftChild.LastName}".Trim() : null,
|
|
LeftChildMobile = leftChild?.Mobile,
|
|
LeftChildJoinedAt = leftChild?.Created,
|
|
|
|
// اطلاعات فرزند راست
|
|
RightChildId = rightChild?.Id,
|
|
RightChildFullName = rightChild != null ? $"{rightChild.FirstName} {rightChild.LastName}".Trim() : null,
|
|
RightChildMobile = rightChild?.Mobile,
|
|
RightChildJoinedAt = rightChild?.Created,
|
|
|
|
// آمار کل شبکه
|
|
TotalLeftLegMembers = leftLegCount,
|
|
TotalRightLegMembers = rightLegCount,
|
|
TotalNetworkSize = totalNetworkSize,
|
|
MaxNetworkDepth = maxDepth,
|
|
|
|
// اطلاعات پکیج و دایا
|
|
HasReceivedDayaCredit = user.HasReceivedDayaCredit,
|
|
DayaCreditReceivedAt = user.DayaCreditReceivedAt,
|
|
PackagePurchaseMethod = user.PackagePurchaseMethod,
|
|
HasPurchasedGoldenPackage = user.PackagePurchaseMethod != PackagePurchaseMethod.None,
|
|
|
|
// آمار مالی
|
|
TotalEarnedCommission = commissionStats?.TotalAmount ?? 0,
|
|
TotalPaidCommission = commissionStats?.PaidAmount ?? 0,
|
|
PendingCommission = commissionStats?.PendingAmount ?? 0,
|
|
TotalBalancesEarned = commissionStats?.TotalBalances ?? 0,
|
|
|
|
// آمار فعالیت
|
|
ActiveMembersInNetwork = activeCount,
|
|
InactiveMembersInNetwork = inactiveCount
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// محاسبه تعداد اعضای یک شاخه (چپ یا راست) به صورت بازگشتی
|
|
/// </summary>
|
|
private async Task<int> GetLegMemberCountAsync(long userId, NetworkLeg leg, CancellationToken cancellationToken)
|
|
{
|
|
var directChild = await _context.Users
|
|
.Where(x => x.NetworkParentId == userId && x.LegPosition == leg)
|
|
.Select(x => x.Id)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
|
|
if (directChild == 0)
|
|
return 0;
|
|
|
|
// تعداد کل زیرمجموعه این فرزند + خود فرزند
|
|
var descendants = await GetAllDescendantIdsAsync(directChild, cancellationToken);
|
|
return descendants.Count + 1; // +1 برای خود فرزند
|
|
}
|
|
|
|
/// <summary>
|
|
/// محاسبه حداکثر عمق شبکه
|
|
/// </summary>
|
|
private async Task<int> GetMaxNetworkDepthAsync(long userId, CancellationToken cancellationToken)
|
|
{
|
|
var maxDepth = 0;
|
|
var currentLevelIds = new List<long> { userId };
|
|
|
|
while (currentLevelIds.Any())
|
|
{
|
|
var nextLevelIds = await _context.Users
|
|
.Where(x => currentLevelIds.Contains(x.NetworkParentId ?? 0))
|
|
.Select(x => x.Id)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (nextLevelIds.Any())
|
|
{
|
|
maxDepth++;
|
|
currentLevelIds = nextLevelIds;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return maxDepth;
|
|
}
|
|
|
|
/// <summary>
|
|
/// دریافت تمام ID های زیرمجموعه یک کاربر
|
|
/// </summary>
|
|
private async Task<List<long>> GetAllDescendantIdsAsync(long userId, CancellationToken cancellationToken)
|
|
{
|
|
var allDescendants = new List<long>();
|
|
var currentLevelIds = new List<long> { userId };
|
|
|
|
while (currentLevelIds.Any())
|
|
{
|
|
var children = await _context.Users
|
|
.Where(x => currentLevelIds.Contains(x.NetworkParentId ?? 0))
|
|
.Select(x => x.Id)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (children.Any())
|
|
{
|
|
allDescendants.AddRange(children);
|
|
currentLevelIds = children;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return allDescendants;
|
|
}
|
|
}
|