using Domain.Entities.Store.ValueObject; using SharedKernel.Extensions; using Application.Abstractions.Messaging; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Infrastructure.Persistence.Identity; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using Application.Features.Admin.Store.Order.RequestCouponsRefund; namespace Admin.Pages.Store.Order; public class DetailModel(IMediator mediator, UserManager userManager) : PageModel { public GetOrder.Response? Data { get; private set; } [BindProperty] public RefundRequest Refund { get; set; } = new(); public sealed class RefundRequest { [DisplayName("환불 유형")] public RefundType Type { get; set; } = RefundType.Cancel; [DisplayName("환불 금액(P)")] [Range(1, int.MaxValue, ErrorMessage = "환불 금액은 1P 이상이어야 합니다.")] public int Amount { get; set; } [DisplayName("사유")] [Required(ErrorMessage = "{0}는 필수입니다.")] [StringLength(500)] public string Reason { get; set; } = ""; } public async Task OnGetAsync(int id, CancellationToken ct) { await LoadOrderAsync(id, ct); } public async Task OnPostRequestCouponsRefundAsync(int id, int orderItemID, List couponCodeIds, CouponPostRefundAction action, string reason, CancellationToken ct) { if (couponCodeIds is null || couponCodeIds.Count == 0) { TempData["ErrorMessages"] = "환불할 쿠폰을 1개 이상 선택해 주세요."; return RedirectToPage("/Store/Order/Detail", new { id }); } if (string.IsNullOrWhiteSpace(reason)) { TempData["ErrorMessages"] = "환불 사유는 필수입니다."; return RedirectToPage("/Store/Order/Detail", new { id }); } var lines = couponCodeIds.Distinct().Select(c => new CouponRefundLine(orderItemID, c, action)).ToList(); var result = await mediator.Send(new Application.Features.Admin.Store.Order.RequestCouponsRefund.Command(id, lines, reason), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; } else { TempData["SuccessMessage"] = $"쿠폰 {lines.Count}건 환불 요청이 등록되었습니다. (RefundID={result.Value}) — '환불 이력' 표에서 '실행' 버튼으로 처리하세요."; } return RedirectToPage("/Store/Order/Detail", new { id }); } public async Task OnPostRequestRefundAsync(int id, CancellationToken ct) { if (!ModelState.IsValid) { TempData["ErrorMessages"] = ModelState.GetErrorMessages(); return RedirectToPage("/Store/Order/Detail", new { id }); } var result = await mediator.Send(new RequestOrderRefund.Command(id, Refund.Type, Refund.Amount, Refund.Reason), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; } else { TempData["SuccessMessage"] = $"환불 요청이 접수되었습니다. (RefundID={result.Value})"; } return RedirectToPage("/Store/Order/Detail", new { id }); } public async Task OnPostProcessRefundAsync(int id, int refundID, string? adminMemo, CancellationToken ct) { var admin = await userManager.GetUserAsync(User); if (admin is null) { TempData["ErrorMessages"] = "관리자 정보를 확인할 수 없습니다."; return RedirectToPage("/Store/Order/Detail", new { id }); } var result = await mediator.Send(new ProcessOrderRefund.Command(refundID, admin.Id, admin.Email, adminMemo), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; } else { TempData["SuccessMessage"] = "환불 처리가 완료되었습니다."; } return RedirectToPage("/Store/Order/Detail", new { id }); } public async Task OnPostRejectRefundAsync(int id, int refundID, string adminMemo, CancellationToken ct) { var admin = await userManager.GetUserAsync(User); if (admin is null) { TempData["ErrorMessages"] = "관리자 정보를 확인할 수 없습니다."; return RedirectToPage("/Store/Order/Detail", new { id }); } if (string.IsNullOrWhiteSpace(adminMemo)) { TempData["ErrorMessages"] = "거부 사유(메모)는 필수입니다."; return RedirectToPage("/Store/Order/Detail", new { id }); } var result = await mediator.Send(new RejectOrderRefund.Command(refundID, admin.Id, admin.Email, adminMemo), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; } else { TempData["SuccessMessage"] = "환불 요청이 거부되었습니다."; } return RedirectToPage("/Store/Order/Detail", new { id }); } private async Task LoadOrderAsync(int id, CancellationToken ct) { var result = await mediator.Send(new GetOrder.Query(id), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; return; } Data = result.Value; Refund.Amount = Data.TotalAmount; } }