OrderVisitDomainService.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using DotNetCore.CAP;
  2. using Hotline.Caching.Interfaces;
  3. using Hotline.Share.Dtos;
  4. using Hotline.Share.Dtos.Order;
  5. using Hotline.Share.Dtos.Push;
  6. using Hotline.Share.Enums.Order;
  7. using Hotline.Share.Tools;
  8. using Mapster;
  9. using Microsoft.Extensions.Logging;
  10. using XF.Domain.Dependency;
  11. using XF.Domain.Exceptions;
  12. using XF.Domain.Repository;
  13. using Hotline.EventBus;
  14. using Hotline.Orders.Notifications;
  15. using Hotline.Configurations;
  16. using Microsoft.Extensions.Options;
  17. using Hotline.Settings;
  18. using System.Text.RegularExpressions;
  19. namespace Hotline.Orders;
  20. public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependency
  21. {
  22. private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
  23. private readonly ILogger<OrderVisitDomainService> _logger;
  24. private readonly IRepository<Order> _orderRepository;
  25. private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
  26. private readonly IOrderVisitRepository _orderVisitRepository;
  27. private readonly ICapPublisher _capPublisher;
  28. private readonly Publisher _publisher;
  29. private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
  30. private readonly ISettingOrderVisitSmsReplyRuleRepository _settingOrderVisitSmsReplyRuleRepository;
  31. public OrderVisitDomainService(IRepository<OrderVisitDetail> orderVisitDetailRepository, ILogger<OrderVisitDomainService> logger, IRepository<Order> orderRepository, ISystemDicDataCacheManager systemDicDataCacheManager, IOrderVisitRepository orderVisitRepository, ICapPublisher capPublisher, Publisher publisher, IOptionsSnapshot<AppConfiguration> appOptions, ISettingOrderVisitSmsReplyRuleRepository settingOrderVisitSmsReplyRuleRepository)
  32. {
  33. _orderVisitDetailRepository = orderVisitDetailRepository;
  34. _logger = logger;
  35. _orderRepository = orderRepository;
  36. _systemDicDataCacheManager = systemDicDataCacheManager;
  37. _orderVisitRepository = orderVisitRepository;
  38. _capPublisher = capPublisher;
  39. _publisher = publisher;
  40. _appOptions = appOptions;
  41. _settingOrderVisitSmsReplyRuleRepository = settingOrderVisitSmsReplyRuleRepository;
  42. }
  43. /// <summary>
  44. /// 用户回访短信回复更新回访状态
  45. /// </summary>
  46. /// <param name="dto"></param>
  47. /// <param name="data"></param>
  48. /// <returns></returns>
  49. public async Task UpdateSmsReplyAsync(MessageDto data)
  50. {
  51. if (data.IsSmsReply == false || data.SmsReplyContent.IsNullOrEmpty()) return;
  52. var orderVisits = await _orderVisitRepository.Queryable()
  53. .Includes(m => m.Order)
  54. .Where(m => m.Order.Contact == data.TelNumber)
  55. .Where(m => m.VisitState == EVisitState.SMSVisiting)
  56. .ToListAsync();
  57. foreach (var orderVisit in orderVisits)
  58. {
  59. await UpdateSmsReplyAsync(orderVisit, data.SmsReplyContent!.Trim());
  60. }
  61. }
  62. /// <summary>
  63. /// 根据用户短信或电话回复的内容转换成系统中对应的评价
  64. /// </summary>
  65. /// <typeparam name="T"></typeparam>
  66. /// <param name="replyTxt"></param>
  67. /// <returns></returns>
  68. /// <exception cref="UserFriendlyException"></exception>
  69. public SettingOrderVisitSmsReplyRule GetVisitEvaluateByReplyTxt(string replyTxt)
  70. {
  71. var replyToEnumMap = _settingOrderVisitSmsReplyRuleRepository.GetByAppScope(_appOptions.Value.AppScope);
  72. if (replyToEnumMap.IsNullOrEmpty()) throw new UserFriendlyException("系统未配置短信回访规则");
  73. replyTxt = replyTxt.Trim();
  74. return replyToEnumMap.FirstOrDefault(m => new Regex(m.ReplyRegular).IsMatch(replyTxt))
  75. ?? throw new UserFriendlyException($"用户回复内容异常; replyTxt: {replyTxt}");
  76. }
  77. /// <summary>
  78. /// 超过48小时未回复短信,修改短信回访记录为默认满意
  79. /// </summary>
  80. /// <param name="dto"></param>
  81. /// <returns></returns>
  82. public async Task UpdateSmsReplyDefaultAsync(MessageDto dto)
  83. {
  84. await _orderVisitRepository.Queryable()
  85. .Includes(m => m.Order)
  86. .Where(m => m.Id == dto.ExternalId)
  87. .Where(m => m.VisitState == EVisitState.SMSVisiting)
  88. .FirstAsync()
  89. .Then(async orderVisit =>
  90. {
  91. // 默认满意
  92. await UpdateSmsReplyAsync(orderVisit, "0");
  93. });
  94. }
  95. /// <summary>
  96. /// 超过48小时未回复短信,修改短信回访记录为默认满意
  97. /// 用户回访短信回复更新回访状态
  98. /// </summary>
  99. /// <param name="orderVisit"></param>
  100. /// <param name="replyTxt"></param>
  101. /// <returns></returns>
  102. private async Task UpdateSmsReplyAsync(OrderVisit orderVisit, string replyTxt)
  103. {
  104. orderVisit.Order ??= await _orderRepository.GetAsync(orderVisit.OrderId);
  105. orderVisit.VisitType = EVisitType.SmsVisit;
  106. if (new string[] { "4", "5", "不满意", "非常不满意" }.Contains(replyTxt))
  107. {
  108. // “短信不满意待回访”状态下,由其他方式再次进行回访,回访方式需更新为最新的回访方式
  109. // 故在此置为空
  110. orderVisit.VisitType = null;
  111. }
  112. var smsReplyRule = GetVisitEvaluateByReplyTxt(replyTxt);
  113. var visitSatisfactionKv = smsReplyRule.GetOrgProcessingResults(_systemDicDataCacheManager.VisitSatisfaction);
  114. if (smsReplyRule.OrgProcessingResults != null)
  115. orderVisit.NowEvaluate = visitSatisfactionKv;
  116. orderVisit.VisitTime = DateTime.Now;
  117. if (smsReplyRule.VisitState != null)
  118. orderVisit.VisitState = smsReplyRule.VisitState.Value;
  119. await _orderVisitRepository.UpdateAsync(orderVisit, ignoreNullColumns: false);
  120. if (orderVisit.VisitState == EVisitState.Visited)
  121. {
  122. await _orderRepository.GetAsync(orderVisit.OrderId)
  123. .Then(async order =>
  124. {
  125. order!.Visited(visitSatisfactionKv.Key, visitSatisfactionKv.Value);
  126. await _orderRepository.UpdateAsync(order);
  127. });
  128. }
  129. var detailOrg = await _orderVisitDetailRepository.Queryable()
  130. .Where(m => m.VisitId == orderVisit.Id && m.VisitTarget == EVisitTarget.Org)
  131. .ToListAsync();
  132. foreach (var item in detailOrg)
  133. {
  134. item.ReplyBackfill(visitSatisfactionKv);
  135. if (_appOptions.Value.IsZiGong)
  136. item.OrgHandledAttitude = visitSatisfactionKv;
  137. }
  138. await _orderVisitDetailRepository.UpdateRangeAsync(detailOrg);
  139. await _orderVisitDetailRepository.Queryable()
  140. .Where(m => m.VisitId == orderVisit.Id && m.VisitTarget == EVisitTarget.Seat)
  141. .FirstAsync()
  142. .Then(async detailSeat =>
  143. {
  144. if (smsReplyRule.SeatEvaluate != null)
  145. {
  146. detailSeat.ReplyBackfill(smsReplyRule.SeatEvaluate.Value);
  147. await _orderVisitDetailRepository.UpdateAsync(detailSeat);
  148. }
  149. });
  150. if (orderVisit.VisitState != EVisitState.Visited) return;
  151. orderVisit.Order.Visited(visitSatisfactionKv.Key, visitSatisfactionKv.Value);
  152. await _orderRepository.UpdateAsync(orderVisit.Order);
  153. var orderDto = orderVisit.Order.Adapt<OrderDto>();
  154. var first = detailOrg.First();
  155. if (visitSatisfactionKv.Key != null && visitSatisfactionKv.Value != null)
  156. {
  157. //推省上
  158. await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
  159. new PublishVisitDto()
  160. {
  161. Order = orderDto,
  162. No = orderVisit.No,
  163. VisitType = orderVisit.VisitType,
  164. VisitName = orderVisit.CreatorName,
  165. VisitTime = orderVisit.VisitTime,
  166. VisitRemark = string.IsNullOrEmpty(first.VisitContent) ? first.OrgProcessingResults?.Value : first.VisitContent,
  167. AreaCode = orderVisit.Order.AreaCode!,
  168. SubjectResultSatifyCode = first.OrgProcessingResults.Key,
  169. FirstSatisfactionCode = orderVisit.Order.FirstVisitResultCode!,
  170. ClientGuid = ""
  171. }, cancellationToken: CancellationToken.None);
  172. }
  173. }
  174. }