4d6d77531d
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 15m3s
- SP sp_CalculateWeeklyBalances: added @PackageId, @InputMaxBalancesPerLeg, @InputMaxNetworkLevel params; filters by PackageId - SP sp_CalculateWeeklyCommissionPool: added @PackageId param; all queries filter by PackageId/WeeklyPoolId for isolation - ICommissionCalculationStrategy: added optional PackageId param to both methods - StoredProcedureCommissionCalculationStrategy: loops per-package for both Balance and Pool methods; filters by packageId if provided - OrmCommissionCalculationStrategy: signature updated to match interface - TriggerWeeklyCalculationCommand: added PackageId optional field - TriggerWeeklyCalculationCommandHandler: passes PackageId to strategy - GetWeeklyCommissionPoolQuery: added optional PackageId filter - GetWeeklyCommissionPoolQueryHandler: filters pool by PackageId if provided - GetAllWeeklyPoolsQuery/Handler/DTO: added PackageId filter + PackageTitle in response - Proto commission.proto: added package_id to TriggerWeeklyCalculationRequest, GetWeeklyCommissionPoolRequest, WeeklyCommissionPoolModel, GetWeeklyCommissionPoolResponse, GetAllWeeklyPoolsRequest - CommissionProfile: added explicit mappings for TriggerWeeklyCalculation, GetWeeklyCommissionPool, GetAllWeeklyPools Fixes: SP picks wrong pool when multiple packages per week Fixes: SP ignores PackageId on ForceRecalculate (now uses WeeklyPoolId) Fixes: Zero-balance pools not fully recorded (now sets TotalBalances=0, ValuePerBalance=0)
568 lines
22 KiB
C#
568 lines
22 KiB
C#
using System.Collections.Generic;
|
|
using CMSMicroservice.Application.Common.Interfaces;
|
|
using CMSMicroservice.Domain.Common;
|
|
using CMSMicroservice.Domain.Entities.Club;
|
|
using CMSMicroservice.Domain.Entities.Commission;
|
|
using CMSMicroservice.Domain.Entities.Network;
|
|
using CMSMicroservice.Domain.Enums;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace CMSMicroservice.Infrastructure.Services.Commission;
|
|
|
|
/// <summary>
|
|
/// پیادهسازی محاسبه کمیسیون با استفاده از Entity Framework (ORM)
|
|
/// این روش برای دادههای کم مناسب است و دیباگ و تست راحتتری دارد
|
|
/// </summary>
|
|
public class OrmCommissionCalculationStrategy : ICommissionCalculationStrategy
|
|
{
|
|
private readonly IApplicationDbContext _context;
|
|
private readonly IWeekDefinitionRepository _weekRepository;
|
|
|
|
public OrmCommissionCalculationStrategy(
|
|
IApplicationDbContext context,
|
|
IWeekDefinitionRepository weekRepository)
|
|
{
|
|
_context = context;
|
|
_weekRepository = weekRepository;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<int> CalculateWeeklyBalancesAsync(
|
|
long weekDefinitionId,
|
|
bool forceRecalculate,
|
|
long? packageId = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var regorianWeekNumber = _weekRepository.GetGregorianWeekNumber(weekDefinitionId);
|
|
if (regorianWeekNumber == null)
|
|
{
|
|
throw new InvalidOperationException($"هفته {weekDefinitionId} در سیستم تعریف نشده است");
|
|
}
|
|
|
|
// بررسی وجود محاسبه قبلی
|
|
var existingBalances = await _context.NetworkWeeklyBalances
|
|
.Where(x => x.WeekDefinitionId == weekDefinitionId)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (existingBalances.Any() && !forceRecalculate)
|
|
{
|
|
throw new InvalidOperationException($"تعادلهای هفته {weekDefinitionId} قبلاً محاسبه شده است. برای محاسبه مجدد از ForceRecalculate استفاده کنید");
|
|
}
|
|
|
|
// حذف محاسبات قبلی در صورت ForceRecalculate
|
|
if (existingBalances.Any())
|
|
{
|
|
_context.NetworkWeeklyBalances.RemoveRange(existingBalances);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
// دریافت همه کاربرانی که عضو فعال باشگاه هستند
|
|
// ⚠️ Magic Wallet: کاربرهایی که در حالت جادویی هستند از کمیسیون خارج میشن
|
|
var magicModeUserIds = await _context.UserWallets
|
|
.Where(w => w.WalletMode == WalletMode.Magic)
|
|
.Select(w => w.UserId)
|
|
.ToHashSetAsync(cancellationToken);
|
|
|
|
// دریافت عضویتهای فعال به همراه PackageId هر کاربر
|
|
var activeClubMemberships = await _context.ClubMemberships
|
|
.Where(c => c.IsActive && !magicModeUserIds.Contains(c.UserId))
|
|
.Select(c => new { c.UserId, PackageId = c.LastPackageId })
|
|
.ToListAsync(cancellationToken);
|
|
|
|
var activeClubMemberUserIds = activeClubMemberships
|
|
.Select(c => c.UserId)
|
|
.ToHashSet();
|
|
|
|
// نگاشت کاربر → PackageId
|
|
var userPackageMap = activeClubMemberships
|
|
.Where(c => c.PackageId.HasValue)
|
|
.ToDictionary(c => c.UserId, c => c.PackageId!.Value);
|
|
|
|
// دریافت کاربران فعال در شبکه که عضو باشگاه هستند
|
|
var usersInNetwork = await _context.Users
|
|
.Where(x => activeClubMemberUserIds.Contains(x.Id))
|
|
.Select(x => new { x.Id })
|
|
.ToListAsync(cancellationToken);
|
|
|
|
// بارگذاری همه پکیجهای فعال (bulk load)
|
|
var allPackages = await _context.Packages
|
|
.Where(p => !p.IsDeleted)
|
|
.ToDictionaryAsync(p => p.Id, cancellationToken);
|
|
|
|
// پکیج پیشفرض (fallback برای کاربرانی که PackageId ندارند)
|
|
var defaultPackage = allPackages.Values
|
|
.FirstOrDefault(p => p.IsBasePackage)
|
|
?? throw new InvalidOperationException("پکیج پایه یافت نشد");
|
|
|
|
// دریافت باقیماندههای هفته قبل — شامل PackageId
|
|
var previousWeekDefinitionId = GetPreviousWeekDefinitionId(weekDefinitionId);
|
|
Dictionary<(long UserId, long PackageId), (int LeftLegRemainder, int RightLegRemainder)> previousWeekCarryovers;
|
|
|
|
if (previousWeekDefinitionId.HasValue)
|
|
{
|
|
previousWeekCarryovers = await _context.NetworkWeeklyBalances
|
|
.Where(x => x.WeekDefinitionId == previousWeekDefinitionId.Value)
|
|
.ToDictionaryAsync(
|
|
x => (x.UserId, x.PackageId),
|
|
x => (x.LeftLegRemainder, x.RightLegRemainder),
|
|
cancellationToken);
|
|
}
|
|
else
|
|
{
|
|
previousWeekCarryovers = new Dictionary<(long, long), (int, int)>();
|
|
}
|
|
|
|
var balancesList = new List<NetworkWeeklyBalance>();
|
|
var calculatedAt = DateTime.Now;
|
|
|
|
foreach (var user in usersInNetwork.OrderBy(o => o.Id))
|
|
{
|
|
// تعیین پکیج هر کاربر (per-user)
|
|
var userPackageId = userPackageMap.GetValueOrDefault(user.Id, defaultPackage.Id);
|
|
var package = allPackages.GetValueOrDefault(userPackageId, defaultPackage);
|
|
var maxBalancesPerLeg = package.MaxBalancesPerLeg;
|
|
var maxNetworkLevel = package.MaxNetworkLevel;
|
|
// دریافت باقیمانده هفته قبل — فیلتر per-package
|
|
var leftCarryover = 0;
|
|
var rightCarryover = 0;
|
|
var carryoverKey = (UserId: user.Id, PackageId: userPackageId);
|
|
if (previousWeekCarryovers.ContainsKey(carryoverKey))
|
|
{
|
|
leftCarryover = previousWeekCarryovers[carryoverKey].LeftLegRemainder;
|
|
rightCarryover = previousWeekCarryovers[carryoverKey].RightLegRemainder;
|
|
}
|
|
|
|
// محاسبه تعداد اعضای جدید در این هفته (تا maxNetworkLevel لول پایینتر)
|
|
var leftNewMembers = await CountNewMembersInLeg(user.Id, NetworkLeg.Left, weekDefinitionId, maxNetworkLevel, cancellationToken);
|
|
var rightNewMembers = await CountNewMembersInLeg(user.Id, NetworkLeg.Right, weekDefinitionId, maxNetworkLevel, cancellationToken);
|
|
|
|
// محاسبه مجموع هر پا (جدید + باقیمانده)
|
|
var leftTotal = leftNewMembers + leftCarryover;
|
|
var rightTotal = rightNewMembers + rightCarryover;
|
|
|
|
// تعادل = کمترین مقدار بین چپ و راست
|
|
var totalBalances = Math.Min(leftTotal, rightTotal);
|
|
|
|
// باقیمانده برای هفته بعد
|
|
var leftRemainder = leftTotal - totalBalances;
|
|
var rightRemainder = rightTotal - totalBalances;
|
|
|
|
// اعمال سقف 300
|
|
var cappedBalances = Math.Min(totalBalances, maxBalancesPerLeg);
|
|
|
|
// محاسبه فلش
|
|
var flushedPerSide = totalBalances - cappedBalances;
|
|
var totalFlushed = flushedPerSide * 2;
|
|
|
|
var balance = new NetworkWeeklyBalance
|
|
{
|
|
UserId = user.Id,
|
|
WeekDefinitionId = weekDefinitionId,
|
|
PackageId = package.Id,
|
|
LeftLegNewMembers = leftNewMembers,
|
|
RightLegNewMembers = rightNewMembers,
|
|
LeftLegCarryover = leftCarryover,
|
|
RightLegCarryover = rightCarryover,
|
|
LeftLegTotal = leftTotal,
|
|
RightLegTotal = rightTotal,
|
|
TotalBalances = cappedBalances,
|
|
LeftLegRemainder = leftRemainder,
|
|
RightLegRemainder = rightRemainder,
|
|
FlushedPerSide = flushedPerSide,
|
|
TotalFlushed = totalFlushed,
|
|
SubordinateBalances = 0,
|
|
#pragma warning disable CS0618
|
|
LeftLegBalances = leftTotal,
|
|
RightLegBalances = rightTotal,
|
|
#pragma warning restore CS0618
|
|
WeeklyPoolContribution = 0,
|
|
CalculatedAt = calculatedAt,
|
|
IsExpired = false
|
|
};
|
|
|
|
balancesList.Add(balance);
|
|
}
|
|
|
|
await _context.NetworkWeeklyBalances.AddRangeAsync(balancesList, cancellationToken);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
// محاسبه تعادل زیرمجموعه — per-user maxNetworkLevel
|
|
var balancesDictionary = balancesList.ToDictionary(x => x.UserId);
|
|
|
|
foreach (var balance in balancesList)
|
|
{
|
|
var balancePackage = allPackages.GetValueOrDefault(balance.PackageId, defaultPackage);
|
|
var subordinateBalances = await CalculateSubordinateBalancesAsync(
|
|
balance.UserId,
|
|
balancesDictionary,
|
|
balancePackage.MaxNetworkLevel,
|
|
cancellationToken
|
|
);
|
|
|
|
balance.SubordinateBalances = subordinateBalances;
|
|
}
|
|
|
|
_context.NetworkWeeklyBalances.UpdateRange(balancesList);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
return balancesList.Count;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<long> CalculateWeeklyCommissionPoolAsync(
|
|
long weekDefinitionId,
|
|
bool forceRecalculate,
|
|
long? packageId = null,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var weekDefinition = _weekRepository.GetGregorianWeekNumber(weekDefinitionId);
|
|
if (weekDefinition == null)
|
|
{
|
|
throw new InvalidOperationException($"هفته {weekDefinitionId} در سیستم تعریف نشده است");
|
|
}
|
|
|
|
// بررسی وجود استخر
|
|
var existingPool = await _context.WeeklyCommissionPools
|
|
.FirstOrDefaultAsync(x => x.WeekDefinitionId == weekDefinitionId, cancellationToken);
|
|
|
|
if (existingPool == null)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Pool هفته {weekDefinitionId} وجود ندارد. " +
|
|
"Pool باید در هنگام فعالسازی باشگاه مشتریان ایجاد شده باشد"
|
|
);
|
|
}
|
|
|
|
if (existingPool.IsCalculated && !forceRecalculate)
|
|
{
|
|
throw new InvalidOperationException($"استخر کمیسیون هفته {weekDefinitionId} قبلاً محاسبه شده است");
|
|
}
|
|
|
|
// بررسی وجود تعادلهای هفتگی
|
|
var weeklyBalances = await _context.NetworkWeeklyBalances
|
|
.Where(x => x.WeekDefinitionId == weekDefinitionId)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (!weeklyBalances.Any())
|
|
{
|
|
throw new InvalidOperationException($"تعادلهای هفته {weekDefinitionId} هنوز محاسبه نشده است. ابتدا CalculateWeeklyBalances را اجرا کنید");
|
|
}
|
|
|
|
var totalPoolAmount = existingPool.TotalPoolAmount;
|
|
var totalBalancesInNetwork = weeklyBalances.Sum(x => x.TotalBalances);
|
|
|
|
long valuePerBalance = 0;
|
|
if (totalBalancesInNetwork > 0)
|
|
{
|
|
valuePerBalance = totalPoolAmount / totalBalancesInNetwork;
|
|
}
|
|
|
|
// بهروزرسانی Pool
|
|
existingPool.TotalBalances = totalBalancesInNetwork;
|
|
existingPool.ValuePerBalance = valuePerBalance;
|
|
existingPool.IsCalculated = true;
|
|
existingPool.CalculatedAt = DateTime.Now;
|
|
|
|
_context.WeeklyCommissionPools.Update(existingPool);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
// حذف پرداختهای قبلی در صورت ForceRecalculate
|
|
if (forceRecalculate)
|
|
{
|
|
var oldPayouts = await _context.UserCommissionPayouts
|
|
.Where(p => p.WeekDefinitionId == weekDefinitionId)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (oldPayouts.Any())
|
|
{
|
|
var oldPayoutIds = oldPayouts.Select(p => p.Id).ToList();
|
|
|
|
// برگرداندن NetworkBalance به حالت قبل (Revert)
|
|
await RevertUserWalletsAsync(oldPayoutIds, cancellationToken);
|
|
|
|
// حذف تاریخچهها
|
|
var oldHistories = await _context.CommissionPayoutHistories
|
|
.Where(h => oldPayoutIds.Contains(h.UserCommissionPayoutId))
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (oldHistories.Any())
|
|
{
|
|
_context.CommissionPayoutHistories.RemoveRange(oldHistories);
|
|
}
|
|
|
|
_context.UserCommissionPayouts.RemoveRange(oldPayouts);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
}
|
|
|
|
// ثبت پرداخت برای کاربرانی که تعادل دارند
|
|
var payouts = new List<UserCommissionPayout>();
|
|
|
|
foreach (var balance in weeklyBalances)
|
|
{
|
|
var userBalance = balance.TotalBalances;
|
|
if (userBalance <= 0) continue;
|
|
|
|
var totalAmount = (long)(userBalance * valuePerBalance);
|
|
|
|
var payout = new UserCommissionPayout
|
|
{
|
|
UserId = balance.UserId,
|
|
WeekDefinitionId = weekDefinitionId,
|
|
WeeklyPoolId = existingPool.Id,
|
|
PackageId = balance.PackageId, // per-user PackageId از محاسبه تعادل
|
|
BalancesEarned = userBalance,
|
|
ValuePerBalance = valuePerBalance,
|
|
TotalAmount = totalAmount,
|
|
Status = CommissionPayoutStatus.Pending,
|
|
PaidAt = null,
|
|
WithdrawalMethod = null,
|
|
IbanNumber = null,
|
|
WithdrawnAt = null
|
|
};
|
|
|
|
payouts.Add(payout);
|
|
}
|
|
|
|
if (payouts.Any())
|
|
{
|
|
await _context.UserCommissionPayouts.AddRangeAsync(payouts, cancellationToken);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
// ثبت تاریخچه
|
|
var historyList = payouts.Select(payout => new CommissionPayoutHistory
|
|
{
|
|
UserCommissionPayoutId = payout.Id,
|
|
UserId = payout.UserId,
|
|
WeekDefinitionId = weekDefinitionId,
|
|
AmountBefore = 0,
|
|
AmountAfter = payout.TotalAmount,
|
|
OldStatus = default(CommissionPayoutStatus),
|
|
NewStatus = CommissionPayoutStatus.Pending,
|
|
Action = CommissionPayoutAction.Created,
|
|
PerformedBy = "System",
|
|
Reason = "پردازش خودکار کمیسیون هفتگی (ORM)"
|
|
}).ToList();
|
|
|
|
await _context.CommissionPayoutHistories.AddRangeAsync(historyList, cancellationToken);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
// شارژ کیف پول کاربران
|
|
await ChargeUserWalletsAsync(payouts, weekDefinitionId, cancellationToken);
|
|
}
|
|
|
|
return existingPool.Id;
|
|
}
|
|
|
|
#region Private Methods
|
|
|
|
private long? GetPreviousWeekDefinitionId(long currentWeekDefinitionId)
|
|
{
|
|
var currentWeekNumber = _weekRepository.GetGregorianWeekNumber(currentWeekDefinitionId);
|
|
if (currentWeekNumber == null) return null;
|
|
|
|
var previousWeekNumber = _weekRepository.GetPreviousWeekNumber(currentWeekNumber);
|
|
if (previousWeekNumber == null) return null;
|
|
|
|
return _weekRepository.GetWeekDefinitionId(previousWeekNumber);
|
|
}
|
|
|
|
private async Task<int> CountNewMembersInLeg(long userId, NetworkLeg leg, long weekDefinitionId, int maxLevel, CancellationToken cancellationToken)
|
|
{
|
|
var startDateEndDate = _weekRepository.GetWeekDateRange(weekDefinitionId);
|
|
var count = await CountNewMembersRecursive(userId, leg, startDateEndDate.Value.startDate, startDateEndDate.Value.endDate, 0, maxLevel, cancellationToken);
|
|
return count;
|
|
}
|
|
|
|
private async Task<int> CountNewMembersRecursive(
|
|
long userId,
|
|
NetworkLeg leg,
|
|
DateTime startDate,
|
|
DateTime endDate,
|
|
int currentLevel,
|
|
int maxLevel,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (currentLevel >= maxLevel)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
var child = await _context.Users
|
|
.FirstOrDefaultAsync(x => x.NetworkParentId == userId && x.LegPosition == leg, cancellationToken);
|
|
|
|
if (child == null)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
var count = 0;
|
|
// ⚠️ از ClubMembershipCycle.PackagePurchasedAt استفاده میکنیم (نه ActivatedAt که overwrite میشد)
|
|
var currentCycle = await _context.ClubMembershipCycles
|
|
.FirstOrDefaultAsync(x => x.UserId == child.Id && x.IsCurrentCycle, cancellationToken);
|
|
|
|
if (currentCycle?.PackagePurchasedAt >= startDate && currentCycle?.PackagePurchasedAt <= endDate)
|
|
{
|
|
count = 1;
|
|
}
|
|
|
|
var childLeft = await CountNewMembersRecursive(child.Id, NetworkLeg.Left, startDate, endDate, currentLevel + 1, maxLevel, cancellationToken);
|
|
var childRight = await CountNewMembersRecursive(child.Id, NetworkLeg.Right, startDate, endDate, currentLevel + 1, maxLevel, cancellationToken);
|
|
|
|
return count + childLeft + childRight;
|
|
}
|
|
|
|
private async Task<int> CalculateSubordinateBalancesAsync(
|
|
long userId,
|
|
Dictionary<long, NetworkWeeklyBalance> allBalances,
|
|
int maxLevel,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
private async Task ChargeUserWalletsAsync(
|
|
List<UserCommissionPayout> payouts,
|
|
long weekDefinitionId,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var userIds = payouts.Select(p => p.UserId).Distinct().ToList();
|
|
|
|
var existingWallets = await _context.UserWallets
|
|
.Where(w => userIds.Contains(w.UserId))
|
|
.ToDictionaryAsync(w => w.UserId, cancellationToken);
|
|
|
|
var newWallets = new List<UserWallet>();
|
|
var walletLogs = new List<UserWalletHistory>();
|
|
|
|
foreach (var payout in payouts)
|
|
{
|
|
if (payout.TotalAmount <= 0) continue;
|
|
|
|
UserWallet wallet;
|
|
|
|
if (existingWallets.TryGetValue(payout.UserId, out var existingWallet))
|
|
{
|
|
wallet = existingWallet;
|
|
}
|
|
else
|
|
{
|
|
wallet = new UserWallet
|
|
{
|
|
UserId = payout.UserId,
|
|
Balance = 0,
|
|
NetworkBalance = 0,
|
|
DiscountBalance = 0
|
|
};
|
|
newWallets.Add(wallet);
|
|
existingWallets[payout.UserId] = wallet;
|
|
}
|
|
}
|
|
|
|
if (newWallets.Any())
|
|
{
|
|
await _context.UserWallets.AddRangeAsync(newWallets, cancellationToken);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
foreach (var payout in payouts)
|
|
{
|
|
if (payout.TotalAmount <= 0) continue;
|
|
|
|
var wallet = existingWallets[payout.UserId];
|
|
wallet.NetworkBalance += payout.TotalAmount;
|
|
|
|
var walletLog = new UserWalletHistory
|
|
{
|
|
WalletId = wallet.Id,
|
|
CurrentBalance = wallet.Balance,
|
|
ChangeValue = 0,
|
|
CurrentNetworkBalance = wallet.NetworkBalance,
|
|
ChangeNerworkValue = payout.TotalAmount,
|
|
CurrentDiscountBalance = wallet.DiscountBalance,
|
|
ChangeDiscountValue = 0,
|
|
IsIncrease = true,
|
|
RefrenceId = payout.Id
|
|
};
|
|
|
|
walletLogs.Add(walletLog);
|
|
}
|
|
|
|
await _context.UserWalletHistories.AddRangeAsync(walletLogs, cancellationToken);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
private async Task RevertUserWalletsAsync(
|
|
List<long> oldPayoutIds,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var oldWalletLogs = await _context.UserWalletHistories
|
|
.Where(l => l.RefrenceId.HasValue && oldPayoutIds.Contains(l.RefrenceId.Value))
|
|
.ToListAsync(cancellationToken);
|
|
|
|
if (!oldWalletLogs.Any()) return;
|
|
|
|
var walletIds = oldWalletLogs.Select(l => l.WalletId).Distinct().ToList();
|
|
var wallets = await _context.UserWallets
|
|
.Where(w => walletIds.Contains(w.Id))
|
|
.ToDictionaryAsync(w => w.Id, cancellationToken);
|
|
|
|
foreach (var log in oldWalletLogs)
|
|
{
|
|
if (wallets.TryGetValue(log.WalletId, out var wallet))
|
|
{
|
|
wallet.NetworkBalance -= log.ChangeNerworkValue;
|
|
if (wallet.NetworkBalance < 0)
|
|
{
|
|
wallet.NetworkBalance = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
_context.UserWalletHistories.RemoveRange(oldWalletLogs);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
#endregion
|
|
}
|