feat: refactor week number handling to use WeekDefinitionId across multiple entities and queries
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Infrastructure.Persistence;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Data.Seeding;
|
||||
|
||||
/// <summary>
|
||||
/// Seeder برای پر کردن جدول WeekDefinitions
|
||||
/// هفته اول سیستم: 2025-W46 میلادی = 1404-W35 شمسی
|
||||
/// شروع هفته شمسی: شنبه | شروع هفته میلادی ISO: دوشنبه
|
||||
/// </summary>
|
||||
public class WeekDefinitionSeeder
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly ILogger<WeekDefinitionSeeder> _logger;
|
||||
private readonly PersianCalendar _persianCalendar;
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ شروع هفته اول سیستم (شنبه 17 آبان 1404 = 8 نوامبر 2025)
|
||||
/// این شنبه در هفته 46 میلادی (ISO) و هفته 35 شمسی قرار دارد
|
||||
/// </summary>
|
||||
private static readonly DateTime BaseWeekStartDate = new DateTime(2025, 11, 8); // شنبه 8 نوامبر 2025
|
||||
|
||||
public WeekDefinitionSeeder(
|
||||
ApplicationDbContext context,
|
||||
ILogger<WeekDefinitionSeeder> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
_persianCalendar = new PersianCalendar();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seed هفتهها از هفته مبدأ تا یک سال بعد
|
||||
/// </summary>
|
||||
public async Task SeedAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
_logger.LogInformation("=== WeekDefinitionSeeder: Starting ===");
|
||||
_logger.LogInformation("Base week starts at: {BaseDate:yyyy-MM-dd} (Saturday)", BaseWeekStartDate);
|
||||
|
||||
try
|
||||
{
|
||||
var existingCount = await _context.WeekDefinitions.CountAsync(cancellationToken);
|
||||
|
||||
if (existingCount > 0)
|
||||
{
|
||||
_logger.LogInformation("WeekDefinitions already has {Count} records. Checking for missing weeks...", existingCount);
|
||||
}
|
||||
|
||||
// شروع از هفته مبدأ
|
||||
var startDate = BaseWeekStartDate;
|
||||
// پایان تا یک سال بعد از الان
|
||||
var endDate = GetEndOfWeek(DateTime.Today.AddYears(1));
|
||||
|
||||
var currentDate = startDate;
|
||||
var addedCount = 0;
|
||||
|
||||
while (currentDate <= endDate)
|
||||
{
|
||||
var weekStart = currentDate; // شنبه
|
||||
var weekEnd = currentDate.AddDays(6); // جمعه
|
||||
|
||||
// محاسبه شماره ترتیبی هفته (از 1 شروع میشود)
|
||||
var weekOrder = CalculateWeekOrder(weekStart);
|
||||
|
||||
// نام نمایشی: هفته یکم، هفته دوم، ...
|
||||
var displayName = GetPersianOrdinalWeekName(weekOrder);
|
||||
|
||||
// شماره هفته میلادی ISO (بر اساس دوشنبه)
|
||||
var gregorianWeekNumber = GetISOWeekNumber(weekStart);
|
||||
|
||||
// شماره هفته شمسی (بر اساس شنبه)
|
||||
var persianWeekNumber = GetPersianWeekNumber(weekStart);
|
||||
|
||||
// چک کنیم که این هفته قبلاً ثبت نشده باشه
|
||||
var exists = await _context.WeekDefinitions
|
||||
.AnyAsync(w => w.StartDate == weekStart, cancellationToken);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
var weekDefinition = new WeekDefinition
|
||||
{
|
||||
WeekOrder = weekOrder,
|
||||
DisplayName = displayName,
|
||||
GregorianWeekNumber = gregorianWeekNumber,
|
||||
PersianWeekNumber = persianWeekNumber,
|
||||
StartDate = weekStart,
|
||||
EndDate = weekEnd,
|
||||
GregorianYear = weekStart.Year,
|
||||
PersianYear = _persianCalendar.GetYear(weekStart),
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
_context.WeekDefinitions.Add(weekDefinition);
|
||||
addedCount++;
|
||||
|
||||
_logger.LogDebug("Added: {DisplayName} | {GregorianWeek} | {PersianWeek} | {Start:yyyy-MM-dd} - {End:yyyy-MM-dd}",
|
||||
displayName, gregorianWeekNumber, persianWeekNumber, weekStart, weekEnd);
|
||||
}
|
||||
|
||||
// رفتن به هفته بعد (7 روز)
|
||||
currentDate = currentDate.AddDays(7);
|
||||
}
|
||||
|
||||
if (addedCount > 0)
|
||||
{
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
_logger.LogInformation("Successfully added {Count} week definitions", addedCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("No new week definitions needed");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error seeding WeekDefinitions");
|
||||
throw;
|
||||
}
|
||||
|
||||
_logger.LogInformation("=== WeekDefinitionSeeder: Completed ===");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// محاسبه شماره ترتیبی هفته بر اساس فاصله از هفته مبدأ
|
||||
/// هفته مبدأ = 1، هفته بعد = 2، ...
|
||||
/// </summary>
|
||||
private static int CalculateWeekOrder(DateTime weekStartDate)
|
||||
{
|
||||
var daysDiff = (weekStartDate - BaseWeekStartDate).Days;
|
||||
var weeksDiff = daysDiff / 7;
|
||||
return weeksDiff + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// تبدیل عدد به نام ترتیبی فارسی
|
||||
/// 1 -> هفته یکم، 2 -> هفته دوم، ...
|
||||
/// </summary>
|
||||
private static string GetPersianOrdinalWeekName(int weekOrder)
|
||||
{
|
||||
var ordinals = new Dictionary<int, string>
|
||||
{
|
||||
{ 1, "یکم" }, { 2, "دوم" }, { 3, "سوم" }, { 4, "چهارم" }, { 5, "پنجم" },
|
||||
{ 6, "ششم" }, { 7, "هفتم" }, { 8, "هشتم" }, { 9, "نهم" }, { 10, "دهم" },
|
||||
{ 11, "یازدهم" }, { 12, "دوازدهم" }, { 13, "سیزدهم" }, { 14, "چهاردهم" }, { 15, "پانزدهم" },
|
||||
{ 16, "شانزدهم" }, { 17, "هفدهم" }, { 18, "هجدهم" }, { 19, "نوزدهم" }, { 20, "بیستم" },
|
||||
{ 21, "بیست و یکم" }, { 22, "بیست و دوم" }, { 23, "بیست و سوم" }, { 24, "بیست و چهارم" }, { 25, "بیست و پنجم" },
|
||||
{ 26, "بیست و ششم" }, { 27, "بیست و هفتم" }, { 28, "بیست و هشتم" }, { 29, "بیست و نهم" }, { 30, "سیام" },
|
||||
{ 31, "سی و یکم" }, { 32, "سی و دوم" }, { 33, "سی و سوم" }, { 34, "سی و چهارم" }, { 35, "سی و پنجم" },
|
||||
{ 36, "سی و ششم" }, { 37, "سی و هفتم" }, { 38, "سی و هشتم" }, { 39, "سی و نهم" }, { 40, "چهلم" },
|
||||
{ 41, "چهل و یکم" }, { 42, "چهل و دوم" }, { 43, "چهل و سوم" }, { 44, "چهل و چهارم" }, { 45, "چهل و پنجم" },
|
||||
{ 46, "چهل و ششم" }, { 47, "چهل و هفتم" }, { 48, "چهل و هشتم" }, { 49, "چهل و نهم" }, { 50, "پنجاهم" },
|
||||
{ 51, "پنجاه و یکم" }, { 52, "پنجاه و دوم" }, { 53, "پنجاه و سوم" }, { 54, "پنجاه و چهارم" }, { 55, "پنجاه و پنجم" },
|
||||
{ 56, "پنجاه و ششم" }, { 57, "پنجاه و هفتم" }, { 58, "پنجاه و هشتم" }, { 59, "پنجاه و نهم" }, { 60, "شصتم" }
|
||||
};
|
||||
|
||||
if (ordinals.TryGetValue(weekOrder, out var ordinal))
|
||||
{
|
||||
return $"هفته {ordinal}";
|
||||
}
|
||||
|
||||
// برای اعداد بزرگتر از 60
|
||||
return $"هفته {weekOrder}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پیدا کردن شنبه این هفته (شروع هفته شمسی)
|
||||
/// </summary>
|
||||
private static DateTime GetStartOfWeek(DateTime date)
|
||||
{
|
||||
var diff = (7 + (date.DayOfWeek - DayOfWeek.Saturday)) % 7;
|
||||
return date.AddDays(-diff).Date;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پیدا کردن جمعه این هفته (پایان هفته شمسی)
|
||||
/// </summary>
|
||||
private static DateTime GetEndOfWeek(DateTime date)
|
||||
{
|
||||
return GetStartOfWeek(date).AddDays(6);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// شماره هفته میلادی ISO 8601
|
||||
/// هفته ISO از دوشنبه شروع میشود
|
||||
/// برای تاریخ شنبه، باید دوشنبه همان هفته را پیدا کنیم (2 روز بعد)
|
||||
/// </summary>
|
||||
private static string GetISOWeekNumber(DateTime saturdayDate)
|
||||
{
|
||||
// شنبه + 2 روز = دوشنبه همان هفته ISO
|
||||
var mondayOfWeek = saturdayDate.AddDays(2);
|
||||
|
||||
// محاسبه شماره هفته ISO
|
||||
var cal = CultureInfo.InvariantCulture.Calendar;
|
||||
var weekNumber = cal.GetWeekOfYear(mondayOfWeek, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
|
||||
var year = mondayOfWeek.Year;
|
||||
|
||||
// تصحیح سال برای هفتههای لبهای
|
||||
if (weekNumber == 1 && mondayOfWeek.Month == 12)
|
||||
{
|
||||
year++;
|
||||
}
|
||||
else if (weekNumber >= 52 && mondayOfWeek.Month == 1)
|
||||
{
|
||||
year--;
|
||||
}
|
||||
|
||||
return $"{year}-W{weekNumber:D2}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// شماره هفته شمسی
|
||||
/// هفته شمسی از شنبه شروع میشود
|
||||
/// </summary>
|
||||
private string GetPersianWeekNumber(DateTime saturdayDate)
|
||||
{
|
||||
var persianYear = _persianCalendar.GetYear(saturdayDate);
|
||||
var dayOfYear = _persianCalendar.GetDayOfYear(saturdayDate);
|
||||
|
||||
// اول فروردین این سال
|
||||
var firstDayOfYear = _persianCalendar.ToDateTime(persianYear, 1, 1, 0, 0, 0, 0);
|
||||
|
||||
// پیدا کردن اولین شنبه سال
|
||||
var daysUntilFirstSaturday = ((int)DayOfWeek.Saturday - (int)firstDayOfYear.DayOfWeek + 7) % 7;
|
||||
|
||||
// اگر اول فروردین شنبه باشه، daysUntilFirstSaturday = 0
|
||||
// در غیر این صورت روزهای قبل از اولین شنبه، هفته 0 یا هفته آخر سال قبل هستند
|
||||
|
||||
int weekNumber;
|
||||
if (daysUntilFirstSaturday == 0)
|
||||
{
|
||||
// اول فروردین شنبه است
|
||||
weekNumber = ((dayOfYear - 1) / 7) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// روزهای قبل از اولین شنبه
|
||||
if (dayOfYear <= daysUntilFirstSaturday)
|
||||
{
|
||||
// این روزها متعلق به آخرین هفته سال قبل هستند
|
||||
// اما برای سادگی، هفته 1 در نظر میگیریم
|
||||
weekNumber = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
weekNumber = ((dayOfYear - daysUntilFirstSaturday - 1) / 7) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $"{persianYear}-W{weekNumber:D2}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user