using Application.Abstractions.Messaging; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using SharedKernel.Extensions; using System.ComponentModel.DataAnnotations; using System.Globalization; namespace Admin.Pages.Stocks.MarketHoliday; /// /// KRX 휴장일 관리 — 목록(연도 필터)/추가/삭제. 수집 배치(KrxBackfill/MarketCalendar)의 영업일 판정에 사용되므로 /// 거래일을 휴장일로 잘못 등록하면 해당 날짜 데이터가 영구 결손된다 (추가/삭제 모두 confirm). /// public class IndexModel(IMediator mediator) : PageModel { public int? Year { get; private set; } public int Total { get; private set; } public List Years { get; private set; } = []; public List<( DateOnly Date, string DayOfWeek, string Name )> Data { get; private set; } = []; [BindProperty] public InputModel Input { get; set; } = new(); public sealed class InputModel { [Required] public DateOnly? Date { get; set; } [Required] [StringLength(50)] public string? Name { get; set; } } [BindProperty] public DateOnly DeleteDate { get; set; } public async Task OnGetAsync(int? year, CancellationToken ct) { Year = year; var result = await mediator.Send(new GetMarketHolidays.Query(year), ct); Total = result.Total; Years = [..result.Years]; Data = [..result.List.Select(c => ( c.Date, CultureInfo.GetCultureInfo("ko-KR").DateTimeFormat.GetDayName(c.Date.DayOfWeek), c.Name ))]; } public async Task OnPostAddAsync(int? year, CancellationToken ct) { if (!ModelState.IsValid || Input.Date is null || Input.Name is null) { TempData["ErrorMessages"] = ModelState.GetErrorMessages(); return RedirectToIndex(year); } var result = await mediator.Send(new AddMarketHoliday.Command(Input.Date.Value, Input.Name), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; } else { TempData["SuccessMessage"] = $"{Input.Date.Value:yyyy-MM-dd} ({Input.Name}) 휴장일이 등록되었습니다."; } return RedirectToIndex(year); } public async Task OnPostDeleteAsync(int? year, CancellationToken ct) { var result = await mediator.Send(new DeleteMarketHoliday.Command(DeleteDate), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; } else { TempData["SuccessMessage"] = $"{DeleteDate:yyyy-MM-dd} 휴장일이 삭제되었습니다."; } return RedirectToIndex(year); } private RedirectToPageResult RedirectToIndex(int? year) { return year.HasValue ? RedirectToPage("/Stocks/MarketHoliday/Index", new { year }) : RedirectToPage("/Stocks/MarketHoliday/Index"); } }