OrderVisitDomainServiceTest.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. using Hotline.Api.Controllers;
  2. using Hotline.Caching.Interfaces;
  3. using Hotline.Configurations;
  4. using Hotline.EventBus;
  5. using Hotline.Identity.Accounts;
  6. using Hotline.Identity.Roles;
  7. using Hotline.Orders;
  8. using Hotline.Push.FWMessage;
  9. using Hotline.Push.Notifies;
  10. using Hotline.Settings;
  11. using Hotline.Share.Dtos;
  12. using Hotline.Share.Dtos.Push;
  13. using Hotline.Share.Enums.Order;
  14. using Hotline.Share.Enums.Push;
  15. using Hotline.Share.Tools;
  16. using Hotline.Snapshot.Interfaces;
  17. using Hotline.Tests.Mock;
  18. using Hotline.Users;
  19. using Mapster;
  20. using Microsoft.AspNetCore.Http;
  21. using Microsoft.Extensions.DependencyInjection;
  22. using Microsoft.Extensions.Options;
  23. using Shouldly;
  24. using XF.Domain.Repository;
  25. namespace Hotline.Tests.Domain;
  26. public class OrderVisitDomainServiceTest : TestBase
  27. {
  28. private readonly IOrderVisitDomainService _orderVisitDomainService;
  29. private readonly IOrderVisitRepository _orderVisitRepository;
  30. private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
  31. private readonly Publisher _publisher;
  32. private readonly IOrderRepository _orderRepository;
  33. private readonly OrderServiceMock _orderServiceMock;
  34. private readonly ISettingOrderVisitSmsReplyRuleRepository _settingOrderVisitSmsReplyRuleRepository;
  35. private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
  36. private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
  37. private readonly ISystemLogRepository _logRepository;
  38. public OrderVisitDomainServiceTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IOrderVisitDomainService orderVisitDomainService, IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, Publisher publisher, IOrderRepository orderRepository, OrderServiceMock orderServiceMock, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ISettingOrderVisitSmsReplyRuleRepository settingOrderVisitSmsReplyRuleRepository, ISystemDicDataCacheManager systemDicDataCacheManager, IOptionsSnapshot<AppConfiguration> appOptions, ISystemLogRepository logRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount)
  39. {
  40. _orderVisitDomainService = orderVisitDomainService;
  41. _orderVisitRepository = orderVisitRepository;
  42. _orderVisitDetailRepository = orderVisitDetailRepository;
  43. _publisher = publisher;
  44. _orderRepository = orderRepository;
  45. _orderServiceMock = orderServiceMock;
  46. _settingOrderVisitSmsReplyRuleRepository = settingOrderVisitSmsReplyRuleRepository;
  47. _systemDicDataCacheManager = systemDicDataCacheManager;
  48. _appOptions = appOptions;
  49. _logRepository = logRepository;
  50. }
  51. //[Fact]
  52. public async Task UpdateSmsReplyDefault_Test()
  53. {
  54. var visit = await _orderVisitRepository
  55. .Queryable()
  56. .Where(m => m.VisitState == EVisitState.SMSVisiting)
  57. .OrderByDescending(m => m.CreationTime)
  58. .FirstAsync();
  59. visit.ShouldNotBeNull("缺少测试数据");
  60. var msg = new MessageDto()
  61. {
  62. ExternalId = visit.Id,
  63. };
  64. await _orderVisitDomainService.UpdateSmsReplyDefaultAsync(msg);
  65. var replyTxt = "默认满意";
  66. var smsReply = _orderVisitDomainService.GetVisitEvaluateByReplyTxt("默认满意");
  67. var kv = smsReply.GetOrgProcessingResults(_systemDicDataCacheManager.VisitSatisfaction);
  68. var order = await _orderRepository.Queryable()
  69. .Includes(m => m.OrderVisits)
  70. .Where(m => m.OrderVisits.Any(o => o.Id == visit.Id))
  71. .FirstAsync();
  72. order.Status.ShouldBe(EOrderStatus.Visited);
  73. var visitDetail = await _orderVisitDetailRepository.Queryable()
  74. .Where(m => m.VisitId == visit.Id)
  75. .ToListAsync();
  76. foreach (var detail in visitDetail)
  77. {
  78. if (detail.VisitTarget == EVisitTarget.Seat)
  79. {
  80. var seatEvaluate = smsReply.SeatEvaluate;
  81. var voiceEvaluate = smsReply.VoiceEvaluate;
  82. detail.SeatEvaluate.ShouldBe(seatEvaluate);
  83. detail.VoiceEvaluate.ShouldBe(voiceEvaluate);
  84. }
  85. if (detail.VisitTarget == EVisitTarget.Org)
  86. {
  87. detail.OrgProcessingResults.Key.ShouldBe(kv.Key);
  88. detail.OrgProcessingResults.Value.ShouldBe(kv.Value);
  89. detail.OrgHandledAttitude.Key.ShouldBe(kv.Key);
  90. detail.OrgHandledAttitude.Value.ShouldBe(kv.Value);
  91. }
  92. }
  93. }
  94. //[Fact]
  95. public async Task OnSmsUpdate_Test()
  96. {
  97. var data = new Message() { IsSmsReply = true, SmsReplyContent = "1", PushBusiness = EPushBusiness.VisitSms };
  98. await _publisher.PublishAsync(data.Adapt<ReceiveMessageNotify>(), PublishStrategy.ParallelNoWait, new CancellationToken());
  99. }
  100. [Theory]
  101. [InlineData("4", "SMSUnsatisfied", "2", "不满意", "不满意", "Published")]
  102. [InlineData("1", "Visited", "5", "非常满意", "非常满意")]
  103. [InlineData("2", "Visited", "4", "满意", "满意")]
  104. [InlineData("3", "Visited", "4", "满意", "一般")]
  105. [InlineData("5", "SMSUnsatisfied", "2", "不满意", "不满意", "Published")]
  106. [InlineData("默认满意", "Visited", "0", "默认满意", "超过48小时自动回访")]
  107. [InlineData("都没有办理好", "SMSUnsatisfied", "", "", "都没有办理好", "Published", "YiBin")]
  108. [InlineData("1", "Visited", "4", "满意", "满意", "Visited", "YiBin")]
  109. [InlineData("2", "SMSUnsatisfied", "2", "不满意", "不满意", "Published", "YiBin")]
  110. public async Task UpdateSmsReply_Test(string content, string visitState, string orgResuktKey, string orgResuktValue, string visitContent, string visited = "Visited", string appScope = "ZiGong")
  111. {
  112. if (appScope != "ZiGong")
  113. ChangeAppScopeYiBin();
  114. else
  115. ChangeAppScopeZiGong();
  116. var appScopeFile = _appOptions.Value.AppScope;
  117. SetZuoXi();
  118. var order = _orderServiceMock.CreateOrder()
  119. .办理到一级部门()
  120. .办理到二级部门(Set一级部门)
  121. .办理一级部门汇总(Set二级部门)
  122. .办理到归档(Set一级部门)
  123. .发布工单(SetZuoXi)
  124. .发送回访短信(SetZuoXi)
  125. .GetCreateResult();
  126. order.Id.ShouldNotBeNull();
  127. var visit = await _orderVisitRepository.Queryable()
  128. .Includes(m => m.Order)
  129. .Where(m => m.VisitState == EVisitState.SMSVisiting)
  130. .OrderByDescending(m => m.CreationTime)
  131. .FirstAsync();
  132. if (visit == null) return;
  133. visit.ShouldNotBeNull("缺少测试数据");
  134. var message = new MessageDto { ExternalId = visit.Id, IsSmsReply = true, SmsReplyContent = content, TelNumber = visit.Order.Contact };
  135. var dto = new PushReceiveMessageDto();
  136. await _orderVisitDomainService.UpdateSmsReplyAsync(message);
  137. visit = _orderVisitRepository.Get(visit.Id);
  138. visit.VisitState.ShouldBe(visitState.ToEnum<EVisitState>());
  139. if (orgResuktKey.NotNullOrEmpty())
  140. {
  141. visit.NowEvaluate.ShouldNotBeNull();
  142. visit.NowEvaluate.Key.ShouldBe(orgResuktKey);
  143. visit.NowEvaluate.Value.ShouldBe(orgResuktValue);
  144. }
  145. var orderEntity = await _orderRepository.GetAsync(order.Id);
  146. orderEntity.ShouldNotBeNull();
  147. orderEntity.Status.ShouldBe(visited.ToEnum<EOrderStatus>());
  148. if (content == "4" || content == "5" || content == "不满意" || content == "非常不满意" || content == "都没有办理好")
  149. {
  150. visit.VisitType.ShouldBeNull();
  151. }
  152. var smsReply = _orderVisitDomainService.GetVisitEvaluateByReplyTxt(content);
  153. var log = _logRepository.Queryable().Where(m => m.Name == "短信回访-回复内容匹配结果" && m.Remark == order.No).First();
  154. log.ShouldNotBeNull();
  155. await _orderVisitDetailRepository.Queryable()
  156. .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Org)
  157. .FirstAsync()
  158. .Then(org =>
  159. {
  160. if (content != "都没有办理好")
  161. {
  162. org.OrgProcessingResults.ShouldNotBeNull();
  163. org.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
  164. org.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
  165. org.VisitContent.ShouldBe(visitContent);
  166. // 验证跟新工单上的字段是否成功
  167. if (new string[] { "4", "5", "不满意", "非常不满意"}.Contains(content) == false)
  168. {
  169. if (appScope != "YiBin" && content != "2")
  170. {
  171. orderEntity.OrgProcessingResults.ShouldNotBeNull();
  172. orderEntity.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
  173. orderEntity.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
  174. }
  175. }
  176. if (appScope != "YiBin")
  177. {
  178. org.OrgHandledAttitude.ShouldNotBeNull();
  179. org.OrgHandledAttitude.Key.ShouldBe(orgResuktKey);
  180. org.OrgHandledAttitude.Value.ShouldBe(orgResuktValue);
  181. }
  182. if (smsReply.IsReplyToOrgVisitContent == true)
  183. {
  184. org.VisitContent = content;
  185. }
  186. }
  187. return Task.CompletedTask;
  188. });
  189. await _orderVisitDetailRepository.Queryable()
  190. .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Seat)
  191. .FirstAsync()
  192. .Then(seat =>
  193. {
  194. if (content != "都没有办理好")
  195. {
  196. // 验证跟新工单上的字段是否成功
  197. if (new string[] { "4", "5", "不满意", "非常不满意", "都没有办理好" }.Contains(content) == true)
  198. {
  199. seat.SeatEvaluate.ShouldNotBe(ESeatEvaluate.NoSatisfied);
  200. seat.SeatEvaluate.ShouldNotBe(ESeatEvaluate.VeryNoSatisfied);
  201. seat.VoiceEvaluate.ShouldNotBe(EVoiceEvaluate.NoSatisfied);
  202. seat.VoiceEvaluate.ShouldNotBe(EVoiceEvaluate.VeryNoSatisfied);
  203. }
  204. else
  205. {
  206. if (smsReply.SeatEvaluate != null)
  207. seat.SeatEvaluate.ShouldBe(smsReply.SeatEvaluate);
  208. if (smsReply.VoiceEvaluate != null)
  209. seat.VoiceEvaluate.ShouldBe(smsReply.VoiceEvaluate);
  210. }
  211. }
  212. return Task.CompletedTask;
  213. });
  214. }
  215. [Theory]
  216. [InlineData("1", "非常满意", "Visited", "", "", "非常满意|5")]
  217. [InlineData("2", "满意", "Visited", "", "", "满意|4")]
  218. [InlineData("3", "一般", "Visited", "", "", "满意|4")]
  219. [InlineData("4", "不满意", "SMSUnsatisfied", "", "", "不满意|2")]
  220. [InlineData("5", "不满意", "SMSUnsatisfied", "", "", "不满意|2")]
  221. //[InlineData("默认满意", "超过48小时自动回访", "Visited", "DefaultSatisfied", "DefaultSatisfied", "默认满意|0")]
  222. [InlineData("默认满意", "超过48小时自动回访", "Visited", "", "", "默认满意|0")]
  223. [InlineData("1非常满意", "非常满意", "Visited", "", "", "非常满意|5")]
  224. public void GetVisitEvaluateByReplyTxt_Test(string replyTxt, string assertReplyTxt, string visitState, string seatEvaluate, string voiceEvaluate, string kv)
  225. {
  226. var smsReply = _orderVisitDomainService.GetVisitEvaluateByReplyTxt(replyTxt);
  227. var replyString = smsReply.VisitContent;
  228. replyString.ShouldBe(assertReplyTxt);
  229. var visitStateEnum = smsReply.VisitState;
  230. visitStateEnum.ShouldBe(visitState.ToEnum<EVisitState>());
  231. if (seatEvaluate.NotNullOrEmpty())
  232. {
  233. var seatEvaluateEnum = smsReply.SeatEvaluate;
  234. seatEvaluateEnum.ShouldBe(seatEvaluate.ToEnum<ESeatEvaluate>());
  235. }
  236. if (voiceEvaluate.NotNullOrEmpty())
  237. {
  238. var voiceEvaluateEnum = smsReply.VoiceEvaluate;
  239. voiceEvaluateEnum.ShouldBe(voiceEvaluate.ToEnum<EVoiceEvaluate>());
  240. }
  241. var kvResult = smsReply.GetOrgProcessingResults(_systemDicDataCacheManager.VisitSatisfaction);
  242. var sp = kv.Split('|');
  243. var kV = new Kv(sp[1].ToString(), sp[0].ToString());
  244. kvResult.Key.ShouldBe(kV.Key);
  245. kvResult.Value.ShouldBe(kV.Value);
  246. }
  247. [Fact]
  248. public async Task Init_SettingOrderVisitSmsReplyRule_Data()
  249. {
  250. IEnumerable<SettingOrderVisitSmsReplyRule> entities = [
  251. new () {Name = "非常满意的规则", AppScope = "ZiGong", ReplyRegular = "1", VisitContent = "非常满意", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=5, OrgHandledAttitude = 5, VisitType = EVisitType.SmsVisit, SortOrder = 1},
  252. new () {Name = "满意的规则", AppScope = "ZiGong", ReplyRegular = "2", VisitContent = "满意", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=4, OrgHandledAttitude = 4 , VisitType = EVisitType.SmsVisit, SortOrder = 2},
  253. new () {Name = "一般的规则", AppScope = "ZiGong", ReplyRegular = "3", VisitContent = "一般", VisitState = EVisitState.Visited, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults= 4, OrgHandledAttitude = 4 , VisitType = EVisitType.SmsVisit, SortOrder = 3},
  254. new () {Name = "不满意的规则", AppScope = "ZiGong", ReplyRegular = "4", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=2, OrgHandledAttitude = 2 , VisitType = null, SortOrder = 4},
  255. new () {Name = "非常不满意的规则", AppScope = "ZiGong", ReplyRegular = "5", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults=2, OrgHandledAttitude = 2, VisitType = null, SortOrder = 5},
  256. new () {Name = "默认满意的规则", AppScope = "ZiGong", ReplyRegular = "默认满意", VisitContent = "超过48小时自动回访", VisitState = EVisitState.Visited, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults=0, OrgHandledAttitude = 0, VisitType = EVisitType.SmsVisit, SortOrder = 0},
  257. new () {Name = "用户回答非1,2,3,4,5的匹配规则", AppScope = "ZiGong", ReplyRegular = "^(?!.*[12345]).*$", VisitContent = "默认满意", VisitState = EVisitState.Visited, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults=0, OrgHandledAttitude = 0, VisitType = EVisitType.SmsVisit, SortOrder = 6},
  258. new () {Name = "对部门处理结果满意", AppScope = "YiBin", ReplyRegular = "1", VisitContent = "满意", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults = 4 , OrgHandledAttitude = null, VisitType = EVisitType.SmsVisit, SortOrder = 1},
  259. new () {Name = "默认满意的规则", AppScope = "YiBin", ReplyRegular = "默认满意", VisitContent = "超过48小时自动回访", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=0, OrgHandledAttitude = 0 , VisitType = EVisitType.SmsVisit, SortOrder = 0},
  260. new () {Name = "对部门处理结果不满意的规则", AppScope = "YiBin", ReplyRegular = "2", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=2, OrgHandledAttitude = null , VisitType = null, SortOrder = 2},
  261. new () {Name = "用户回复的非1和2的规则", AppScope = "YiBin", ReplyRegular = "^(?!.*[12]).*$", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults= null, OrgHandledAttitude = null , VisitType = null, SortOrder = 3, IsReplyToOrgVisitContent = true},
  262. ];
  263. foreach (var item in entities)
  264. {
  265. item.UniqueKey = (item.AppScope + item.ReplyRegular).GetMD5();
  266. if (await _settingOrderVisitSmsReplyRuleRepository.AnyAsync(m => m.UniqueKey == item.UniqueKey) == false)
  267. await _settingOrderVisitSmsReplyRuleRepository.AddAsync(item);
  268. }
  269. }
  270. }