OrderControllerTest.cs 20 KB

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