OrderControllerTest.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. using AutoFixture;
  2. using Castle.DynamicProxy;
  3. using Hotline.Api.Controllers;
  4. using Hotline.Application.CallCenter;
  5. using Hotline.Application.Tests.Dto;
  6. using Hotline.Application.Tests.Infrastructure;
  7. using Hotline.Application.Tests.Mock;
  8. using Hotline.Application.Tests.SqlSuger;
  9. using Hotline.Caching.Interfaces;
  10. using Hotline.Caching.Services;
  11. using Hotline.CallCenter.Calls;
  12. using Hotline.FlowEngine.Notifications;
  13. using Hotline.FlowEngine.WorkflowModules;
  14. using Hotline.Identity.Accounts;
  15. using Hotline.Identity.Roles;
  16. using Hotline.Orders;
  17. using Hotline.Repository.SqlSugar;
  18. using Hotline.Repository.SqlSugar.Snapshot;
  19. using Hotline.Settings;
  20. using Hotline.Settings.Hotspots;
  21. using Hotline.Share.Dtos;
  22. using Hotline.Share.Dtos.CallCenter;
  23. using Hotline.Share.Dtos.File;
  24. using Hotline.Share.Dtos.FlowEngine;
  25. using Hotline.Share.Dtos.Order;
  26. using Hotline.Share.Dtos.Order.Publish;
  27. using Hotline.Share.Dtos.Snapshot;
  28. using Hotline.Share.Dtos.TrCallCenter;
  29. using Hotline.Share.Dtos.Users;
  30. using Hotline.Share.Enums.CallCenter;
  31. using Hotline.Share.Enums.FlowEngine;
  32. using Hotline.Share.Enums.Order;
  33. using Hotline.Share.Enums.Settings;
  34. using Hotline.Share.Tools;
  35. using Hotline.Snapshot.Interfaces;
  36. using Hotline.Users;
  37. using Mapster;
  38. using MediatR;
  39. using Microsoft.AspNetCore.Http;
  40. using Microsoft.AspNetCore.Mvc;
  41. using Microsoft.AspNetCore.Mvc.Testing;
  42. using Microsoft.Extensions.DependencyInjection;
  43. using Moq;
  44. using Shouldly;
  45. using SqlSugar;
  46. using System;
  47. using System.Collections.Generic;
  48. using System.Linq;
  49. using System.Text;
  50. using System.Threading;
  51. using System.Threading.Tasks;
  52. using XF.Domain.Authentications;
  53. using XF.Domain.Exceptions;
  54. using XF.Domain.Repository;
  55. namespace Hotline.Application.Tests.Controller;
  56. public class OrderControllerTest : TestBase
  57. {
  58. private readonly OrderController _orderController;
  59. private readonly IRepository<Hotspot> _hotspotRepository;
  60. private readonly IOrderRepository _orderRepository;
  61. private readonly OrderServiceMock _orderServiceMock;
  62. private readonly IRepository<OrderPublish> _orderPublishRepository;
  63. private readonly INotificationHandler<EndWorkflowNotify> _orderPublishEndWorkflowHandler;
  64. private readonly IOrderVisitRepository _orderVisitRepository;
  65. private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
  66. private readonly IRepository<SystemSetting> _systemSettingRepository;
  67. private readonly ISystemSettingCacheManager _systemSettingCacheManager;
  68. private readonly IRepository<CallNative> _callNativeRepository;
  69. private readonly IRepository<CallidRelation> _callIdRelationRepository;
  70. private readonly XingTangCallApplication _defaultCallApplication;
  71. private readonly ISqlSugarClient _capSqlClient;
  72. private readonly IIndustryRepository _industryRepository;
  73. private readonly IOrderSnapshotRepository _orderSnapshotRepository;
  74. private readonly ISystemLogRepository _systemLogRepository;
  75. private readonly IOrderVisitDomainService _orderVisitDomainService;
  76. private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
  77. public OrderControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository,
  78. UserController userController, IRepository<Hotspot> hotspotRepository, OrderController orderController,
  79. IOrderRepository orderRepository, IServiceScopeFactory scopeFactory, IRepository<User> userRepository,
  80. OrderServiceMock orderServiceMock, IRepository<OrderPublish> orderPublishRepository,
  81. INotificationHandler<EndWorkflowNotify> orderPublishEndWorkflowHandler,
  82. IOrderVisitRepository orderVisitRepository, IRepository<SystemSetting> systemSettingRepository,
  83. ISystemSettingCacheManager systemSettingCacheManager, IRepository<CallNative> callNativeRepository,
  84. IRepository<CallidRelation> callIdRelationRepository, XingTangCallApplication defaultCallApplication,
  85. ISugarUnitOfWork<CapDbContext> capDbContext, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdService,
  86. IThirdAccountRepository thirdAccount, IIndustryRepository industryRepository, IOrderSnapshotRepository orderSnapshotRepository,
  87. ISystemLogRepository systemLogRepository, IOrderVisitDomainService orderVisitDomainService, IRepository<OrderVisitDetail> orderVisitDetailRepository, ISystemDicDataCacheManager systemDicDataCacheManager)
  88. : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount)
  89. {
  90. _hotspotRepository = hotspotRepository;
  91. _orderController = orderController;
  92. _orderController.ControllerContext = new ControllerContext
  93. {
  94. HttpContext = new DefaultHttpContext()
  95. };
  96. _orderRepository = orderRepository;
  97. _orderServiceMock = orderServiceMock;
  98. _orderPublishRepository = orderPublishRepository;
  99. _orderPublishEndWorkflowHandler = orderPublishEndWorkflowHandler;
  100. _orderVisitRepository = orderVisitRepository;
  101. _systemSettingRepository = systemSettingRepository;
  102. _systemSettingCacheManager = systemSettingCacheManager;
  103. _callNativeRepository = callNativeRepository;
  104. _callIdRelationRepository = callIdRelationRepository;
  105. _defaultCallApplication = defaultCallApplication;
  106. _capSqlClient = capDbContext.Db;
  107. _industryRepository = industryRepository;
  108. _orderSnapshotRepository = orderSnapshotRepository;
  109. _systemLogRepository = systemLogRepository;
  110. _orderVisitDomainService = orderVisitDomainService;
  111. _orderVisitDetailRepository = orderVisitDetailRepository;
  112. _systemDicDataCacheManager = systemDicDataCacheManager;
  113. }
  114. /// <summary>
  115. /// 创建工单时传入一个错误callId
  116. /// 验证:
  117. /// 测试在延迟消息后会不会把工单测CallId修复成正确的CallId
  118. /// 推送的省上数据是否正确
  119. /// 测试修复后的CallId 再次保存功能, 能通过 systemLog 查询修复记录, 拦截工单保存
  120. /// </summary>
  121. /// <returns></returns>
  122. [Fact]
  123. public async Task OrderCallIdRelevance_Test()
  124. {
  125. var callNo = DateTime.Now.ToString("yyyyMMddhhmmss") + "Flow";
  126. var inDto = _fixture.Build<CallNative>()
  127. .With(m => m.Id, Ulid.NewUlid().ToString())
  128. .With(m => m.CallNo, callNo)
  129. .With(m => m.Direction, ECallDirection.In)
  130. .With(m => m.IsDeleted, false)
  131. .Create();
  132. await _callNativeRepository.AddAsync(inDto);
  133. var inDto2 = _fixture.Build<CallNative>()
  134. .With(m => m.Id, Ulid.NewUlid().ToString())
  135. .With(m => m.Direction, ECallDirection.Out)
  136. .With(m => m.CallNo, callNo)
  137. .With(m => m.AudioFile, string.Empty)
  138. .With(m => m.IsDeleted, false)
  139. .Create();
  140. await _callNativeRepository.AddAsync(inDto2);
  141. var callOrder = new CallidRelation
  142. {
  143. Id = callNo,
  144. CallId = inDto2.Id,
  145. };
  146. await _callIdRelationRepository.AddAsync(callOrder, CancellationToken.None);
  147. SetZuoXi();
  148. var order = _orderServiceMock.CreateOrder(callNo)
  149. .办理到派单员()
  150. .GetCreateResult();
  151. order.ShouldNotBeNull();
  152. await _defaultCallApplication.OrderRelateCallHandlerAsync(order.Id, CancellationToken.None);
  153. var orderEntity = await _orderRepository.GetAsync(order.Id);
  154. orderEntity.ShouldNotBeNull();
  155. orderEntity.CallId.ShouldBe(inDto.Id);
  156. var query = _capSqlClient.Queryable<PublishedEntity>()
  157. .Where(m => m.Name == "hotline.call.connect.order" && m.Content.Contains(order.Id));
  158. var sql = query.ToSqlString();
  159. sql.Contains("id").ShouldBeFalse("字段大小写错误" + sql);
  160. var published = await query.FirstAsync();
  161. published.ShouldNotBeNull("推送数据不存在");
  162. var message = published.Content.FromJson<Message<PublishCallRecrodDto>>();
  163. message.Value.Order.ShouldNotBeNull("推送的工单信息为空");
  164. message.Value.Order.ProvinceNo.ShouldNotBeNull("省工单编号不能为空");
  165. message.Value.Order.No.ShouldBe(order.No, "推送的工单编号错误");
  166. try
  167. {
  168. order = _orderServiceMock.CreateOrder(callNo)
  169. .办理到派单员()
  170. .GetCreateResult();
  171. }
  172. catch (UserFriendlyException e)
  173. {
  174. e.FriendlyMessage.ShouldBe("来电已保存工单!");
  175. }
  176. }
  177. [Fact]
  178. public async Task Visit_Test()
  179. {
  180. SetZuoXi();
  181. var order = _orderServiceMock.CreateOrder()
  182. .办理到一级部门()
  183. .办理到二级部门(Set一级部门)
  184. .办理一级部门汇总(Set二级部门)
  185. .办理到归档(Set一级部门)
  186. .发布工单(SetZuoXi)
  187. .GetCreateResult();
  188. var visit = await _orderVisitRepository.Queryable()
  189. .Where(m => m.OrderId == order.Id)
  190. .FirstAsync();
  191. var visitDetaila = await _orderVisitDetailRepository.Queryable().Where(m => m.VisitId == visit.Id).ToListAsync();
  192. var visitDetail = visitDetaila.Adapt<List<VisitDetailDto>>();
  193. visitDetail.ForEach(m => {
  194. m.SeatEvaluate = ESeatEvaluate.DefaultSatisfied;
  195. var smsReply = _orderVisitDomainService.GetVisitEvaluateByReplyTxt("0");
  196. m.OrgProcessingResults = smsReply.GetOrgProcessingResults(_systemDicDataCacheManager.VisitSatisfaction);
  197. m.OrgHandledAttitude = smsReply.GetOrgHandledAttitude(_systemDicDataCacheManager.VisitSatisfaction);
  198. });
  199. var callNo = DateTime.Now.ToString("yyyyMMddhhmmss") + "Flow";
  200. var inDto = _fixture.Build<CallNative>()
  201. .With(m => m.Id, Ulid.NewUlid().ToString())
  202. .With(m => m.CallNo, callNo)
  203. .With(m => m.Direction, ECallDirection.In)
  204. .With(m => m.IsDeleted, false)
  205. .Create();
  206. await _callNativeRepository.AddAsync(inDto);
  207. _systemLogRepository.Add("回访外呼已经接通", "", new CallRemarkDto { CallId = callNo, CallNumber = inDto.ToNo }.ToJson(), "", 1, visit.Id);
  208. var visitDto = new VisitDto
  209. {
  210. Id = visit.Id,
  211. IsPutThrough = true,
  212. VisitDetails = visitDetail
  213. };
  214. await _orderController.Visit(visitDto);
  215. }
  216. /// <summary>
  217. /// 创建工单并派送给派单员
  218. /// </summary>
  219. /// <returns></returns>
  220. [Fact]
  221. public async Task ToPaiDanYuan_Test()
  222. {
  223. SetZuoXi();
  224. var order = _orderServiceMock.CreateOrder()
  225. .办理到派单员()
  226. .GetCreateResult();
  227. order.ShouldNotBeNull();
  228. }
  229. /// <summary>
  230. /// 创建随手拍工单
  231. /// 验证随手拍工单是否能正常创建
  232. /// </summary>
  233. /// <returns></returns>
  234. [Fact]
  235. public async Task OrderSnapshot_Test()
  236. {
  237. var industryItems = await _industryRepository.Queryable() .Select(d => new { d.Id, d.Name, }) .ToListAsync();
  238. var industry = industryItems.First();
  239. SetZuoXi();
  240. var order = _orderServiceMock.CreateOrder(industryId:industry.Id, industryName: industry.Name)
  241. .办理到派单员()
  242. .办理到归档(SetPaiDanYuan, data =>
  243. {
  244. data.IsEvasive = true;
  245. data.IsInactively = true;
  246. })
  247. .GetCreateResult();
  248. var orderEntity = await _orderRepository.GetAsync(order.Id);
  249. orderEntity.ShouldNotBeNull();
  250. var snapshot = await _orderSnapshotRepository.GetAsync(m => m.Id == order.Id);
  251. snapshot.ShouldNotBeNull();
  252. snapshot.IndustryId.ShouldBe(industry.Id);
  253. snapshot.IndustryName.ShouldBe(industry.Name);
  254. }
  255. /// <summary>
  256. /// 验证中心直办工单归档后 自动发布
  257. /// 是否推诿, 是否不积极
  258. /// </summary>
  259. /// <returns></returns>
  260. [Fact]
  261. public async Task AutoPublish_Test()
  262. {
  263. SetZuoXi();
  264. var order = _orderServiceMock.CreateOrder()
  265. .办理到派单员()
  266. .办理到归档(SetPaiDanYuan, data =>
  267. {
  268. data.IsEvasive = true;
  269. data.IsInactively = true;
  270. })
  271. .GetCreateResult();
  272. var publish = await _orderPublishRepository.GetAsync(m => m.No == order.No);
  273. publish.ShouldNotBeNull(order.No);
  274. var orderEntity = await _orderRepository.GetAsync(order.Id);
  275. orderEntity.ShouldNotBeNull();
  276. orderEntity.IsEvasive.ShouldBeTrue();
  277. orderEntity.IsInactively.ShouldBeTrue();
  278. orderEntity.Status.ShouldBe(EOrderStatus.Visited);
  279. orderEntity.OrgProcessingResults.ShouldNotBeNull();
  280. orderEntity.OrgProcessingResults.Key.ShouldBe("4");
  281. orderEntity.OrgProcessingResults.Value.ShouldBe("满意");
  282. orderEntity.SeatEvaluate.ShouldBe(ESeatEvaluate.Satisfied);
  283. }
  284. [Fact]
  285. public void Set一级部门_Test()
  286. {
  287. Set一级部门();
  288. }
  289. [Fact]
  290. public async Task IsStepUrgent_True_Test()
  291. {
  292. SetZuoXi();
  293. var order = _orderServiceMock.CreateOrder()
  294. .办理到派单员()
  295. .办理到归档(SetPaiDanYuan, data => data.IsStepUrgent = true, workflow =>
  296. {
  297. workflow.BusinessType = EBusinessType.DepartmentLeader;
  298. workflow.Opinion = "测试保存勾选紧急";
  299. })
  300. .GetCreateResult();
  301. order.ShouldNotBeNull();
  302. order.Id.ShouldNotBeNull();
  303. var orderDto = await _orderController.Get(order.Id);
  304. orderDto.IsStepUrgent.ShouldBeTrue();
  305. orderDto.IsStepUrgenText.ShouldBe("紧急");
  306. }
  307. /// <summary>
  308. /// 测试在办理的过程中能正确保存
  309. /// 1.与市民电话联系
  310. /// 2.已赴现场处置
  311. /// 3.其他
  312. /// 4.其他原因
  313. /// 5.经办人
  314. /// 6.经办人电话
  315. /// 7.沟通时间
  316. /// 8.沟通地点
  317. /// </summary>
  318. /// <returns></returns>
  319. [Fact]
  320. public async Task CreateOrder_Test()
  321. {
  322. SetZuoXi();
  323. var order = _orderServiceMock.CreateOrder()
  324. .办理到一级部门()
  325. .办理到二级部门(Set一级部门)
  326. .办理一级部门汇总(Set二级部门)
  327. .GetCreateResult();
  328. order.Id.ShouldNotBeNull();
  329. var orderEntity = await _orderRepository.GetAsync(order.Id);
  330. orderEntity.RealCommunicationAddress.ShouldNotBeNull();
  331. orderEntity.RealCommunicationTime.ShouldNotBeNull();
  332. orderEntity.RealContactLocale.ShouldNotBeNull();
  333. orderEntity.RealContactLocale.ShouldBe(true);
  334. orderEntity.RealHandlerName.ShouldNotBeNull();
  335. orderEntity.RealHandlerPhone.ShouldNotBeNull();
  336. }
  337. [Fact]
  338. public async Task GetOrderHandleTimeConfigByAcceptType_Test()
  339. {
  340. var result = await _orderController.GetOrderHandleTimeConfigByAcceptType(Share.Enums.FlowEngine.EFlowDirection.OrgToCenter, "10");
  341. result.Count.ShouldBe(1);
  342. result.TimeText.ShouldBe("1个工作日");
  343. result.TimeType.ShouldBe(ETimeType.WorkDay);
  344. }
  345. /// <summary>
  346. /// 测试取消发布功能
  347. /// </summary>
  348. /// <returns></returns>
  349. [Fact]
  350. public async Task CancelOrderPublish_Test()
  351. {
  352. var system = await _systemSettingRepository.Queryable()
  353. .Where(m => m.Code == SettingConstants.CancelPublishOrderEnabled)
  354. .FirstAsync();
  355. system.SettingValue[0] = "true";
  356. await _systemSettingRepository.UpdateAsync(system);
  357. _systemSettingCacheManager.DelSystemSetting(SettingConstants.CancelPublishOrderEnabled);
  358. SetZuoXi();
  359. var order = _orderServiceMock.CreateOrder()
  360. .办理到派单员()
  361. .办理到归档(SetPaiDanYuan, data =>
  362. {
  363. data.IsEvasive = true;
  364. data.IsInactively = true;
  365. })
  366. .GetCreateResult();
  367. var publish = await _orderPublishRepository.GetAsync(m => m.No == order.No);
  368. publish.ShouldNotBeNull(order.No);
  369. var orderEntity = await _orderRepository.GetAsync(order.Id);
  370. orderEntity.ShouldNotBeNull();
  371. orderEntity.IsEvasive.ShouldBeTrue();
  372. orderEntity.IsInactively.ShouldBeTrue();
  373. await _orderController.PublishCancelAsync(new PublishCancelInDto { OrderPublishId = publish.Id });
  374. var visit = await _orderVisitRepository.GetAsync(m => m.OrderId == order.Id);
  375. var publishCount = await _orderPublishRepository.Queryable().Where(m => m.OrderId == order.Id && m.IsDeleted == false).CountAsync();
  376. publishCount.ShouldBe(0, "发布工单数据已经被删除, 应该是0条");
  377. visit.ShouldNotBeNull("回访信息不存在");
  378. visit.VisitState.ShouldBe(EVisitState.Visited, "回访状态应该是已回访");
  379. orderEntity = await _orderRepository.GetAsync(order.Id);
  380. orderEntity.Status.ShouldBe(EOrderStatus.Filed);
  381. var publishList = await _orderController.PublishOrderList(new QueryOrderPublishDto
  382. {
  383. PageSize = 1000,
  384. QuerySelf = true
  385. });
  386. publishList.Items.Any(m => m.Id == order.Id).ShouldBeTrue("工单发布列表中没有取消的工单");
  387. SetZuoXi();
  388. // 验证是否能非上次发布人员发布
  389. try
  390. {
  391. await _orderController.PublishOrder(new PublishOrderDto { Id = order.Id });
  392. }
  393. catch (UserFriendlyException e)
  394. {
  395. e.Message.Contains("您不能发布").ShouldBeTrue();
  396. }
  397. // 验证被取消前的发布人能否继续发布
  398. SetPaiDanYuan();
  399. var inDto = _fixture.Create<PublishOrderDto>();
  400. inDto.Id = order.Id;
  401. await _orderController.PublishOrder(inDto);
  402. var published = await _orderPublishRepository.Queryable().Where(m => m.OrderId == order.Id && m.IsDeleted == false).FirstAsync();
  403. published.ShouldNotBeNull();
  404. published.IsDeleted.ShouldBeFalse();
  405. }
  406. /// <summary>
  407. /// 工单批量标注
  408. /// </summary>
  409. /// <returns></returns>
  410. [Fact]
  411. public async Task OrderSignBath_Test()
  412. {
  413. var inDto = new OrderSignBathInDto
  414. {
  415. IsSafetyDepartment = true,
  416. Remark = "单元测试标注",
  417. OrderIds = new List<string>()
  418. };
  419. inDto.OrderIds.Add(_orderServiceMock.CreateSnapshotOrder(SetWeiXin).办理到工单标注(SetZuoXi).GetCreateResult().Id);
  420. inDto.OrderIds.Add(_orderServiceMock.CreateSnapshotOrder(SetWeiXin).办理到工单标注(SetZuoXi).GetCreateResult().Id);
  421. Set班长();
  422. await _orderController.GetNextStepsWithRecommend(inDto.OrderIds.First());
  423. var result = await _orderController.OrderSignBathAsync(inDto);
  424. result.Contains("标注完成").ShouldBe(true);
  425. }
  426. }