using Domain.Entities.Store.ValueObject; using SharedKernel.Extensions; using Application.Abstractions.Messaging; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.Rendering; using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Admin.Pages.Store.Coupon; public class WriteModel(IMediator mediator) : PageModel { public List Games { get; set; } = []; public List<(int ID, int GameID, string Name)> Products { get; set; } = []; [BindProperty] public InputModel Input { get; set; } = new(); public sealed class InputModel { [DisplayName("게임")] [Required(ErrorMessage = "{0}을(를) 선택하세요.")] [Range(1, int.MaxValue, ErrorMessage = "게임을 선택해 주세요.")] public int GameID { get; set; } [DisplayName("무형 상품")] [Required(ErrorMessage = "{0}을(를) 선택하세요.")] [Range(1, int.MaxValue, ErrorMessage = "상품을 선택해 주세요.")] public int ProductID { get; set; } [DisplayName("쿠폰명")] [Required(ErrorMessage = "{0}은(는) 필수입니다.")] [StringLength(200)] public string Name { get; set; } = null!; [DisplayName("사용 정책")] public CouponUsagePolicy UsagePolicy { get; set; } = CouponUsagePolicy.SingleUse; [DisplayName("만료 일시")] [DataType(DataType.DateTime)] public DateTime? ExpiresAt { get; set; } [DisplayName("재고 부족 알림 임계치")] [Range(0, int.MaxValue)] public int LowStockThreshold { get; set; } = 10; } public async Task OnGetAsync(CancellationToken ct) { await LoadDataAsync(ct); } public async Task OnPostAsync(CancellationToken ct) { if (!ModelState.IsValid) { TempData["ErrorMessages"] = ModelState.GetErrorMessages(); await LoadDataAsync(ct); return Page(); } var result = await mediator.Send(new CreateCoupon.Command( Input.ProductID, Input.GameID, Input.Name, Input.UsagePolicy, Input.ExpiresAt, Input.LowStockThreshold ), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; await LoadDataAsync(ct); return Page(); } TempData["SuccessMessage"] = $"{Input.Name} 쿠폰이 등록되었습니다. 코드 풀에서 CSV 업로드 진행하세요."; return RedirectToPage("/Store/Coupon/Codes", new { id = result.Value }); } private async Task LoadDataAsync(CancellationToken ct) { var gamesResult = await mediator.Send(new GetGames.Query(true), ct); Games = [.. gamesResult.List.Select(g => new SelectListItem { Value = g.ID.ToString(), Text = $"{g.KorName} ({g.Publisher})" })]; // 무형 상품만 (Coupon 은 무형 상품에 발급) var productsResult = await mediator.Send(new SearchProducts.Query(null, null, null, null, null, ProductType.Digital, true, 1, 1000), ct); Products = [.. productsResult.List.Select(p => (p.ID, p.GameID, p.Name))]; } }