diff --git a/src/TaxBaik.Web/Controllers/InquiryController.cs b/src/TaxBaik.Web/Controllers/InquiryController.cs.bak similarity index 100% rename from src/TaxBaik.Web/Controllers/InquiryController.cs rename to src/TaxBaik.Web/Controllers/InquiryController.cs.bak diff --git a/src/TaxBaik.Web/Endpoints/Inquiry/ConvertToClientEndpoint.cs b/src/TaxBaik.Web/Endpoints/Inquiry/ConvertToClientEndpoint.cs new file mode 100644 index 0000000..bc7143a --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Inquiry/ConvertToClientEndpoint.cs @@ -0,0 +1,59 @@ +using System.Security.Claims; +using FastEndpoints; +using TaxBaik.Application.Services; + +namespace TaxBaik.Web.Endpoints.Inquiry; + +public class ConvertToClientEndpoint : Endpoint +{ + private readonly InquiryService _inquiryService; + private readonly ClientService _clientService; + + public ConvertToClientEndpoint(InquiryService inquiryService, ClientService clientService) + { + _inquiryService = inquiryService; + _clientService = clientService; + } + + public override void Configure() + { + Post("/api/inquiry/{id}/convert-to-client"); + Policies("Bearer"); + } + + public override async Task HandleAsync(ConvertToClientRequest request, CancellationToken ct) + { + var id = Route("id"); + var inquiry = await _inquiryService.GetByIdAsync(id); + if (inquiry == null) + { + ThrowError("문의를 찾을 수 없습니다.", statusCode: 404); + } + + if (inquiry.ClientId != null) + { + ThrowError("이미 고객 카드가 연결되어 있습니다.", statusCode: 400); + } + + try + { + var clientId = await _clientService.CreateFromInquiryAsync( + request.Name ?? inquiry.Name, + request.Phone ?? inquiry.Phone, + request.ServiceType ?? inquiry.ServiceType); + + await _inquiryService.LinkClientAsync(inquiry.Id, clientId); + await _inquiryService.UpdateStatusAsync(inquiry.Id, "consulting", User.FindFirstValue(ClaimTypes.Name) ?? "system"); + + await SendAsync(new ConvertToClientResponse + { + ClientId = clientId, + Message = "고객 카드가 생성되었습니다." + }, 200, cancellation: ct); + } + catch (Exception ex) + { + ThrowError(ex.Message); + } + } +} diff --git a/src/TaxBaik.Web/Endpoints/Inquiry/GetByIdEndpoint.cs b/src/TaxBaik.Web/Endpoints/Inquiry/GetByIdEndpoint.cs new file mode 100644 index 0000000..9741795 --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Inquiry/GetByIdEndpoint.cs @@ -0,0 +1,32 @@ +using FastEndpoints; +using TaxBaik.Application.Services; + +namespace TaxBaik.Web.Endpoints.Inquiry; + +public class GetByIdEndpoint : Endpoint +{ + private readonly InquiryService _inquiryService; + + public GetByIdEndpoint(InquiryService inquiryService) + { + _inquiryService = inquiryService; + } + + public override void Configure() + { + Get("/api/inquiry/{id}"); + Policies("Bearer"); + } + + public override async Task HandleAsync(EmptyRequest _, CancellationToken ct) + { + var id = Route("id"); + var inquiry = await _inquiryService.GetByIdAsync(id); + if (inquiry == null) + { + ThrowError("문의를 찾을 수 없습니다.", statusCode: 404); + } + + await SendAsync(inquiry, 200, cancellation: ct); + } +} diff --git a/src/TaxBaik.Web/Endpoints/Inquiry/GetPagedEndpoint.cs b/src/TaxBaik.Web/Endpoints/Inquiry/GetPagedEndpoint.cs new file mode 100644 index 0000000..2ba77bd --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Inquiry/GetPagedEndpoint.cs @@ -0,0 +1,32 @@ +using FastEndpoints; +using TaxBaik.Application.Services; + +namespace TaxBaik.Web.Endpoints.Inquiry; + +public class GetPagedEndpoint : Endpoint +{ + private readonly InquiryService _inquiryService; + + public GetPagedEndpoint(InquiryService inquiryService) + { + _inquiryService = inquiryService; + } + + public override void Configure() + { + Get("/api/inquiry"); + Policies("Bearer"); + } + + public override async Task HandleAsync(InquiryQuery request, CancellationToken ct) + { + var (inquiries, total) = await _inquiryService.GetPagedAsync(request.Page, request.PageSize); + await SendAsync(new InquiryPagedResponse + { + Data = inquiries.Cast().ToList(), + Total = total, + Page = request.Page, + PageSize = request.PageSize + }, 200, cancellation: ct); + } +} diff --git a/src/TaxBaik.Web/Endpoints/Inquiry/InquiryDtos.cs b/src/TaxBaik.Web/Endpoints/Inquiry/InquiryDtos.cs new file mode 100644 index 0000000..32e85b0 --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Inquiry/InquiryDtos.cs @@ -0,0 +1,45 @@ +using TaxBaik.Application.DTOs; + +namespace TaxBaik.Web.Endpoints.Inquiry; + +public class InquiryPagedResponse +{ + public List Data { get; set; } = []; + public int Total { get; set; } + public int Page { get; set; } + public int PageSize { get; set; } +} + +public class InquiryQuery +{ + public int Page { get; set; } = 1; + public int PageSize { get; set; } = 20; +} + +public class UpdateStatusRequest +{ + public string Status { get; set; } = string.Empty; +} + +public class UpdateAdminMemoRequest +{ + public string? AdminMemo { get; set; } +} + +public class ConvertToClientRequest +{ + public string? Name { get; set; } + public string? Phone { get; set; } + public string? ServiceType { get; set; } +} + +public class ConvertToClientResponse +{ + public int ClientId { get; set; } + public string Message { get; set; } = string.Empty; +} + +public class MessageResponse +{ + public string Message { get; set; } = string.Empty; +} diff --git a/src/TaxBaik.Web/Endpoints/Inquiry/SubmitEndpoint.cs b/src/TaxBaik.Web/Endpoints/Inquiry/SubmitEndpoint.cs new file mode 100644 index 0000000..86e26c5 --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Inquiry/SubmitEndpoint.cs @@ -0,0 +1,46 @@ +using FastEndpoints; +using TaxBaik.Application.DTOs; +using TaxBaik.Application.Services; + +namespace TaxBaik.Web.Endpoints.Inquiry; + +public class SubmitEndpoint : Endpoint +{ + private readonly InquiryService _inquiryService; + + public SubmitEndpoint(InquiryService inquiryService) + { + _inquiryService = inquiryService; + } + + public override void Configure() + { + Post("/api/inquiry"); + AllowAnonymous(); + } + + public override async Task HandleAsync(SubmitInquiryDto request, CancellationToken ct) + { + if (string.IsNullOrWhiteSpace(request.Name) || string.IsNullOrWhiteSpace(request.Phone)) + { + ThrowError("이름과 전화번호를 입력하세요."); + } + + try + { + await _inquiryService.SubmitAsync( + request.Name, + request.Phone, + request.ServiceType, + request.Message, + request.Email, + HttpContext.Connection.RemoteIpAddress?.ToString(), + request.SuppressNotification); + await SendAsync(new MessageResponse { Message = "상담 신청이 접수되었습니다." }, 200, cancellation: ct); + } + catch (ValidationException ex) + { + ThrowError(ex.Message); + } + } +} diff --git a/src/TaxBaik.Web/Endpoints/Inquiry/UpdateAdminMemoEndpoint.cs b/src/TaxBaik.Web/Endpoints/Inquiry/UpdateAdminMemoEndpoint.cs new file mode 100644 index 0000000..9f9ef8d --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Inquiry/UpdateAdminMemoEndpoint.cs @@ -0,0 +1,40 @@ +using FastEndpoints; +using TaxBaik.Application.Services; + +namespace TaxBaik.Web.Endpoints.Inquiry; + +public class UpdateAdminMemoEndpoint : Endpoint +{ + private readonly InquiryService _inquiryService; + + public UpdateAdminMemoEndpoint(InquiryService inquiryService) + { + _inquiryService = inquiryService; + } + + public override void Configure() + { + Put("/api/inquiry/{id}/memo"); + Policies("Bearer"); + } + + public override async Task HandleAsync(UpdateAdminMemoRequest request, CancellationToken ct) + { + var id = Route("id"); + var inquiry = await _inquiryService.GetByIdAsync(id); + if (inquiry == null) + { + ThrowError("문의를 찾을 수 없습니다.", statusCode: 404); + } + + try + { + await _inquiryService.UpdateAdminMemoAsync(id, request.AdminMemo); + await SendAsync(new MessageResponse { Message = "메모가 저장되었습니다." }, 200, cancellation: ct); + } + catch (Exception ex) + { + ThrowError(ex.Message); + } + } +} diff --git a/src/TaxBaik.Web/Endpoints/Inquiry/UpdateEndpoint.cs b/src/TaxBaik.Web/Endpoints/Inquiry/UpdateEndpoint.cs new file mode 100644 index 0000000..28c1cb1 --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Inquiry/UpdateEndpoint.cs @@ -0,0 +1,40 @@ +using FastEndpoints; +using TaxBaik.Application.DTOs; +using TaxBaik.Application.Services; + +namespace TaxBaik.Web.Endpoints.Inquiry; + +public class UpdateEndpoint : Endpoint +{ + private readonly InquiryService _inquiryService; + + public UpdateEndpoint(InquiryService inquiryService) + { + _inquiryService = inquiryService; + } + + public override void Configure() + { + Put("/api/inquiry/{id}"); + Policies("Bearer"); + } + + public override async Task HandleAsync(UpdateInquiryDto request, CancellationToken ct) + { + var id = Route("id"); + try + { + var result = await _inquiryService.UpdateAsync(id, request); + if (result == null) + { + ThrowError("문의를 찾을 수 없습니다.", statusCode: 404); + } + + await SendAsync(result, 200, cancellation: ct); + } + catch (ValidationException ex) + { + ThrowError(ex.Message); + } + } +} diff --git a/src/TaxBaik.Web/Endpoints/Inquiry/UpdateStatusEndpoint.cs b/src/TaxBaik.Web/Endpoints/Inquiry/UpdateStatusEndpoint.cs new file mode 100644 index 0000000..b3d3985 --- /dev/null +++ b/src/TaxBaik.Web/Endpoints/Inquiry/UpdateStatusEndpoint.cs @@ -0,0 +1,42 @@ +using System.Security.Claims; +using FastEndpoints; +using TaxBaik.Application.Services; + +namespace TaxBaik.Web.Endpoints.Inquiry; + +public class UpdateStatusEndpoint : Endpoint +{ + private readonly InquiryService _inquiryService; + + public UpdateStatusEndpoint(InquiryService inquiryService) + { + _inquiryService = inquiryService; + } + + public override void Configure() + { + Put("/api/inquiry/{id}/status"); + Policies("Bearer"); + } + + public override async Task HandleAsync(UpdateStatusRequest request, CancellationToken ct) + { + var id = Route("id"); + var inquiry = await _inquiryService.GetByIdAsync(id); + if (inquiry == null) + { + ThrowError("문의를 찾을 수 없습니다.", statusCode: 404); + } + + try + { + var changedBy = User.FindFirstValue(ClaimTypes.Name) ?? User.Identity?.Name; + await _inquiryService.UpdateStatusAsync(id, request.Status, changedBy); + await SendAsync(new MessageResponse { Message = "상태가 변경되었습니다." }, 200, cancellation: ct); + } + catch (ValidationException ex) + { + ThrowError(ex.Message); + } + } +} diff --git a/test_run/TaxBaik.Application.dll b/test_run/TaxBaik.Application.dll index 183f2b2..dbb9920 100644 Binary files a/test_run/TaxBaik.Application.dll and b/test_run/TaxBaik.Application.dll differ diff --git a/test_run/TaxBaik.Application.pdb b/test_run/TaxBaik.Application.pdb index 903e49d..bd295cc 100644 Binary files a/test_run/TaxBaik.Application.pdb and b/test_run/TaxBaik.Application.pdb differ diff --git a/test_run/TaxBaik.Domain.dll b/test_run/TaxBaik.Domain.dll index 26bc415..eec0f2e 100644 Binary files a/test_run/TaxBaik.Domain.dll and b/test_run/TaxBaik.Domain.dll differ diff --git a/test_run/TaxBaik.Domain.pdb b/test_run/TaxBaik.Domain.pdb index d1a2b5e..1121a33 100644 Binary files a/test_run/TaxBaik.Domain.pdb and b/test_run/TaxBaik.Domain.pdb differ diff --git a/test_run/TaxBaik.Infrastructure.dll b/test_run/TaxBaik.Infrastructure.dll index c32bcba..16b4d40 100644 Binary files a/test_run/TaxBaik.Infrastructure.dll and b/test_run/TaxBaik.Infrastructure.dll differ diff --git a/test_run/TaxBaik.Infrastructure.pdb b/test_run/TaxBaik.Infrastructure.pdb index 62686a3..4c8c3db 100644 Binary files a/test_run/TaxBaik.Infrastructure.pdb and b/test_run/TaxBaik.Infrastructure.pdb differ diff --git a/test_run/TaxBaik.Web.dll b/test_run/TaxBaik.Web.dll index 542eb83..6c1daf0 100644 Binary files a/test_run/TaxBaik.Web.dll and b/test_run/TaxBaik.Web.dll differ diff --git a/test_run/TaxBaik.Web.exe b/test_run/TaxBaik.Web.exe index 945df35..de11b3f 100644 Binary files a/test_run/TaxBaik.Web.exe and b/test_run/TaxBaik.Web.exe differ diff --git a/test_run/TaxBaik.Web.pdb b/test_run/TaxBaik.Web.pdb index 0f718f2..778dc16 100644 Binary files a/test_run/TaxBaik.Web.pdb and b/test_run/TaxBaik.Web.pdb differ