feat: Enhance network membership and withdrawal processing with user tracking and logging
This commit is contained in:
@@ -3,10 +3,14 @@ namespace CMSMicroservice.Application.ClubMembershipCQ.Commands.ActivateClubMemb
|
||||
public class ActivateClubMembershipCommandHandler : IRequestHandler<ActivateClubMembershipCommand, long>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public ActivateClubMembershipCommandHandler(IApplicationDbContext context)
|
||||
public ActivateClubMembershipCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<long> Handle(ActivateClubMembershipCommand request, CancellationToken cancellationToken)
|
||||
@@ -21,16 +25,12 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler<ActivateClub
|
||||
}
|
||||
|
||||
// دریافت مبلغ عضویت از Configuration
|
||||
var membershipPrice = await _context.SystemConfigurations
|
||||
.Where(x => x.Key == "club_membership_price" && x.IsActive)
|
||||
var activationFeeConfig = await _context.SystemConfigurations
|
||||
.Where(x => x.Key == "Club.ActivationFee" && x.IsActive)
|
||||
.Select(x => x.Value)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
long initialContribution = 25_000_000; // Default: 25 million Rials
|
||||
if (!string.IsNullOrEmpty(membershipPrice) && long.TryParse(membershipPrice, out var parsedPrice))
|
||||
{
|
||||
initialContribution = parsedPrice;
|
||||
}
|
||||
long initialContribution = long.Parse(activationFeeConfig ?? "25000000"); // Default: 25 million Rials
|
||||
|
||||
// بررسی عضویت فعلی
|
||||
var existingMembership = await _context.ClubMemberships
|
||||
@@ -87,7 +87,7 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler<ActivateClub
|
||||
NewIsActive = true,
|
||||
Action = ClubMembershipAction.Activated,
|
||||
Reason = request.Reason ?? (isNewMembership ? "Initial activation" : "Reactivated"),
|
||||
PerformedBy = "System" // TODO: باید از Current User گرفته شود
|
||||
PerformedBy = _currentUser.GetPerformedBy()
|
||||
};
|
||||
|
||||
await _context.ClubMembershipHistories.AddAsync(history, cancellationToken);
|
||||
|
||||
@@ -3,10 +3,14 @@ namespace CMSMicroservice.Application.ClubMembershipCQ.Commands.DeactivateClubMe
|
||||
public class DeactivateClubMembershipCommandHandler : IRequestHandler<DeactivateClubMembershipCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public DeactivateClubMembershipCommandHandler(IApplicationDbContext context)
|
||||
public DeactivateClubMembershipCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(DeactivateClubMembershipCommand request, CancellationToken cancellationToken)
|
||||
@@ -38,8 +42,8 @@ public class DeactivateClubMembershipCommandHandler : IRequestHandler<Deactivate
|
||||
OldIsActive = true,
|
||||
NewIsActive = false,
|
||||
Action = ClubMembershipAction.Deactivated,
|
||||
Reason = request.Reason ?? "Membership deactivated",
|
||||
PerformedBy = "System" // TODO: باید از Current User گرفته شود
|
||||
Reason = request.Reason ?? "Manual deactivation",
|
||||
PerformedBy = _currentUser.GetPerformedBy()
|
||||
};
|
||||
|
||||
await _context.ClubMembershipHistories.AddAsync(history, cancellationToken);
|
||||
|
||||
@@ -6,10 +6,14 @@ namespace CMSMicroservice.Application.CommissionCQ.Commands.ApproveWithdrawal;
|
||||
public class ApproveWithdrawalCommandHandler : IRequestHandler<ApproveWithdrawalCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public ApproveWithdrawalCommandHandler(IApplicationDbContext context)
|
||||
public ApproveWithdrawalCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(ApproveWithdrawalCommand request, CancellationToken cancellationToken)
|
||||
@@ -30,6 +34,8 @@ public class ApproveWithdrawalCommandHandler : IRequestHandler<ApproveWithdrawal
|
||||
// Update status to Withdrawn (approved)
|
||||
payout.Status = CommissionPayoutStatus.Withdrawn;
|
||||
payout.WithdrawnAt = DateTime.UtcNow;
|
||||
payout.ProcessedBy = _currentUser.GetPerformedBy();
|
||||
payout.ProcessedAt = DateTime.UtcNow;
|
||||
payout.LastModified = DateTime.UtcNow;
|
||||
|
||||
// TODO: Add PayoutHistory record
|
||||
|
||||
@@ -34,30 +34,95 @@ public class CalculateWeeklyBalancesCommandHandler : IRequestHandler<CalculateWe
|
||||
.Select(x => new { x.Id })
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
// دریافت باقیماندههای هفته قبل
|
||||
var previousWeekNumber = GetPreviousWeekNumber(request.WeekNumber);
|
||||
var previousWeekCarryovers = await _context.NetworkWeeklyBalances
|
||||
.Where(x => x.WeekNumber == previousWeekNumber)
|
||||
.Select(x => new
|
||||
{
|
||||
x.UserId,
|
||||
x.LeftLegRemainder,
|
||||
x.RightLegRemainder
|
||||
})
|
||||
.ToDictionaryAsync(x => x.UserId, cancellationToken);
|
||||
|
||||
var balancesList = new List<NetworkWeeklyBalance>();
|
||||
var calculatedAt = DateTime.UtcNow;
|
||||
|
||||
// خواندن یکباره Configuration ها (بهینهسازی - به جای N query)
|
||||
var configs = await _context.SystemConfigurations
|
||||
.Where(x => x.IsActive && (
|
||||
x.Key == "Club.ActivationFee" ||
|
||||
x.Key == "Commission.WeeklyPoolContributionPercent" ||
|
||||
x.Key == "Commission.MaxWeeklyBalancesPerUser"))
|
||||
.ToDictionaryAsync(x => x.Key, x => x.Value, cancellationToken);
|
||||
|
||||
var activationFee = long.Parse(configs.GetValueOrDefault("Club.ActivationFee", "25000000"));
|
||||
var poolPercent = decimal.Parse(configs.GetValueOrDefault("Commission.WeeklyPoolContributionPercent", "20")) / 100m;
|
||||
var maxWeeklyBalances = int.Parse(configs.GetValueOrDefault("Commission.MaxWeeklyBalancesPerUser", "300"));
|
||||
|
||||
foreach (var user in usersInNetwork)
|
||||
{
|
||||
// محاسبه تعادل پای چپ (Left Leg)
|
||||
var leftLegBalances = (int)await CalculateLegBalances(user.Id, NetworkLeg.Left, cancellationToken);
|
||||
// دریافت باقیمانده هفته قبل
|
||||
var leftCarryover = 0;
|
||||
var rightCarryover = 0;
|
||||
if (previousWeekCarryovers.ContainsKey(user.Id))
|
||||
{
|
||||
leftCarryover = previousWeekCarryovers[user.Id].LeftLegRemainder;
|
||||
rightCarryover = previousWeekCarryovers[user.Id].RightLegRemainder;
|
||||
}
|
||||
|
||||
// محاسبه تعادل پای راست (Right Leg)
|
||||
var rightLegBalances = (int)await CalculateLegBalances(user.Id, NetworkLeg.Right, cancellationToken);
|
||||
// محاسبه تعداد اعضای جدید در این هفته (فقط فرزندان مستقیم که در این هفته فعال شدند)
|
||||
var leftNewMembers = await CountNewMembersInLeg(user.Id, NetworkLeg.Left, request.WeekNumber, cancellationToken);
|
||||
var rightNewMembers = await CountNewMembersInLeg(user.Id, NetworkLeg.Right, request.WeekNumber, cancellationToken);
|
||||
|
||||
// محاسبه Total Balances (کمترین مقدار دو پا)
|
||||
var totalBalances = Math.Min(leftLegBalances, rightLegBalances);
|
||||
// محاسبه مجموع هر پا (جدید + باقیمانده)
|
||||
var leftTotal = leftNewMembers + leftCarryover;
|
||||
var rightTotal = rightNewMembers + rightCarryover;
|
||||
|
||||
// محاسبه سهم استخر (10% از Total Balances)
|
||||
var weeklyPoolContribution = (long)(totalBalances * 0.10m);
|
||||
// محاسبه تعادل (کمترین مقدار)
|
||||
var totalBalances = Math.Min(leftTotal, rightTotal);
|
||||
|
||||
// اعمال محدودیت سقف تعادل هفتگی (مثلاً 300)
|
||||
var cappedBalances = Math.Min(totalBalances, maxWeeklyBalances);
|
||||
|
||||
// محاسبه باقیمانده برای هفته بعد
|
||||
// اگر تعادل بیش از سقف بود، مازاد هم به remainder اضافه میشود
|
||||
var excessBalances = totalBalances - cappedBalances;
|
||||
var leftRemainder = (leftTotal - totalBalances) + (leftTotal >= rightTotal ? excessBalances : 0);
|
||||
var rightRemainder = (rightTotal - totalBalances) + (rightTotal >= leftTotal ? excessBalances : 0);
|
||||
|
||||
// محاسبه سهم استخر (20% از مجموع فعالسازیهای جدید کل شبکه)
|
||||
// طبق گفته دکتر: کل افراد جدید در شبکه × هزینه فعالسازی × 20%
|
||||
var totalNewMembers = leftNewMembers + rightNewMembers;
|
||||
var weeklyPoolContribution = (long)(totalNewMembers * activationFee * poolPercent);
|
||||
|
||||
var balance = new NetworkWeeklyBalance
|
||||
{
|
||||
UserId = user.Id,
|
||||
WeekNumber = request.WeekNumber,
|
||||
LeftLegBalances = leftLegBalances,
|
||||
RightLegBalances = rightLegBalances,
|
||||
TotalBalances = totalBalances,
|
||||
|
||||
// اطلاعات جدید
|
||||
LeftLegNewMembers = leftNewMembers,
|
||||
RightLegNewMembers = rightNewMembers,
|
||||
LeftLegCarryover = leftCarryover,
|
||||
RightLegCarryover = rightCarryover,
|
||||
|
||||
// مجموع
|
||||
LeftLegTotal = leftTotal,
|
||||
RightLegTotal = rightTotal,
|
||||
TotalBalances = cappedBalances, // تعادل واقعی بعد از اعمال سقف
|
||||
|
||||
// باقیمانده برای هفته بعد
|
||||
LeftLegRemainder = leftRemainder,
|
||||
RightLegRemainder = rightRemainder,
|
||||
|
||||
// فیلدهای قدیمی (deprecated) - برای سازگاری با کدهای قبلی
|
||||
#pragma warning disable CS0618
|
||||
LeftLegBalances = leftTotal,
|
||||
RightLegBalances = rightTotal,
|
||||
#pragma warning restore CS0618
|
||||
|
||||
WeeklyPoolContribution = weeklyPoolContribution,
|
||||
CalculatedAt = calculatedAt,
|
||||
IsExpired = false
|
||||
@@ -73,23 +138,89 @@ public class CalculateWeeklyBalancesCommandHandler : IRequestHandler<CalculateWe
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// محاسبه تعادل یک پا (Left یا Right) به صورت بازگشتی
|
||||
/// شماره هفته قبل را محاسبه میکند
|
||||
/// </summary>
|
||||
private async Task<long> CalculateLegBalances(long userId, NetworkLeg leg, CancellationToken cancellationToken)
|
||||
private string GetPreviousWeekNumber(string currentWeekNumber)
|
||||
{
|
||||
// پیدا کردن فرزند در پای مورد نظر
|
||||
// مثال: "2025-W48" -> "2025-W47"
|
||||
var parts = currentWeekNumber.Split('-');
|
||||
var year = int.Parse(parts[0]);
|
||||
var week = int.Parse(parts[1].Replace("W", ""));
|
||||
|
||||
week--;
|
||||
if (week < 1)
|
||||
{
|
||||
year--;
|
||||
week = 52; // یا 53 بسته به سال
|
||||
}
|
||||
|
||||
return $"{year}-W{week:D2}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// شمارش اعضای جدیدی که در این هفته به یک پا اضافه شدند
|
||||
/// فقط فرزندان مستقیم که ActivatedAt آنها در این هفته است
|
||||
/// </summary>
|
||||
private async Task<int> CountNewMembersInLeg(long userId, NetworkLeg leg, string weekNumber, CancellationToken cancellationToken)
|
||||
{
|
||||
// تبدیل WeekNumber به بازه تاریخی
|
||||
var (startDate, endDate) = GetWeekDateRange(weekNumber);
|
||||
|
||||
// شمارش تمام اعضای زیرمجموعه که در این هفته فعال شدند
|
||||
var count = await CountNewMembersRecursive(userId, leg, startDate, endDate, cancellationToken);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// شمارش بازگشتی اعضای جدید در یک پا
|
||||
/// </summary>
|
||||
private async Task<int> CountNewMembersRecursive(long userId, NetworkLeg leg, DateTime startDate, DateTime endDate, CancellationToken cancellationToken)
|
||||
{
|
||||
// پیدا کردن فرزند مستقیم در پای مورد نظر
|
||||
var child = await _context.Users
|
||||
.FirstOrDefaultAsync(x => x.NetworkParentId == userId && x.LegPosition == leg, cancellationToken);
|
||||
|
||||
if (child == null)
|
||||
{
|
||||
return 0; // اگر فرزندی نداشته باشد، تعادل صفر است
|
||||
return 0;
|
||||
}
|
||||
|
||||
// محاسبه بازگشتی: مجموع تعادل فرزند چپ + راست + 1 (خود فرزند)
|
||||
var childLeftLeg = await CalculateLegBalances(child.Id, NetworkLeg.Left, cancellationToken);
|
||||
var childRightLeg = await CalculateLegBalances(child.Id, NetworkLeg.Right, cancellationToken);
|
||||
var count = 0;
|
||||
|
||||
return 1 + childLeftLeg + childRightLeg;
|
||||
// اگر فرزند در این هفته فعال شده، 1 امتیاز
|
||||
var membership = await _context.ClubMemberships
|
||||
.FirstOrDefaultAsync(x => x.UserId == child.Id && x.IsActive, cancellationToken);
|
||||
|
||||
if (membership?.ActivatedAt >= startDate && membership?.ActivatedAt <= endDate)
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
|
||||
// جمع کردن اعضای جدید از پای چپ و راست فرزند
|
||||
var childLeft = await CountNewMembersRecursive(child.Id, NetworkLeg.Left, startDate, endDate, cancellationToken);
|
||||
var childRight = await CountNewMembersRecursive(child.Id, NetworkLeg.Right, startDate, endDate, cancellationToken);
|
||||
|
||||
return count + childLeft + childRight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// تبدیل شماره هفته به بازه تاریخی
|
||||
/// </summary>
|
||||
private (DateTime startDate, DateTime endDate) GetWeekDateRange(string weekNumber)
|
||||
{
|
||||
// مثال: "2025-W48"
|
||||
var parts = weekNumber.Split('-');
|
||||
var year = int.Parse(parts[0]);
|
||||
var week = int.Parse(parts[1].Replace("W", ""));
|
||||
|
||||
// محاسبه اولین روز هفته (شنبه)
|
||||
var jan1 = new DateTime(year, 1, 1);
|
||||
var daysOffset = DayOfWeek.Saturday - jan1.DayOfWeek;
|
||||
var firstSaturday = jan1.AddDays(daysOffset);
|
||||
var weekStart = firstSaturday.AddDays((week - 1) * 7);
|
||||
var weekEnd = weekStart.AddDays(6).AddHours(23).AddMinutes(59).AddSeconds(59);
|
||||
|
||||
return (weekStart, weekEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,14 @@ namespace CMSMicroservice.Application.CommissionCQ.Commands.ProcessWithdrawal;
|
||||
public class ProcessWithdrawalCommandHandler : IRequestHandler<ProcessWithdrawalCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public ProcessWithdrawalCommandHandler(IApplicationDbContext context)
|
||||
public ProcessWithdrawalCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(ProcessWithdrawalCommand request, CancellationToken cancellationToken)
|
||||
|
||||
@@ -6,10 +6,14 @@ namespace CMSMicroservice.Application.CommissionCQ.Commands.RejectWithdrawal;
|
||||
public class RejectWithdrawalCommandHandler : IRequestHandler<RejectWithdrawalCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public RejectWithdrawalCommandHandler(IApplicationDbContext context)
|
||||
public RejectWithdrawalCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(RejectWithdrawalCommand request, CancellationToken cancellationToken)
|
||||
@@ -29,6 +33,9 @@ public class RejectWithdrawalCommandHandler : IRequestHandler<RejectWithdrawalCo
|
||||
|
||||
// Update status to Cancelled (rejected)
|
||||
payout.Status = CommissionPayoutStatus.Cancelled;
|
||||
payout.ProcessedBy = _currentUser.GetPerformedBy();
|
||||
payout.ProcessedAt = DateTime.UtcNow;
|
||||
payout.RejectionReason = request.Reason;
|
||||
payout.LastModified = DateTime.UtcNow;
|
||||
|
||||
// TODO: Add PayoutHistory record with rejection reason
|
||||
|
||||
@@ -3,10 +3,14 @@ namespace CMSMicroservice.Application.CommissionCQ.Commands.RequestWithdrawal;
|
||||
public class RequestWithdrawalCommandHandler : IRequestHandler<RequestWithdrawalCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public RequestWithdrawalCommandHandler(IApplicationDbContext context)
|
||||
public RequestWithdrawalCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(RequestWithdrawalCommand request, CancellationToken cancellationToken)
|
||||
|
||||
@@ -16,78 +16,51 @@ public class GetWorkerExecutionLogsQueryHandler : IRequestHandler<GetWorkerExecu
|
||||
GetWorkerExecutionLogsQuery request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: این باید از یک entity واقعی لاگها را بگیرد
|
||||
// فعلاً mock data برمیگرداند
|
||||
|
||||
await Task.CompletedTask;
|
||||
|
||||
var mockLogs = new List<WorkerExecutionLogModel>
|
||||
{
|
||||
new WorkerExecutionLogModel
|
||||
{
|
||||
ExecutionId = Guid.NewGuid().ToString(),
|
||||
WeekNumber = "2025-W48",
|
||||
Step = "Full",
|
||||
Success = true,
|
||||
ErrorMessage = null,
|
||||
StartedAt = DateTime.UtcNow.AddHours(-24),
|
||||
CompletedAt = DateTime.UtcNow.AddHours(-24).AddMinutes(15),
|
||||
DurationMs = 900000, // 15 minutes
|
||||
RecordsProcessed = 1523,
|
||||
Details = "محاسبات کامل هفته 2025-W48 با موفقیت انجام شد"
|
||||
},
|
||||
new WorkerExecutionLogModel
|
||||
{
|
||||
ExecutionId = Guid.NewGuid().ToString(),
|
||||
WeekNumber = "2025-W47",
|
||||
Step = "Full",
|
||||
Success = true,
|
||||
ErrorMessage = null,
|
||||
StartedAt = DateTime.UtcNow.AddDays(-7),
|
||||
CompletedAt = DateTime.UtcNow.AddDays(-7).AddMinutes(12),
|
||||
DurationMs = 720000,
|
||||
RecordsProcessed = 1489,
|
||||
Details = "محاسبات کامل هفته 2025-W47 با موفقیت انجام شد"
|
||||
},
|
||||
new WorkerExecutionLogModel
|
||||
{
|
||||
ExecutionId = Guid.NewGuid().ToString(),
|
||||
WeekNumber = "2025-W46",
|
||||
Step = "Pool",
|
||||
Success = false,
|
||||
ErrorMessage = "خطا در محاسبه استخر کمیسیون",
|
||||
StartedAt = DateTime.UtcNow.AddDays(-14),
|
||||
CompletedAt = DateTime.UtcNow.AddDays(-14).AddSeconds(30),
|
||||
DurationMs = 30000,
|
||||
RecordsProcessed = 0,
|
||||
Details = "محاسبه استخر با خطا مواجه شد"
|
||||
}
|
||||
};
|
||||
// Query from database
|
||||
var query = _context.WorkerExecutionLogs.AsQueryable();
|
||||
|
||||
// Apply filters
|
||||
if (!string.IsNullOrEmpty(request.WeekNumber))
|
||||
{
|
||||
mockLogs = mockLogs.Where(x => x.WeekNumber == request.WeekNumber).ToList();
|
||||
query = query.Where(x => x.WeekNumber == request.WeekNumber);
|
||||
}
|
||||
|
||||
if (request.SuccessOnly == true)
|
||||
{
|
||||
mockLogs = mockLogs.Where(x => x.Success).ToList();
|
||||
query = query.Where(x => x.Status == Domain.Entities.Commission.WorkerExecutionStatus.Success ||
|
||||
x.Status == Domain.Entities.Commission.WorkerExecutionStatus.SuccessWithWarnings);
|
||||
}
|
||||
|
||||
if (request.FailedOnly == true)
|
||||
{
|
||||
mockLogs = mockLogs.Where(x => !x.Success).ToList();
|
||||
query = query.Where(x => x.Status == Domain.Entities.Commission.WorkerExecutionStatus.Failed);
|
||||
}
|
||||
|
||||
var totalCount = mockLogs.Count;
|
||||
// Order by most recent first
|
||||
query = query.OrderByDescending(x => x.StartedAt);
|
||||
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
var pageSize = request.PaginationState?.PageSize ?? 10;
|
||||
var pageNumber = request.PaginationState?.PageNumber ?? 1;
|
||||
|
||||
var pagedLogs = mockLogs
|
||||
var logs = await query
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToList();
|
||||
.Select(x => new WorkerExecutionLogModel
|
||||
{
|
||||
ExecutionId = x.ExecutionId.ToString(),
|
||||
WeekNumber = x.WeekNumber,
|
||||
Step = "Full", // We only have full execution now
|
||||
Success = x.Status == Domain.Entities.Commission.WorkerExecutionStatus.Success ||
|
||||
x.Status == Domain.Entities.Commission.WorkerExecutionStatus.SuccessWithWarnings,
|
||||
ErrorMessage = x.ErrorMessage,
|
||||
StartedAt = x.StartedAt,
|
||||
CompletedAt = x.CompletedAt ?? x.StartedAt,
|
||||
DurationMs = x.DurationMs ?? 0,
|
||||
RecordsProcessed = x.ProcessedCount,
|
||||
Details = x.Details ?? $"Worker execution: {x.Status}"
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return new GetWorkerExecutionLogsResponseDto
|
||||
{
|
||||
@@ -100,7 +73,7 @@ public class GetWorkerExecutionLogsQueryHandler : IRequestHandler<GetWorkerExecu
|
||||
HasPrevious = pageNumber > 1,
|
||||
HasNext = pageNumber < (int)Math.Ceiling(totalCount / (double)pageSize)
|
||||
},
|
||||
Models = pagedLogs
|
||||
Models = logs
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,5 +34,6 @@ public interface IApplicationDbContext
|
||||
DbSet<WeeklyCommissionPool> WeeklyCommissionPools { get; }
|
||||
DbSet<UserCommissionPayout> UserCommissionPayouts { get; }
|
||||
DbSet<CommissionPayoutHistory> CommissionPayoutHistories { get; }
|
||||
DbSet<WorkerExecutionLog> WorkerExecutionLogs { get; }
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -1,6 +1,27 @@
|
||||
namespace CMSMicroservice.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// سرویس دریافت اطلاعات کاربر فعلی از Authentication Context
|
||||
/// </summary>
|
||||
public interface ICurrentUserService
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه کاربر فعلی (از JWT Claims)
|
||||
/// </summary>
|
||||
string? UserId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// نام کاربری (Username یا Email)
|
||||
/// </summary>
|
||||
string? Username { get; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا کاربر Authenticated است؟
|
||||
/// </summary>
|
||||
bool IsAuthenticated { get; }
|
||||
|
||||
/// <summary>
|
||||
/// دریافت string برای PerformedBy (UserId:Username یا "System")
|
||||
/// </summary>
|
||||
string GetPerformedBy();
|
||||
}
|
||||
|
||||
@@ -3,10 +3,14 @@ namespace CMSMicroservice.Application.ConfigurationCQ.Commands.DeactivateConfigu
|
||||
public class DeactivateConfigurationCommandHandler : IRequestHandler<DeactivateConfigurationCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public DeactivateConfigurationCommandHandler(IApplicationDbContext context)
|
||||
public DeactivateConfigurationCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(DeactivateConfigurationCommand request, CancellationToken cancellationToken)
|
||||
@@ -36,7 +40,7 @@ public class DeactivateConfigurationCommandHandler : IRequestHandler<DeactivateC
|
||||
OldValue = oldValue,
|
||||
NewValue = entity.Value,
|
||||
Reason = request.Reason ?? "Configuration deactivated",
|
||||
PerformedBy = "System" // TODO: باید از Current User گرفته شود
|
||||
PerformedBy = _currentUser.GetPerformedBy()
|
||||
};
|
||||
|
||||
await _context.SystemConfigurationHistories.AddAsync(history, cancellationToken);
|
||||
|
||||
@@ -3,10 +3,14 @@ namespace CMSMicroservice.Application.ConfigurationCQ.Commands.SetConfigurationV
|
||||
public class SetConfigurationValueCommandHandler : IRequestHandler<SetConfigurationValueCommand, long>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public SetConfigurationValueCommandHandler(IApplicationDbContext context)
|
||||
public SetConfigurationValueCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<long> Handle(SetConfigurationValueCommand request, CancellationToken cancellationToken)
|
||||
|
||||
@@ -3,7 +3,7 @@ namespace CMSMicroservice.Application.NetworkMembershipCQ.Commands.JoinNetwork;
|
||||
/// <summary>
|
||||
/// Command برای افزودن کاربر به شبکه دوتایی (Binary Network)
|
||||
/// </summary>
|
||||
public record JoinNetworkCommand : IRequest<Unit>
|
||||
public record JoinNetworkCommand : IRequest<long>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه کاربر که میخواهد به شبکه بپیوندد
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
namespace CMSMicroservice.Application.NetworkMembershipCQ.Commands.JoinNetwork;
|
||||
|
||||
public class JoinNetworkCommandHandler : IRequestHandler<JoinNetworkCommand, Unit>
|
||||
public class JoinNetworkCommandHandler : IRequestHandler<JoinNetworkCommand, long>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public JoinNetworkCommandHandler(IApplicationDbContext context)
|
||||
public JoinNetworkCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(JoinNetworkCommand request, CancellationToken cancellationToken)
|
||||
public async Task<long> Handle(JoinNetworkCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// بررسی وجود کاربر
|
||||
var user = await _context.Users
|
||||
@@ -69,12 +73,12 @@ public class JoinNetworkCommandHandler : IRequestHandler<JoinNetworkCommand, Uni
|
||||
NewLegPosition = request.LegPosition,
|
||||
Action = NetworkMembershipAction.Join,
|
||||
Reason = request.Reason ?? "عضویت در شبکه",
|
||||
PerformedBy = "System" // TODO: باید از Current User گرفته شود
|
||||
PerformedBy = _currentUser.GetPerformedBy()
|
||||
};
|
||||
|
||||
await _context.NetworkMembershipHistories.AddAsync(history, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
return user.Id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,14 @@ namespace CMSMicroservice.Application.NetworkMembershipCQ.Commands.MoveInNetwork
|
||||
public class MoveInNetworkCommandHandler : IRequestHandler<MoveInNetworkCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public MoveInNetworkCommandHandler(IApplicationDbContext context)
|
||||
public MoveInNetworkCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(MoveInNetworkCommand request, CancellationToken cancellationToken)
|
||||
|
||||
@@ -3,10 +3,14 @@ namespace CMSMicroservice.Application.NetworkMembershipCQ.Commands.RemoveFromNet
|
||||
public class RemoveFromNetworkCommandHandler : IRequestHandler<RemoveFromNetworkCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public RemoveFromNetworkCommandHandler(IApplicationDbContext context)
|
||||
public RemoveFromNetworkCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(RemoveFromNetworkCommand request, CancellationToken cancellationToken)
|
||||
|
||||
Reference in New Issue
Block a user