OrderDomainService.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. using DotNetCore.CAP;
  2. using Hotline.FlowEngine;
  3. using Hotline.FlowEngine.Workflows;
  4. using Hotline.Share.Dtos.Order;
  5. using Hotline.Share.Enums.Order;
  6. using Hotline.Share.Mq;
  7. using MapsterMapper;
  8. using Microsoft.Extensions.Logging;
  9. using System.Threading;
  10. using Hotline.Share.Consts;
  11. using SqlSugar;
  12. using XF.Domain.Authentications;
  13. using XF.Domain.Cache;
  14. using XF.Domain.Dependency;
  15. using XF.Domain.Entities;
  16. using XF.Domain.Exceptions;
  17. using XF.Domain.Extensions;
  18. using XF.Domain.Repository;
  19. using Hotline.CallCenter.Calls;
  20. using Hotline.Share.Dtos.CallCenter;
  21. namespace Hotline.Orders;
  22. public class OrderDomainService : IOrderDomainService, IScopeDependency
  23. {
  24. private const string OrderNoPrefix = "OrderNo:";
  25. private readonly IOrderRepository _orderRepository;
  26. private readonly IRepository<OrderRedo> _orderRedoRepository;
  27. private readonly IRepository<OrderPublish> _orderPublishRepository;
  28. private readonly IRepository<OrderVisit> _orderVisitRepository;
  29. private readonly ITypedCache<CacheOrderNO> _cacheOrderNo;
  30. private readonly ISessionContext _sessionContext;
  31. private readonly ICapPublisher _capPublisher;
  32. private readonly IMapper _mapper;
  33. private readonly ILogger<OrderDomainService> _logger;
  34. private readonly IRepository<WexCallRecord> _wexCallRecordRepository;
  35. public OrderDomainService(
  36. IOrderRepository orderRepository,
  37. IRepository<OrderRedo> orderRedoRepository,
  38. IRepository<OrderPublish> orderPublishRepository,
  39. IRepository<OrderVisit> orderVisitRepository,
  40. ITypedCache<CacheOrderNO> cacheOrderNo,
  41. ISessionContext sessionContext,
  42. ICapPublisher capPublisher,
  43. IMapper mapper,
  44. ILogger<OrderDomainService> logger,
  45. IRepository<WexCallRecord> wexCallRecordRepository)
  46. {
  47. _orderRepository = orderRepository;
  48. _orderRedoRepository = orderRedoRepository;
  49. _orderPublishRepository = orderPublishRepository;
  50. _orderVisitRepository = orderVisitRepository;
  51. _cacheOrderNo = cacheOrderNo;
  52. _sessionContext = sessionContext;
  53. _capPublisher = capPublisher;
  54. _mapper = mapper;
  55. _logger = logger;
  56. _wexCallRecordRepository = wexCallRecordRepository;
  57. }
  58. public async Task<Order> GetOrderAsync(string? orderId, CancellationToken cancellationToken)
  59. {
  60. if (string.IsNullOrEmpty(orderId))
  61. throw UserFriendlyException.SameMessage("无效工单编号");
  62. var order = await _orderRepository.Queryable()
  63. .Includes(d => d.Hotspot)
  64. .Includes(d => d.Acceptor)
  65. .FirstAsync(d => d.Id == orderId, cancellationToken);
  66. if (order == null)
  67. throw new UserFriendlyException($"无效工单编号, orderId: {orderId}", "无效工单编号");
  68. return order;
  69. }
  70. public async Task<string> AddAsync(Order order, CancellationToken cancellationToken)
  71. {
  72. if (order.OrderType == EOrderType.MarketSupervisionBy12315 && order.AcceptTypeCode == AcceptTypeConst.TouSu && order.OrderComplain == null)
  73. throw UserFriendlyException.SameMessage("非法投诉参数");
  74. if (order.OrderType == EOrderType.MarketSupervisionBy12315 && order.AcceptTypeCode == AcceptTypeConst.JuBao && order.OrderReport == null)
  75. throw UserFriendlyException.SameMessage("非法举报参数");
  76. order.Init(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.StaffNo);
  77. order.No = GenerateNewOrderNo();
  78. if (order.SourceChannelCode == OrderDefaults.SourceChannel.DianHua && !string.IsNullOrEmpty(order.CallId))
  79. {
  80. var callRecord = await _wexCallRecordRepository.GetAsync(x => x.CallId == order.CallId,cancellationToken);
  81. if (callRecord != null)
  82. {
  83. await _capPublisher.PublishAsync(EventNames.HotlineCallConnectWithOrder, new CallConnectOrderDto
  84. {
  85. Order = _mapper.Map<OrderDto>(order),
  86. CallRecord = _mapper.Map<CallRecordDto>(callRecord)
  87. }, cancellationToken: cancellationToken);
  88. }
  89. }
  90. return await _orderRepository.AddOrderNavAsync(order, cancellationToken);
  91. }
  92. /// <summary>
  93. /// 归档
  94. /// </summary>
  95. public async Task FileAsync(string? orderId, CancellationToken cancellationToken)
  96. {
  97. var order = await GetOrderAsync(orderId, cancellationToken);
  98. order.Filed();
  99. await _orderRepository.UpdateAsync(order, cancellationToken);
  100. }
  101. /// <summary>
  102. /// 撤回或跳转前处理数据及校验
  103. /// <remarks>
  104. ///工单撤回时需校验工单当前是否存在待发布记录、待回访记录,若存在需删除对应记录(跳转同理)
  105. ///工单撤回时需校验工单是否存在甄别中记录,若存在不允许撤回当前工单(跳转同理)
  106. /// </remarks>
  107. /// </summary>
  108. public async Task ReadyToRecallAsync(string orderId, CancellationToken cancellationToken)
  109. {
  110. var order = await _orderRepository.Queryable()
  111. .Includes(d => d.OrderPublish)
  112. .Includes(d => d.OrderVisits.Where(d => d.VisitState == EVisitState.WaitForVisit))
  113. .Includes(d => d.OrderScreens)
  114. .FirstAsync(d => d.Id == orderId, cancellationToken);
  115. if (order.OrderScreens.Any())
  116. throw UserFriendlyException.SameMessage("已甄别工单无法撤回或跳转");
  117. if (order.OrderPublish is not null)
  118. await _orderPublishRepository.RemoveAsync(order.OrderPublish, cancellationToken: cancellationToken);
  119. if (order.OrderVisits.Any())
  120. await _orderVisitRepository.RemoveNav(order.OrderVisits)
  121. .Include(d => d.OrderVisitDetails)
  122. .ExecuteCommandAsync();
  123. }
  124. public Task<string> AddOrderRedoAsync(OrderRedo orderRedo, CancellationToken cancellationToken) =>
  125. _orderRedoRepository.AddAsync(orderRedo, cancellationToken);
  126. public Task RemoveOrderRedoAsync(string id, CancellationToken cancellationToken) =>
  127. _orderRedoRepository.RemoveAsync(id, cancellationToken: cancellationToken);
  128. public Task UpdateOrderRedoAsync(OrderRedo orderRedo, CancellationToken cancellationToken) =>
  129. _orderRedoRepository.UpdateAsync(orderRedo, cancellationToken);
  130. #region private
  131. private async Task<Order> GetOrderByFlowIdAsync(string workflowId, CancellationToken cancellationToken)
  132. {
  133. if (string.IsNullOrEmpty(workflowId))
  134. throw UserFriendlyException.SameMessage("无效流程编号");
  135. var order = await _orderRepository.Queryable()
  136. .Includes(d => d.Hotspot)
  137. .Includes(d => d.Acceptor)
  138. .FirstAsync(d => d.WorkflowId == workflowId);
  139. if (order == null)
  140. throw new UserFriendlyException($"无效流程编号, workflowId: {workflowId}", "无效流程编号");
  141. return order;
  142. }
  143. //private void CheckOrderIfFiled(Order order)
  144. //{
  145. // if (order.Status is EOrderStatus.Filed)
  146. // throw UserFriendlyException.SameMessage("工单已归档");
  147. //}
  148. private string GenerateNewOrderNo()
  149. {
  150. var today = DateTime.Today;
  151. var cacheKey = $"{OrderNoPrefix}{today:yyyyMMdd}";
  152. var cacheOrderNo = _cacheOrderNo.GetOrSet(cacheKey, f =>
  153. {
  154. var todayOrderCount = _orderRepository.Queryable(true)
  155. .CountAsync(d => d.CreationTime.Date == today.Date)
  156. .GetAwaiter()
  157. .GetResult();
  158. return new CacheOrderNO { TotalCount = todayOrderCount };
  159. }, TimeSpan.FromDays(1));
  160. cacheOrderNo!.TotalCount += 1;
  161. var no = GenerateOrderNo(today, cacheOrderNo.TotalCount);
  162. _cacheOrderNo.Set(cacheKey, cacheOrderNo);
  163. return no;
  164. }
  165. private string GenerateOrderNo(DateTime today, int count)
  166. {
  167. return $"{today:yyyyMMdd}{count.ToString("000000")}";
  168. }
  169. #endregion
  170. }
  171. public class CacheOrderNO
  172. {
  173. public int TotalCount { get; set; }
  174. }