From 620491fa9fd4d0c027a72cb44fb4952c0c44ffff Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sat, 27 Jun 2026 16:04:23 +0900 Subject: [PATCH] feat: notify inquiry status changes --- .../InquiryServiceTests.cs | 3 ++ .../Services/IInquiryNotificationService.cs | 1 + .../Services/InquiryService.cs | 10 ++++- .../NoopInquiryNotificationService.cs | 3 ++ .../TelegramInquiryNotificationService.cs | 40 +++++++++++++++++++ 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/TaxBaik.Application.Tests/InquiryServiceTests.cs b/TaxBaik.Application.Tests/InquiryServiceTests.cs index 4648cdb..bd93cec 100644 --- a/TaxBaik.Application.Tests/InquiryServiceTests.cs +++ b/TaxBaik.Application.Tests/InquiryServiceTests.cs @@ -61,5 +61,8 @@ public class InquiryServiceTests { public Task NotifyCreatedAsync(int inquiryId, string name, string phone, string serviceType, string message, CancellationToken ct = default) => Task.CompletedTask; + + public Task NotifyStatusChangedAsync(int inquiryId, string name, string phone, string serviceType, string previousStatus, string newStatus, CancellationToken ct = default) + => Task.CompletedTask; } } diff --git a/TaxBaik.Application/Services/IInquiryNotificationService.cs b/TaxBaik.Application/Services/IInquiryNotificationService.cs index 8519e1c..19e8110 100644 --- a/TaxBaik.Application/Services/IInquiryNotificationService.cs +++ b/TaxBaik.Application/Services/IInquiryNotificationService.cs @@ -3,4 +3,5 @@ namespace TaxBaik.Application.Services; public interface IInquiryNotificationService { Task NotifyCreatedAsync(int inquiryId, string name, string phone, string serviceType, string message, CancellationToken ct = default); + Task NotifyStatusChangedAsync(int inquiryId, string name, string phone, string serviceType, string previousStatus, string newStatus, CancellationToken ct = default); } diff --git a/TaxBaik.Application/Services/InquiryService.cs b/TaxBaik.Application/Services/InquiryService.cs index 8415d7c..d79da8d 100644 --- a/TaxBaik.Application/Services/InquiryService.cs +++ b/TaxBaik.Application/Services/InquiryService.cs @@ -51,7 +51,15 @@ public class InquiryService(IInquiryRepository repository, IInquiryNotificationS if (!InquiryStatusMapper.TryParse(status, out var parsed)) throw new ValidationException("지원하지 않는 문의 상태입니다."); - await repository.UpdateStatusAsync(id, InquiryStatusMapper.ToStorageValue(parsed), ct); + var inquiry = await repository.GetByIdAsync(id, ct); + if (inquiry == null) + return; + + var previousStatus = inquiry.Status; + var newStatus = InquiryStatusMapper.ToStorageValue(parsed); + + await repository.UpdateStatusAsync(id, newStatus, ct); + await notificationService.NotifyStatusChangedAsync(id, inquiry.Name, inquiry.Phone, inquiry.ServiceType, previousStatus, newStatus, ct); } private static int NormalizePage(int page) => Math.Max(1, page); diff --git a/TaxBaik.Application/Services/NoopInquiryNotificationService.cs b/TaxBaik.Application/Services/NoopInquiryNotificationService.cs index 2b3e7ee..a34effa 100644 --- a/TaxBaik.Application/Services/NoopInquiryNotificationService.cs +++ b/TaxBaik.Application/Services/NoopInquiryNotificationService.cs @@ -4,4 +4,7 @@ public sealed class NoopInquiryNotificationService : IInquiryNotificationService { public Task NotifyCreatedAsync(int inquiryId, string name, string phone, string serviceType, string message, CancellationToken ct = default) => Task.CompletedTask; + + public Task NotifyStatusChangedAsync(int inquiryId, string name, string phone, string serviceType, string previousStatus, string newStatus, CancellationToken ct = default) + => Task.CompletedTask; } diff --git a/TaxBaik.Web/Services/TelegramInquiryNotificationService.cs b/TaxBaik.Web/Services/TelegramInquiryNotificationService.cs index 10569e5..e45bb2c 100644 --- a/TaxBaik.Web/Services/TelegramInquiryNotificationService.cs +++ b/TaxBaik.Web/Services/TelegramInquiryNotificationService.cs @@ -61,4 +61,44 @@ public class TelegramInquiryNotificationService : IInquiryNotificationService _logger.LogWarning(ex, "텔레그램 알림 전송 중 오류 발생"); } } + + public async Task NotifyStatusChangedAsync(int inquiryId, string name, string phone, string serviceType, string previousStatus, string newStatus, CancellationToken ct = default) + { + var botToken = _configuration["Telegram:BotToken"]; + var chatId = _configuration["Telegram:ChatId"]; + if (string.IsNullOrWhiteSpace(botToken) || string.IsNullOrWhiteSpace(chatId)) + return; + + var adminLink = $"{_baseUrl}/admin/inquiries/{inquiryId}"; + var text = new StringBuilder() + .AppendLine("문의 상태가 변경되었습니다.") + .AppendLine() + .AppendLine($"제목: {serviceType}") + .AppendLine($"이름: {name}") + .AppendLine($"연락처: {phone}") + .AppendLine($"상태: {previousStatus} -> {newStatus}") + .AppendLine() + .AppendLine($"답변 링크: {adminLink}") + .ToString(); + + var client = _httpClientFactory.CreateClient(); + var url = $"https://api.telegram.org/bot{botToken}/sendMessage"; + var payload = new + { + chat_id = chatId, + text, + disable_web_page_preview = false + }; + + try + { + var response = await client.PostAsJsonAsync(url, payload, ct); + if (!response.IsSuccessStatusCode) + _logger.LogWarning("텔레그램 상태 변경 알림 실패: {StatusCode}", response.StatusCode); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "텔레그램 상태 변경 알림 중 오류 발생"); + } + } }