feat: Enhance withdrawal request handling with additional fields and network level configurations

This commit is contained in:
masoodafar-web
2025-12-04 19:53:30 +03:30
parent 5e3112d71f
commit ee1fa9d064
7 changed files with 221 additions and 39 deletions

View File

@@ -37,24 +37,75 @@ public class ProcessUserPayoutsCommandHandler : IRequestHandler<ProcessUserPayou
await _context.SaveChangesAsync(cancellationToken);
}
// دریافت تعادل‌های هفتگی
var weeklyBalances = await _context.NetworkWeeklyBalances
// ⭐ خواندن MaxNetworkLevel از Config
var maxNetworkLevelConfig = await _context.SystemConfigurations
.Where(x => x.Key == "Commission.MaxNetworkLevel" && x.IsActive)
.Select(x => x.Value)
.FirstOrDefaultAsync(cancellationToken);
var maxNetworkLevel = int.Parse(maxNetworkLevelConfig ?? "15");
// دریافت همه تعادل‌های هفتگی (شامل صفرها هم برای محاسبه زیرمجموعه)
var allWeeklyBalances = await _context.NetworkWeeklyBalances
.Where(x => x.WeekNumber == request.WeekNumber)
.ToDictionaryAsync(x => x.UserId, cancellationToken);
// دریافت کاربرانی که تعادل > 0 دارند (یا زیرمجموعه‌شان دارد)
var usersWithBalances = await _context.NetworkWeeklyBalances
.Where(x => x.WeekNumber == request.WeekNumber && x.TotalBalances > 0)
.Select(x => x.UserId)
.ToListAsync(cancellationToken);
// پیدا کردن تمام کاربرانی که باید کمیسیون بگیرند (شامل والدین)
var usersToProcess = new HashSet<long>(usersWithBalances);
// اضافه کردن والدین تا 15 لول بالاتر
foreach (var userId in usersWithBalances)
{
var ancestors = await GetAncestors(userId, maxNetworkLevel, cancellationToken);
foreach (var ancestorId in ancestors)
{
usersToProcess.Add(ancestorId);
}
}
var payoutsList = new List<UserCommissionPayout>();
foreach (var balance in weeklyBalances)
foreach (var userId in usersToProcess)
{
// ⭐ محاسبه تعادل شخصی
var personalBalances = 0;
if (allWeeklyBalances.ContainsKey(userId))
{
personalBalances = allWeeklyBalances[userId].TotalBalances;
}
// ⭐ محاسبه مجموع تعادل‌های زیرمجموعه تا maxNetworkLevel لول
var subordinateBalances = await CalculateSubordinateBalancesAsync(
userId,
request.WeekNumber,
allWeeklyBalances,
maxNetworkLevel,
cancellationToken
);
// ⭐ مجموع تعادل = شخصی + زیرمجموعه
var totalBalancesWithSubordinates = personalBalances + subordinateBalances;
// اگر مجموع تعادل صفر است، نیازی به ثبت نیست
if (totalBalancesWithSubordinates <= 0)
{
continue;
}
// محاسبه مبلغ کمیسیون
var totalAmount = (long)(balance.TotalBalances * pool.ValuePerBalance);
var totalAmount = (long)(totalBalancesWithSubordinates * pool.ValuePerBalance);
var payout = new UserCommissionPayout
{
UserId = balance.UserId,
UserId = userId,
WeekNumber = request.WeekNumber,
WeeklyPoolId = pool.Id,
BalancesEarned = balance.TotalBalances,
BalancesEarned = totalBalancesWithSubordinates, // ⭐ شامل زیرمجموعه
ValuePerBalance = pool.ValuePerBalance,
TotalAmount = totalAmount,
Status = CommissionPayoutStatus.Pending,
@@ -96,4 +147,92 @@ public class ProcessUserPayoutsCommandHandler : IRequestHandler<ProcessUserPayou
return payoutsList.Count;
}
/// <summary>
/// پیدا کردن والدین یک کاربر تا N لول بالاتر
/// </summary>
private async Task<List<long>> GetAncestors(long userId, int maxLevels, CancellationToken cancellationToken)
{
var ancestors = new List<long>();
var currentUserId = userId;
for (int level = 0; level < maxLevels; level++)
{
var user = await _context.Users
.Where(x => x.Id == currentUserId)
.Select(x => x.NetworkParentId)
.FirstOrDefaultAsync(cancellationToken);
if (user == null || !user.HasValue)
{
break;
}
ancestors.Add(user.Value);
currentUserId = user.Value;
}
return ancestors;
}
/// <summary>
/// محاسبه مجموع تعادل‌های زیرمجموعه یک کاربر تا N لول پایین‌تر
/// </summary>
private async Task<int> CalculateSubordinateBalancesAsync(
long userId,
string weekNumber,
Dictionary<long, NetworkWeeklyBalance> allBalances,
int maxLevel,
CancellationToken cancellationToken)
{
// پیدا کردن همه زیرمجموعه‌ها تا maxLevel لول
var subordinates = await GetSubordinatesRecursive(userId, 1, maxLevel, cancellationToken);
// جمع تعادل‌های آنها
var totalSubordinateBalances = 0;
foreach (var subordinateId in subordinates)
{
if (allBalances.ContainsKey(subordinateId))
{
totalSubordinateBalances += allBalances[subordinateId].TotalBalances;
}
}
return totalSubordinateBalances;
}
/// <summary>
/// پیدا کردن بازگشتی زیرمجموعه‌ها تا N لول
/// </summary>
private async Task<List<long>> GetSubordinatesRecursive(
long userId,
int currentLevel,
int maxLevel,
CancellationToken cancellationToken)
{
// محدودیت عمق
if (currentLevel > maxLevel)
{
return new List<long>();
}
var result = new List<long>();
// پیدا کردن فرزندان مستقیم
var children = await _context.Users
.Where(x => x.NetworkParentId == userId)
.Select(x => x.Id)
.ToListAsync(cancellationToken);
result.AddRange(children);
// بازگشت برای هر فرزند
foreach (var childId in children)
{
var grandChildren = await GetSubordinatesRecursive(childId, currentLevel + 1, maxLevel, cancellationToken);
result.AddRange(grandChildren);
}
return result;
}
}