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; /// /// Seeder برای پر کردن جدول WeekDefinitions /// هفته اول سیستم: 2025-W46 میلادی = 1404-W35 شمسی /// شروع هفته شمسی: شنبه | شروع هفته میلادی ISO: دوشنبه /// public class WeekDefinitionSeeder { private readonly ApplicationDbContext _context; private readonly ILogger _logger; private readonly PersianCalendar _persianCalendar; /// /// تاریخ شروع هفته اول سیستم (شنبه 17 آبان 1404 = 8 نوامبر 2025) /// این شنبه در هفته 46 میلادی (ISO) و هفته 35 شمسی قرار دارد /// private static readonly DateTime BaseWeekStartDate = new DateTime(2025, 11, 8); // شنبه 8 نوامبر 2025 public WeekDefinitionSeeder( ApplicationDbContext context, ILogger logger) { _context = context; _logger = logger; _persianCalendar = new PersianCalendar(); } /// /// Seed هفته‌ها از هفته مبدأ تا یک سال بعد /// 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).Date.AddHours(23).AddMinutes(59).AddSeconds(59); // جمعه 23:59:59 // محاسبه شماره ترتیبی هفته (از 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 ==="); } /// /// محاسبه شماره ترتیبی هفته بر اساس فاصله از هفته مبدأ /// هفته مبدأ = 1، هفته بعد = 2، ... /// private static int CalculateWeekOrder(DateTime weekStartDate) { var daysDiff = (weekStartDate - BaseWeekStartDate).Days; var weeksDiff = daysDiff / 7; return weeksDiff + 1; } /// /// تبدیل عدد به نام ترتیبی فارسی /// 1 -> هفته یکم، 2 -> هفته دوم، ... /// private static string GetPersianOrdinalWeekName(int weekOrder) { var ordinals = new Dictionary { { 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}"; } /// /// پیدا کردن شنبه این هفته (شروع هفته شمسی) /// private static DateTime GetStartOfWeek(DateTime date) { var diff = (7 + (date.DayOfWeek - DayOfWeek.Saturday)) % 7; return date.AddDays(-diff).Date; } /// /// پیدا کردن جمعه این هفته (پایان هفته شمسی) /// private static DateTime GetEndOfWeek(DateTime date) { return GetStartOfWeek(date).AddDays(6); } /// /// شماره هفته میلادی ISO 8601 /// هفته ISO از دوشنبه شروع می‌شود /// برای تاریخ شنبه، باید دوشنبه همان هفته را پیدا کنیم (2 روز بعد) /// 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}"; } /// /// شماره هفته شمسی /// هفته شمسی از شنبه شروع می‌شود /// 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}"; } }