namespace CMSMicroservice.Application.CommissionCQ.Commands.CalculateWeeklyBalances; public class CalculateWeeklyBalancesCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; public CalculateWeeklyBalancesCommandHandler(IApplicationDbContext context) { _context = context; } public async Task Handle(CalculateWeeklyBalancesCommand request, CancellationToken cancellationToken) { // بررسی وجود محاسبه قبلی var existingBalances = await _context.NetworkWeeklyBalances .Where(x => x.WeekNumber == request.WeekNumber) .ToListAsync(cancellationToken); if (existingBalances.Any() && !request.ForceRecalculate) { throw new InvalidOperationException($"تعادل‌های هفته {request.WeekNumber} قبلاً محاسبه شده است. برای محاسبه مجدد از ForceRecalculate استفاده کنید"); } // حذف محاسبات قبلی در صورت ForceRecalculate if (existingBalances.Any()) { _context.NetworkWeeklyBalances.RemoveRange(existingBalances); await _context.SaveChangesAsync(cancellationToken); } // دریافت کاربران فعال در شبکه var usersInNetwork = await _context.Users .Where(x => x.NetworkParentId.HasValue) .Select(x => new { x.Id }) .ToListAsync(cancellationToken); var balancesList = new List(); var calculatedAt = DateTime.UtcNow; foreach (var user in usersInNetwork) { // محاسبه تعادل پای چپ (Left Leg) var leftLegBalances = (int)await CalculateLegBalances(user.Id, NetworkLeg.Left, cancellationToken); // محاسبه تعادل پای راست (Right Leg) var rightLegBalances = (int)await CalculateLegBalances(user.Id, NetworkLeg.Right, cancellationToken); // محاسبه Total Balances (کمترین مقدار دو پا) var totalBalances = Math.Min(leftLegBalances, rightLegBalances); // محاسبه سهم استخر (10% از Total Balances) var weeklyPoolContribution = (long)(totalBalances * 0.10m); var balance = new NetworkWeeklyBalance { UserId = user.Id, WeekNumber = request.WeekNumber, LeftLegBalances = leftLegBalances, RightLegBalances = rightLegBalances, TotalBalances = totalBalances, WeeklyPoolContribution = weeklyPoolContribution, CalculatedAt = calculatedAt, IsExpired = false }; balancesList.Add(balance); } await _context.NetworkWeeklyBalances.AddRangeAsync(balancesList, cancellationToken); await _context.SaveChangesAsync(cancellationToken); return balancesList.Count; } /// /// محاسبه تعادل یک پا (Left یا Right) به صورت بازگشتی /// private async Task CalculateLegBalances(long userId, NetworkLeg leg, CancellationToken cancellationToken) { // پیدا کردن فرزند در پای مورد نظر var child = await _context.Users .FirstOrDefaultAsync(x => x.NetworkParentId == userId && x.LegPosition == leg, cancellationToken); if (child == null) { return 0; // اگر فرزندی نداشته باشد، تعادل صفر است } // محاسبه بازگشتی: مجموع تعادل فرزند چپ + راست + 1 (خود فرزند) var childLeftLeg = await CalculateLegBalances(child.Id, NetworkLeg.Left, cancellationToken); var childRightLeg = await CalculateLegBalances(child.Id, NetworkLeg.Right, cancellationToken); return 1 + childLeftLeg + childRightLeg; } }