OrderVisitDomainServiceTest.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. public async Task UpdateSmsReply_Test(string content, string visitState, string orgResuktKey, string orgResuktValue, string visitContent, string visited = "Visited", string appScope = "ZiGong")
  113. {
  114. if (appScope != "ZiGong")
  115. ChangeAppScopeYiBin();
  116. else
  117. ChangeAppScopeZiGong();
  118. var appScopeFile = _appOptions.Value.AppScope;
  119. SetZuoXi();
  120. var order = _orderServiceMock.CreateOrder()
  121. .办理到一级部门()
  122. .办理到二级部门(Set一级部门)
  123. .办理一级部门汇总(Set二级部门)
  124. .办理到归档(Set一级部门)
  125. .发布工单(SetZuoXi)
  126. .发送回访短信(SetZuoXi)
  127. .GetCreateResult();
  128. order.Id.ShouldNotBeNull();
  129. var visit = await _orderVisitRepository.Queryable()
  130. .Includes(m => m.Order)
  131. .Where(m => m.VisitState == EVisitState.SMSVisiting)
  132. .OrderByDescending(m => m.CreationTime)
  133. .FirstAsync();
  134. if (visit == null) return;
  135. visit.ShouldNotBeNull("缺少测试数据");
  136. var message = new MessageDto { ExternalId = visit.Id, IsSmsReply = true, SmsReplyContent = content, TelNumber = visit.Order.Contact };
  137. var dto = new PushReceiveMessageDto();
  138. await _orderVisitDomainService.UpdateSmsReplyAsync(message);
  139. visit = _orderVisitRepository.Get(visit.Id);
  140. visit.VisitState.ShouldBe(visitState.ToEnum<EVisitState>());
  141. if (orgResuktKey.NotNullOrEmpty())
  142. {
  143. visit.NowEvaluate.ShouldNotBeNull();
  144. visit.NowEvaluate.Key.ShouldBe(orgResuktKey);
  145. visit.NowEvaluate.Value.ShouldBe(orgResuktValue);
  146. }
  147. var orderEntity = await _orderRepository.GetAsync(order.Id);
  148. orderEntity.ShouldNotBeNull();
  149. orderEntity.Status.ShouldBe(visited.ToEnum<EOrderStatus>());
  150. if (content == "4" || content == "5" || content == "不满意" || content == "非常不满意" || content == "都没有办理好")
  151. {
  152. visit.VisitType.ShouldBeNull();
  153. }
  154. var smsReply = _orderVisitDomainService.GetVisitEvaluateByReplyTxt(content);
  155. var log = _logRepository.Queryable().Where(m => m.Name == "短信回访-回复内容匹配结果" && m.Remark == order.No).First();
  156. log.ShouldNotBeNull();
  157. await _orderVisitDetailRepository.Queryable()
  158. .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Org)
  159. .FirstAsync()
  160. .Then(org =>
  161. {
  162. if (content != "都没有办理好")
  163. {
  164. org.OrgProcessingResults.ShouldNotBeNull();
  165. org.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
  166. org.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
  167. org.VisitContent.ShouldBe(visitContent);
  168. // 验证跟新工单上的字段是否成功
  169. if (new string[] { "4", "5", "不满意", "非常不满意"}.Contains(content) == false)
  170. {
  171. if (appScope != "YiBin" && content != "2")
  172. {
  173. orderEntity.OrgProcessingResults.ShouldNotBeNull();
  174. orderEntity.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
  175. orderEntity.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
  176. }
  177. }
  178. if (appScope != "YiBin")
  179. {
  180. org.OrgHandledAttitude.ShouldNotBeNull();
  181. org.OrgHandledAttitude.Key.ShouldBe(orgResuktKey);
  182. org.OrgHandledAttitude.Value.ShouldBe(orgResuktValue);
  183. }
  184. if (smsReply.IsReplyToOrgVisitContent == true)
  185. {
  186. org.VisitContent = content;
  187. }
  188. }
  189. return Task.CompletedTask;
  190. });
  191. await _orderVisitDetailRepository.Queryable()
  192. .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Seat)
  193. .FirstAsync()
  194. .Then(seat =>
  195. {
  196. if (content != "都没有办理好")
  197. {
  198. // 验证跟新工单上的字段是否成功
  199. if (new string[] { "4", "5", "不满意", "非常不满意", "都没有办理好" }.Contains(content) == true)
  200. {
  201. seat.SeatEvaluate.ShouldNotBe(ESeatEvaluate.NoSatisfied);
  202. seat.SeatEvaluate.ShouldNotBe(ESeatEvaluate.VeryNoSatisfied);
  203. seat.VoiceEvaluate.ShouldNotBe(EVoiceEvaluate.NoSatisfied);
  204. seat.VoiceEvaluate.ShouldNotBe(EVoiceEvaluate.VeryNoSatisfied);
  205. }
  206. else
  207. {
  208. if (smsReply.SeatEvaluate != null)
  209. seat.SeatEvaluate.ShouldBe(smsReply.SeatEvaluate);
  210. if (smsReply.VoiceEvaluate != null)
  211. seat.VoiceEvaluate.ShouldBe(smsReply.VoiceEvaluate);
  212. }
  213. }
  214. return Task.CompletedTask;
  215. });
  216. }
  217. [Theory]
  218. [InlineData("1", "非常满意", "Visited", "", "", "非常满意|5")]
  219. [InlineData("2", "满意", "Visited", "", "", "满意|4")]
  220. [InlineData("3", "一般", "Visited", "", "", "满意|4")]
  221. [InlineData("4", "不满意", "SMSUnsatisfied", "", "", "不满意|2")]
  222. [InlineData("5", "不满意", "SMSUnsatisfied", "", "", "不满意|2")]
  223. //[InlineData("默认满意", "超过48小时自动回访", "Visited", "DefaultSatisfied", "DefaultSatisfied", "默认满意|0")]
  224. [InlineData("默认满意", "超过48小时自动回访", "Visited", "", "", "默认满意|0")]
  225. [InlineData("1非常满意", "非常满意", "Visited", "", "", "非常满意|5")]
  226. public void GetVisitEvaluateByReplyTxt_Test(string replyTxt, string assertReplyTxt, string visitState, string seatEvaluate, string voiceEvaluate, string kv)
  227. {
  228. var smsReply = _orderVisitDomainService.GetVisitEvaluateByReplyTxt(replyTxt);
  229. var replyString = smsReply.VisitContent;
  230. replyString.ShouldBe(assertReplyTxt);
  231. var visitStateEnum = smsReply.VisitState;
  232. visitStateEnum.ShouldBe(visitState.ToEnum<EVisitState>());
  233. if (seatEvaluate.NotNullOrEmpty())
  234. {
  235. var seatEvaluateEnum = smsReply.SeatEvaluate;
  236. seatEvaluateEnum.ShouldBe(seatEvaluate.ToEnum<ESeatEvaluate>());
  237. }
  238. if (voiceEvaluate.NotNullOrEmpty())
  239. {
  240. var voiceEvaluateEnum = smsReply.VoiceEvaluate;
  241. voiceEvaluateEnum.ShouldBe(voiceEvaluate.ToEnum<EVoiceEvaluate>());
  242. }
  243. var kvResult = smsReply.GetOrgProcessingResults(_systemDicDataCacheManager.VisitSatisfaction);
  244. var sp = kv.Split('|');
  245. var kV = new Kv(sp[1].ToString(), sp[0].ToString());
  246. kvResult.Key.ShouldBe(kV.Key);
  247. kvResult.Value.ShouldBe(kV.Value);
  248. }
  249. [Fact]
  250. public async Task Init_SettingOrderVisitSmsReplyRule_Data()
  251. {
  252. IEnumerable<SettingOrderVisitSmsReplyRule> entities = [
  253. new () {Name = "非常满意的规则", AppScope = "ZiGong", ReplyRegular = "1", VisitContent = "非常满意", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=5, OrgHandledAttitude = 5, VisitType = EVisitType.SmsVisit, SortOrder = 1},
  254. new () {Name = "满意的规则", AppScope = "ZiGong", ReplyRegular = "2", VisitContent = "满意", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=4, OrgHandledAttitude = 4 , VisitType = EVisitType.SmsVisit, SortOrder = 2},
  255. new () {Name = "一般的规则", AppScope = "ZiGong", ReplyRegular = "3", VisitContent = "一般", VisitState = EVisitState.Visited, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults= 4, OrgHandledAttitude = 4 , VisitType = EVisitType.SmsVisit, SortOrder = 3},
  256. new () {Name = "不满意的规则", AppScope = "ZiGong", ReplyRegular = "4", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=2, OrgHandledAttitude = 2 , VisitType = null, SortOrder = 4},
  257. new () {Name = "非常不满意的规则", AppScope = "ZiGong", ReplyRegular = "5", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults=2, OrgHandledAttitude = 2, VisitType = null, SortOrder = 5},
  258. new () {Name = "默认满意的规则", AppScope = "ZiGong", ReplyRegular = "默认满意", VisitContent = "超过48小时自动回访", VisitState = EVisitState.Visited, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults=0, OrgHandledAttitude = 0, VisitType = EVisitType.SmsVisit, SortOrder = 0},
  259. 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},
  260. new () {Name = "对部门处理结果满意", AppScope = "YiBin", ReplyRegular = "1", VisitContent = "满意", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults = 4 , OrgHandledAttitude = null, VisitType = EVisitType.SmsVisit, SortOrder = 1},
  261. new () {Name = "默认满意的规则", AppScope = "YiBin", ReplyRegular = "默认满意", VisitContent = "超过48小时自动回访", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=0, OrgHandledAttitude = 0 , VisitType = EVisitType.SmsVisit, SortOrder = 0},
  262. new () {Name = "对部门处理结果不满意的规则", AppScope = "YiBin", ReplyRegular = "2", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=2, OrgHandledAttitude = null , VisitType = null, SortOrder = 2},
  263. 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},
  264. new () {Name = "非常满意的规则", AppScope = "LuZhou", ReplyRegular = "1", VisitContent = "非常满意", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=5, OrgHandledAttitude = 0, VisitType = EVisitType.SmsVisit, SortOrder = 1},
  265. new () {Name = "满意的规则", AppScope = "LuZhou", ReplyRegular = "2", VisitContent = "满意", VisitState = EVisitState.Visited, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=4, OrgHandledAttitude = 0 , VisitType = EVisitType.SmsVisit, SortOrder = 2},
  266. new () {Name = "一般的规则", AppScope = "LuZhou", ReplyRegular = "3", VisitContent = "一般", VisitState = EVisitState.Visited, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults= 4, OrgHandledAttitude = 0 , VisitType = EVisitType.SmsVisit, SortOrder = 3},
  267. new () {Name = "不满意的规则", AppScope = "LuZhou", ReplyRegular = "4", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null,VoiceEvaluate = null,OrgProcessingResults=2, OrgHandledAttitude = 0 , VisitType = null, SortOrder = 4},
  268. new () {Name = "非常不满意的规则", AppScope = "LuZhou", ReplyRegular = "5", VisitContent = "不满意", VisitState = EVisitState.SMSUnsatisfied, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults=2, OrgHandledAttitude = 0, VisitType = null, SortOrder = 5},
  269. new () {Name = "默认满意的规则", AppScope = "LuZhou", ReplyRegular = "默认满意", VisitContent = "超过48小时自动回访", VisitState = EVisitState.Visited, SeatEvaluate = null, VoiceEvaluate = null,OrgProcessingResults=0, OrgHandledAttitude = 0, VisitType = EVisitType.SmsVisit, SortOrder = 0},
  270. 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},
  271. ];
  272. foreach (var item in entities)
  273. {
  274. item.UniqueKey = (item.AppScope + item.ReplyRegular).GetMD5();
  275. if (await _settingOrderVisitSmsReplyRuleRepository.AnyAsync(m => m.UniqueKey == item.UniqueKey) == false)
  276. await _settingOrderVisitSmsReplyRuleRepository.AddAsync(item);
  277. }
  278. }
  279. }