OrderVisitDomainServiceTest.cs 19 KB

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