OrderVisitDomainServiceTest.cs 17 KB

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