feat: add IsActive field to UserClubFeatures for admin management

This commit is contained in:
masoodafar-web
2025-12-12 01:40:26 +03:30
parent aa66ca10c8
commit ff1c1d5d61
68 changed files with 11456 additions and 198 deletions
@@ -0,0 +1,13 @@
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetAvailableWeeks;
/// <summary>
/// دریافت لیست هفته‌های قابل انتخاب برای محاسبه کمیسیون
/// </summary>
public class GetAvailableWeeksQuery : IRequest<GetAvailableWeeksResponseDto>
{
/// <summary>تعداد هفته‌های آینده برای نمایش (پیش‌فرض: 4)</summary>
public int FutureWeeksCount { get; init; } = 4;
/// <summary>تعداد هفته‌های گذشته برای نمایش (پیش‌فرض: 12)</summary>
public int PastWeeksCount { get; init; } = 12;
}
@@ -0,0 +1,132 @@
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Enums;
using Microsoft.EntityFrameworkCore;
using System.Globalization;
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetAvailableWeeks;
public class GetAvailableWeeksQueryHandler : IRequestHandler<GetAvailableWeeksQuery, GetAvailableWeeksResponseDto>
{
private readonly IApplicationDbContext _context;
public GetAvailableWeeksQueryHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<GetAvailableWeeksResponseDto> Handle(
GetAvailableWeeksQuery request,
CancellationToken cancellationToken)
{
var currentDate = DateTime.Now;
var currentWeekNumber = GetWeekNumber(currentDate);
// دریافت هفته‌های محاسبه شده از دیتابیس
var calculatedPools = await _context.WeeklyCommissionPools
.Where(p => p.IsCalculated)
.OrderByDescending(p => p.WeekNumber)
.Take(request.PastWeeksCount)
.ToListAsync(cancellationToken);
// دریافت لاگ‌های اجرا
var executionLogs = await _context.WorkerExecutionLogs
.Where(log => log.Status == WorkerExecutionStatus.Success ||
log.Status == WorkerExecutionStatus.Failed)
.GroupBy(log => log.WeekNumber)
.Select(g => new
{
WeekNumber = g.Key,
LastLog = g.OrderByDescending(l => l.StartedAt).First()
})
.ToDictionaryAsync(x => x.WeekNumber, x => x.LastLog, cancellationToken);
var allWeeks = new List<WeekInfoDto>();
// هفته جاری
var currentWeekInfo = CreateWeekInfo(currentDate, currentWeekNumber, calculatedPools, executionLogs);
// هفته‌های گذشته (12 هفته)
var pastWeeks = new List<WeekInfoDto>();
for (int i = 1; i <= request.PastWeeksCount; i++)
{
var pastDate = currentDate.AddDays(-7 * i);
var weekNumber = GetWeekNumber(pastDate);
pastWeeks.Add(CreateWeekInfo(pastDate, weekNumber, calculatedPools, executionLogs));
}
// هفته‌های آینده (4 هفته)
var futureWeeks = new List<WeekInfoDto>();
for (int i = 1; i <= request.FutureWeeksCount; i++)
{
var futureDate = currentDate.AddDays(7 * i);
var weekNumber = GetWeekNumber(futureDate);
futureWeeks.Add(CreateWeekInfo(futureDate, weekNumber, calculatedPools, executionLogs));
}
// تفکیک به calculated و pending
var calculatedWeeks = pastWeeks.Where(w => w.IsCalculated).ToList();
var pendingWeeks = pastWeeks.Where(w => !w.IsCalculated).ToList();
return new GetAvailableWeeksResponseDto
{
CurrentWeek = currentWeekInfo,
CalculatedWeeks = calculatedWeeks,
PendingWeeks = pendingWeeks,
FutureWeeks = futureWeeks
};
}
private WeekInfoDto CreateWeekInfo(
DateTime date,
string weekNumber,
List<Domain.Entities.Commission.WeeklyCommissionPool> calculatedPools,
Dictionary<string, Domain.Entities.Commission.WorkerExecutionLog> executionLogs)
{
var (startDate, endDate) = GetWeekRange(date);
var pool = calculatedPools.FirstOrDefault(p => p.WeekNumber == weekNumber);
var log = executionLogs.GetValueOrDefault(weekNumber);
var isCalculated = pool != null && pool.IsCalculated;
var displayText = $"{weekNumber} ({startDate:yyyy/MM/dd} - {endDate:yyyy/MM/dd})";
if (isCalculated)
{
displayText += " ✅ محاسبه شده";
}
return new WeekInfoDto
{
WeekNumber = weekNumber,
StartDate = startDate,
EndDate = endDate,
IsCalculated = isCalculated,
CalculatedAt = pool?.CalculatedAt,
LastExecutionStatus = log?.Status.ToString(),
TotalPoolAmount = pool?.TotalPoolAmount,
EligibleUsersCount = pool?.UserCommissionPayouts?.Count ?? 0,
DisplayText = displayText
};
}
private static string GetWeekNumber(DateTime date)
{
var calendar = CultureInfo.InvariantCulture.Calendar;
var weekOfYear = calendar.GetWeekOfYear(
date,
CalendarWeekRule.FirstFourDayWeek,
DayOfWeek.Monday);
return $"{date.Year}-W{weekOfYear:D2}";
}
private static (DateTime startDate, DateTime endDate) GetWeekRange(DateTime date)
{
var dayOfWeek = (int)date.DayOfWeek;
var daysToMonday = dayOfWeek == 0 ? 6 : dayOfWeek - 1; // اگر یکشنبه باشد، 6 روز عقب برو
var startDate = date.Date.AddDays(-daysToMonday);
var endDate = startDate.AddDays(6);
return (startDate, endDate);
}
}
@@ -0,0 +1,46 @@
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetAvailableWeeks;
public class GetAvailableWeeksResponseDto
{
/// <summary>هفته جاری</summary>
public required WeekInfoDto CurrentWeek { get; init; }
/// <summary>هفته‌های محاسبه شده (از جدیدترین به قدیمی‌ترین)</summary>
public required List<WeekInfoDto> CalculatedWeeks { get; init; }
/// <summary>هفته‌های محاسبه نشده (از جدیدترین به قدیمی‌ترین)</summary>
public required List<WeekInfoDto> PendingWeeks { get; init; }
/// <summary>هفته‌های آینده قابل انتخاب</summary>
public required List<WeekInfoDto> FutureWeeks { get; init; }
}
public class WeekInfoDto
{
/// <summary>شماره هفته (YYYY-Www)</summary>
public required string WeekNumber { get; init; }
/// <summary>تاریخ شروع هفته</summary>
public required DateTime StartDate { get; init; }
/// <summary>تاریخ پایان هفته</summary>
public required DateTime EndDate { get; init; }
/// <summary>آیا محاسبه شده؟</summary>
public bool IsCalculated { get; init; }
/// <summary>تاریخ محاسبه (اگر محاسبه شده باشد)</summary>
public DateTime? CalculatedAt { get; init; }
/// <summary>وضعیت اجرای آخرین محاسبه</summary>
public string? LastExecutionStatus { get; init; }
/// <summary>مبلغ کل استخر کمیسیون (اگر محاسبه شده باشد)</summary>
public long? TotalPoolAmount { get; init; }
/// <summary>تعداد کاربران واجد شرایط</summary>
public int? EligibleUsersCount { get; init; }
/// <summary>نمایش فارسی (برای UI)</summary>
public required string DisplayText { get; init; }
}
@@ -19,7 +19,7 @@ public class GetWithdrawalReportsQueryHandler : IRequestHandler<GetWithdrawalRep
public async Task<WithdrawalReportsDto> Handle(GetWithdrawalReportsQuery request, CancellationToken cancellationToken)
{
// تعیین بازه زمانی پیش‌فرض (30 روز گذشته)
var endDate = request.EndDate ?? DateTime.UtcNow;
var endDate = request.EndDate ?? DateTime.Now;
var startDate = request.StartDate ?? endDate.AddDays(-30);
// Query پایه
@@ -27,8 +27,8 @@ public class GetWorkerStatusQueryHandler : IRequestHandler<GetWorkerStatusQuery,
CurrentExecutionId = null,
CurrentWeekNumber = null,
CurrentStep = "Idle",
LastRunAt = DateTime.UtcNow.AddHours(-24),
NextScheduledRun = DateTime.UtcNow.AddDays(7),
LastRunAt = DateTime.Now.AddHours(-24),
NextScheduledRun = DateTime.Now.AddDays(7),
TotalExecutions = 48,
SuccessfulExecutions = 47,
FailedExecutions = 1