Detail.cshtml.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. using Domain.Entities.Store.ValueObject;
  2. using SharedKernel.Extensions;
  3. using MediatR;
  4. using Microsoft.AspNetCore.Identity;
  5. using Microsoft.AspNetCore.Mvc;
  6. using Microsoft.AspNetCore.Mvc.RazorPages;
  7. using Infrastructure.Persistence.Identity;
  8. using System.ComponentModel;
  9. using System.ComponentModel.DataAnnotations;
  10. using Application.Features.Admin.Store.Order.RequestCouponsRefund;
  11. namespace Admin.Pages.Store.Order;
  12. public class DetailModel(IMediator mediator, UserManager<ApplicationUser> userManager) : PageModel
  13. {
  14. public GetOrder.Response? Data { get; private set; }
  15. [BindProperty]
  16. public RefundRequest Refund { get; set; } = new();
  17. public sealed class RefundRequest
  18. {
  19. [DisplayName("환불 유형")]
  20. public RefundType Type { get; set; } = RefundType.Cancel;
  21. [DisplayName("환불 금액(P)")]
  22. [Range(1, int.MaxValue, ErrorMessage = "환불 금액은 1P 이상이어야 합니다.")]
  23. public int Amount { get; set; }
  24. [DisplayName("사유")]
  25. [Required(ErrorMessage = "{0}는 필수입니다.")]
  26. [StringLength(500)]
  27. public string Reason { get; set; } = "";
  28. }
  29. public async Task OnGetAsync(int id, CancellationToken ct)
  30. {
  31. await LoadOrderAsync(id, ct);
  32. }
  33. public async Task<IActionResult> OnPostRequestCouponsRefundAsync(int id, int orderItemID, List<int> couponCodeIds, CouponPostRefundAction action, string reason, CancellationToken ct)
  34. {
  35. if (couponCodeIds is null || couponCodeIds.Count == 0)
  36. {
  37. TempData["ErrorMessages"] = "환불할 쿠폰을 1개 이상 선택해 주세요.";
  38. return RedirectToPage("/Store/Order/Detail", new { id });
  39. }
  40. if (string.IsNullOrWhiteSpace(reason))
  41. {
  42. TempData["ErrorMessages"] = "환불 사유는 필수입니다.";
  43. return RedirectToPage("/Store/Order/Detail", new { id });
  44. }
  45. var lines = couponCodeIds.Distinct().Select(c => new CouponRefundLine(orderItemID, c, action)).ToList();
  46. var result = await mediator.Send(new Application.Features.Admin.Store.Order.RequestCouponsRefund.Command(id, lines, reason), ct);
  47. if (result.IsFailure)
  48. {
  49. TempData["ErrorMessages"] = result.Error.Description;
  50. }
  51. else
  52. {
  53. TempData["SuccessMessage"] = $"쿠폰 {lines.Count}건 환불 요청이 등록되었습니다. (RefundID={result.Value}) — '환불 이력' 표에서 '실행' 버튼으로 처리하세요.";
  54. }
  55. return RedirectToPage("/Store/Order/Detail", new { id });
  56. }
  57. public async Task<IActionResult> OnPostRequestRefundAsync(int id, CancellationToken ct)
  58. {
  59. if (!ModelState.IsValid)
  60. {
  61. TempData["ErrorMessages"] = ModelState.GetErrorMessages();
  62. return RedirectToPage("/Store/Order/Detail", new { id });
  63. }
  64. var result = await mediator.Send(new RequestOrderRefund.Command(id, Refund.Type, Refund.Amount, Refund.Reason), ct);
  65. if (result.IsFailure)
  66. {
  67. TempData["ErrorMessages"] = result.Error.Description;
  68. }
  69. else
  70. {
  71. TempData["SuccessMessage"] = $"환불 요청이 접수되었습니다. (RefundID={result.Value})";
  72. }
  73. return RedirectToPage("/Store/Order/Detail", new { id });
  74. }
  75. public async Task<IActionResult> OnPostProcessRefundAsync(int id, int refundID, string? adminMemo, CancellationToken ct)
  76. {
  77. var admin = await userManager.GetUserAsync(User);
  78. if (admin is null)
  79. {
  80. TempData["ErrorMessages"] = "관리자 정보를 확인할 수 없습니다.";
  81. return RedirectToPage("/Store/Order/Detail", new { id });
  82. }
  83. var result = await mediator.Send(new ProcessOrderRefund.Command(refundID, admin.Id, admin.Email, adminMemo), ct);
  84. if (result.IsFailure)
  85. {
  86. TempData["ErrorMessages"] = result.Error.Description;
  87. }
  88. else
  89. {
  90. TempData["SuccessMessage"] = "환불 처리가 완료되었습니다.";
  91. }
  92. return RedirectToPage("/Store/Order/Detail", new { id });
  93. }
  94. public async Task<IActionResult> OnPostRejectRefundAsync(int id, int refundID, string adminMemo, CancellationToken ct)
  95. {
  96. var admin = await userManager.GetUserAsync(User);
  97. if (admin is null)
  98. {
  99. TempData["ErrorMessages"] = "관리자 정보를 확인할 수 없습니다.";
  100. return RedirectToPage("/Store/Order/Detail", new { id });
  101. }
  102. if (string.IsNullOrWhiteSpace(adminMemo))
  103. {
  104. TempData["ErrorMessages"] = "거부 사유(메모)는 필수입니다.";
  105. return RedirectToPage("/Store/Order/Detail", new { id });
  106. }
  107. var result = await mediator.Send(new RejectOrderRefund.Command(refundID, admin.Id, admin.Email, adminMemo), ct);
  108. if (result.IsFailure)
  109. {
  110. TempData["ErrorMessages"] = result.Error.Description;
  111. }
  112. else
  113. {
  114. TempData["SuccessMessage"] = "환불 요청이 거부되었습니다.";
  115. }
  116. return RedirectToPage("/Store/Order/Detail", new { id });
  117. }
  118. private async Task LoadOrderAsync(int id, CancellationToken ct)
  119. {
  120. var result = await mediator.Send(new GetOrder.Query(id), ct);
  121. if (result.IsFailure)
  122. {
  123. TempData["ErrorMessages"] = result.Error.Description;
  124. return;
  125. }
  126. Data = result.Value;
  127. Refund.Amount = Data.TotalAmount;
  128. }
  129. }