Add validators and services for Product Galleries and Product Tags

- Implemented Create, Delete, Get, and Update validators for Product Galleries.
- Added Create, Delete, Get, and Update validators for Product Tags.
- Created service classes for handling Discount Categories, Discount Orders, Discount Products, Discount Shopping Cart, Product Categories, Product Galleries, and Product Tags.
- Each service class integrates with CQRS for command and query handling.
- Established mapping profiles for Product Galleries.
This commit is contained in:
masoodafar-web
2025-12-04 02:40:49 +03:30
parent 40d54d08fc
commit f0f48118e7
436 changed files with 33159 additions and 2005 deletions

View File

@@ -0,0 +1,172 @@
using CMSMicroservice.Domain.Enums;
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetWithdrawalReports;
/// <summary>
/// Query برای دریافت گزارش برداشت‌ها
/// </summary>
public record GetWithdrawalReportsQuery : IRequest<WithdrawalReportsDto>
{
/// <summary>
/// تاریخ شروع
/// </summary>
public DateTime? StartDate { get; init; }
/// <summary>
/// تاریخ پایان
/// </summary>
public DateTime? EndDate { get; init; }
/// <summary>
/// نوع بازه زمانی (روزانه، هفتگی، ماهانه)
/// </summary>
public ReportPeriodType PeriodType { get; init; } = ReportPeriodType.Daily;
/// <summary>
/// فیلتر بر اساس وضعیت
/// </summary>
public CommissionPayoutStatus? Status { get; init; }
/// <summary>
/// شناسه کاربر (برای فیلتر کردن بر اساس کاربر خاص)
/// </summary>
public long? UserId { get; init; }
}
/// <summary>
/// نوع بازه زمانی گزارش
/// </summary>
public enum ReportPeriodType
{
Daily = 1,
Weekly = 2,
Monthly = 3
}
/// <summary>
/// DTO گزارش برداشت‌ها
/// </summary>
public class WithdrawalReportsDto
{
/// <summary>
/// گزارش‌های بازه‌های زمانی
/// </summary>
public List<PeriodReportDto> PeriodReports { get; set; } = new();
/// <summary>
/// خلاصه کلی
/// </summary>
public WithdrawalSummaryDto Summary { get; set; } = new();
}
/// <summary>
/// گزارش یک بازه زمانی
/// </summary>
public class PeriodReportDto
{
/// <summary>
/// عنوان بازه (مثلاً "هفته 1" یا "دی ماه")
/// </summary>
public string PeriodLabel { get; set; } = string.Empty;
/// <summary>
/// تاریخ شروع بازه
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// تاریخ پایان بازه
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// تعداد کل درخواست‌ها
/// </summary>
public int TotalRequests { get; set; }
/// <summary>
/// تعداد درخواست‌های در انتظار
/// </summary>
public int PendingCount { get; set; }
/// <summary>
/// تعداد درخواست‌های تأیید شده
/// </summary>
public int ApprovedCount { get; set; }
/// <summary>
/// تعداد درخواست‌های رد شده
/// </summary>
public int RejectedCount { get; set; }
/// <summary>
/// تعداد درخواست‌های موفق
/// </summary>
public int CompletedCount { get; set; }
/// <summary>
/// تعداد درخواست‌های ناموفق
/// </summary>
public int FailedCount { get; set; }
/// <summary>
/// مجموع مبلغ درخواست‌ها
/// </summary>
public long TotalAmount { get; set; }
/// <summary>
/// مجموع مبلغ پرداخت شده
/// </summary>
public long PaidAmount { get; set; }
/// <summary>
/// مجموع مبلغ در انتظار
/// </summary>
public long PendingAmount { get; set; }
}
/// <summary>
/// خلاصه کلی برداشت‌ها
/// </summary>
public class WithdrawalSummaryDto
{
/// <summary>
/// تعداد کل درخواست‌ها
/// </summary>
public int TotalRequests { get; set; }
/// <summary>
/// مجموع کل مبالغ
/// </summary>
public long TotalAmount { get; set; }
/// <summary>
/// مجموع مبلغ پرداخت شده
/// </summary>
public long TotalPaid { get; set; }
/// <summary>
/// مجموع مبلغ در انتظار
/// </summary>
public long TotalPending { get; set; }
/// <summary>
/// مجموع مبلغ رد شده
/// </summary>
public long TotalRejected { get; set; }
/// <summary>
/// میانگین مبلغ هر درخواست
/// </summary>
public long AverageAmount { get; set; }
/// <summary>
/// تعداد کاربران منحصر به فرد
/// </summary>
public int UniqueUsers { get; set; }
/// <summary>
/// درصد موفقیت (Completed / Total)
/// </summary>
public decimal SuccessRate { get; set; }
}

View File

@@ -0,0 +1,213 @@
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Enums;
using Microsoft.EntityFrameworkCore;
namespace CMSMicroservice.Application.CommissionCQ.Queries.GetWithdrawalReports;
/// <summary>
/// Handler برای دریافت گزارش برداشت‌ها
/// </summary>
public class GetWithdrawalReportsQueryHandler : IRequestHandler<GetWithdrawalReportsQuery, WithdrawalReportsDto>
{
private readonly IApplicationDbContext _context;
public GetWithdrawalReportsQueryHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<WithdrawalReportsDto> Handle(GetWithdrawalReportsQuery request, CancellationToken cancellationToken)
{
// تعیین بازه زمانی پیش‌فرض (30 روز گذشته)
var endDate = request.EndDate ?? DateTime.UtcNow;
var startDate = request.StartDate ?? endDate.AddDays(-30);
// Query پایه
var query = _context.UserCommissionPayouts
.Where(p => p.Created >= startDate && p.Created <= endDate);
// فیلتر بر اساس وضعیت
if (request.Status.HasValue)
{
query = query.Where(p => p.Status == request.Status.Value);
}
// فیلتر بر اساس کاربر
if (request.UserId.HasValue)
{
query = query.Where(p => p.UserId == request.UserId.Value);
}
var payouts = await query
.OrderBy(p => p.Created)
.ToListAsync(cancellationToken);
// گروه‌بندی بر اساس نوع بازه
var periodReports = request.PeriodType switch
{
ReportPeriodType.Daily => GroupByDay(payouts, startDate, endDate),
ReportPeriodType.Weekly => GroupByWeek(payouts, startDate, endDate),
ReportPeriodType.Monthly => GroupByMonth(payouts, startDate, endDate),
_ => GroupByDay(payouts, startDate, endDate)
};
// محاسبه خلاصه کلی
var summary = CalculateSummary(payouts);
return new WithdrawalReportsDto
{
PeriodReports = periodReports,
Summary = summary
};
}
private List<PeriodReportDto> GroupByDay(List<Domain.Entities.Commission.UserCommissionPayout> payouts, DateTime startDate, DateTime endDate)
{
var reports = new List<PeriodReportDto>();
var currentDate = startDate.Date;
while (currentDate <= endDate.Date)
{
var dayPayouts = payouts.Where(p => p.Created.Date == currentDate).ToList();
reports.Add(new PeriodReportDto
{
PeriodLabel = currentDate.ToString("yyyy-MM-dd"),
StartDate = currentDate,
EndDate = currentDate.AddDays(1).AddSeconds(-1),
TotalRequests = dayPayouts.Count,
PendingCount = dayPayouts.Count(p => p.Status == CommissionPayoutStatus.Pending ||
p.Status == CommissionPayoutStatus.WithdrawRequested),
ApprovedCount = 0, // تایید جداگانه نداریم
RejectedCount = dayPayouts.Count(p => p.Status == CommissionPayoutStatus.Cancelled),
CompletedCount = dayPayouts.Count(p => p.Status == CommissionPayoutStatus.Withdrawn),
FailedCount = dayPayouts.Count(p => p.Status == CommissionPayoutStatus.PaymentFailed),
TotalAmount = dayPayouts.Sum(p => p.TotalAmount),
PaidAmount = dayPayouts.Where(p => p.Status == CommissionPayoutStatus.Withdrawn).Sum(p => p.TotalAmount),
PendingAmount = dayPayouts.Where(p => p.Status == CommissionPayoutStatus.Pending ||
p.Status == CommissionPayoutStatus.WithdrawRequested).Sum(p => p.TotalAmount)
});
currentDate = currentDate.AddDays(1);
}
return reports;
}
private List<PeriodReportDto> GroupByWeek(List<Domain.Entities.Commission.UserCommissionPayout> payouts, DateTime startDate, DateTime endDate)
{
var reports = new List<PeriodReportDto>();
var currentWeekStart = startDate.Date;
int weekNumber = 1;
while (currentWeekStart <= endDate)
{
var weekEnd = currentWeekStart.AddDays(7).AddSeconds(-1);
if (weekEnd > endDate)
weekEnd = endDate;
var weekPayouts = payouts.Where(p => p.Created >= currentWeekStart && p.Created <= weekEnd).ToList();
reports.Add(new PeriodReportDto
{
PeriodLabel = $"هفته {weekNumber}",
StartDate = currentWeekStart,
EndDate = weekEnd,
TotalRequests = weekPayouts.Count,
PendingCount = weekPayouts.Count(p => p.Status == CommissionPayoutStatus.Pending ||
p.Status == CommissionPayoutStatus.WithdrawRequested),
ApprovedCount = 0, // تایید جداگانه نداریم
RejectedCount = weekPayouts.Count(p => p.Status == CommissionPayoutStatus.Cancelled),
CompletedCount = weekPayouts.Count(p => p.Status == CommissionPayoutStatus.Withdrawn),
FailedCount = weekPayouts.Count(p => p.Status == CommissionPayoutStatus.PaymentFailed),
TotalAmount = weekPayouts.Sum(p => p.TotalAmount),
PaidAmount = weekPayouts.Where(p => p.Status == CommissionPayoutStatus.Withdrawn).Sum(p => p.TotalAmount),
PendingAmount = weekPayouts.Where(p => p.Status == CommissionPayoutStatus.Pending ||
p.Status == CommissionPayoutStatus.WithdrawRequested).Sum(p => p.TotalAmount)
});
currentWeekStart = currentWeekStart.AddDays(7);
weekNumber++;
}
return reports;
}
private List<PeriodReportDto> GroupByMonth(List<Domain.Entities.Commission.UserCommissionPayout> payouts, DateTime startDate, DateTime endDate)
{
var reports = new List<PeriodReportDto>();
var currentMonthStart = new DateTime(startDate.Year, startDate.Month, 1);
while (currentMonthStart <= endDate)
{
var monthEnd = currentMonthStart.AddMonths(1).AddSeconds(-1);
if (monthEnd > endDate)
monthEnd = endDate;
var monthPayouts = payouts.Where(p => p.Created >= currentMonthStart && p.Created <= monthEnd).ToList();
var persianMonthName = GetPersianMonthName(currentMonthStart.Month);
reports.Add(new PeriodReportDto
{
PeriodLabel = $"{persianMonthName} {currentMonthStart.Year}",
StartDate = currentMonthStart,
EndDate = monthEnd,
TotalRequests = monthPayouts.Count,
PendingCount = monthPayouts.Count(p => p.Status == CommissionPayoutStatus.Pending ||
p.Status == CommissionPayoutStatus.WithdrawRequested),
ApprovedCount = 0, // تایید جداگانه نداریم
RejectedCount = monthPayouts.Count(p => p.Status == CommissionPayoutStatus.Cancelled),
CompletedCount = monthPayouts.Count(p => p.Status == CommissionPayoutStatus.Withdrawn),
FailedCount = monthPayouts.Count(p => p.Status == CommissionPayoutStatus.PaymentFailed),
TotalAmount = monthPayouts.Sum(p => p.TotalAmount),
PaidAmount = monthPayouts.Where(p => p.Status == CommissionPayoutStatus.Withdrawn).Sum(p => p.TotalAmount),
PendingAmount = monthPayouts.Where(p => p.Status == CommissionPayoutStatus.Pending ||
p.Status == CommissionPayoutStatus.WithdrawRequested).Sum(p => p.TotalAmount)
});
currentMonthStart = currentMonthStart.AddMonths(1);
}
return reports;
}
private WithdrawalSummaryDto CalculateSummary(List<Domain.Entities.Commission.UserCommissionPayout> payouts)
{
var totalRequests = payouts.Count;
var completedCount = payouts.Count(p => p.Status == CommissionPayoutStatus.Withdrawn);
return new WithdrawalSummaryDto
{
TotalRequests = totalRequests,
TotalAmount = payouts.Sum(p => p.TotalAmount),
TotalPaid = payouts.Where(p => p.Status == CommissionPayoutStatus.Withdrawn).Sum(p => p.TotalAmount),
TotalPending = payouts.Where(p => p.Status == CommissionPayoutStatus.Pending ||
p.Status == CommissionPayoutStatus.WithdrawRequested).Sum(p => p.TotalAmount),
TotalRejected = payouts.Where(p => p.Status == CommissionPayoutStatus.Cancelled).Sum(p => p.TotalAmount),
AverageAmount = totalRequests > 0 ? payouts.Sum(p => p.TotalAmount) / totalRequests : 0,
UniqueUsers = payouts.Select(p => p.UserId).Distinct().Count(),
SuccessRate = totalRequests > 0 ? (decimal)completedCount / totalRequests * 100 : 0
};
}
private string GetPersianMonthName(int month)
{
return month switch
{
1 => "فروردین",
2 => "اردیبهشت",
3 => "خرداد",
4 => "تیر",
5 => "مرداد",
6 => "شهریور",
7 => "مهر",
8 => "آبان",
9 => "آذر",
10 => "دی",
11 => "بهمن",
12 => "اسفند",
_ => month.ToString()
};
}
}