XingTangCallsSyncJob.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. using Hotline.Application.CallCenter;
  2. using Hotline.Share.Tools;
  3. using Quartz;
  4. using SqlSugar;
  5. using Hotline.CallCenter.Calls;
  6. using Hotline.Repository.SqlSugar;
  7. using Hotline.Users;
  8. using MapsterMapper;
  9. using Microsoft.Extensions.Logging;
  10. using XF.Domain.Repository;
  11. using XingTang.Sdk;
  12. using DotNetCore.CAP;
  13. using Hotline.Share.Dtos.Order;
  14. using Hotline.Share.Dtos.TrCallCenter;
  15. using Hotline.Share.Enums.CallCenter;
  16. using System.Dynamic;
  17. using Hotline.Share.Dtos.CallCenter;
  18. using Hotline.Caching.Interfaces;
  19. using Mapster;
  20. using Hotline.Share.Mq;
  21. namespace Hotline.Application.Jobs
  22. {
  23. /// <summary>
  24. /// 查询兴唐通话记录
  25. /// </summary>
  26. public class XingTangCallsSyncJob : IJob, IDisposable
  27. {
  28. private readonly IRepository<CallNative> _callRepository;
  29. private readonly IRepository<User> _userRepository;
  30. private readonly ICallApplication _callApplication;
  31. private readonly ICapPublisher _capPublisher;
  32. private readonly IMapper _mapper;
  33. private readonly ILogger<XingTangCallsSyncJob> _logger;
  34. private readonly ISqlSugarClient _db;
  35. private readonly ISystemSettingCacheManager _systemSettingCacheManager;
  36. public XingTangCallsSyncJob(
  37. ISugarUnitOfWork<XingTangDbContext> uow,
  38. IRepository<CallNative> callRepository,
  39. IRepository<User> userRepository,
  40. ICallApplication callApplication,
  41. ICapPublisher capPublisher,
  42. IMapper mapper,
  43. ILogger<XingTangCallsSyncJob> logger,
  44. ISystemSettingCacheManager systemSettingCacheManager)
  45. {
  46. _callRepository = callRepository;
  47. _userRepository = userRepository;
  48. _callApplication = callApplication;
  49. _capPublisher = capPublisher;
  50. _mapper = mapper;
  51. _logger = logger;
  52. _db = uow.Db;
  53. _systemSettingCacheManager = systemSettingCacheManager;
  54. }
  55. public async Task Execute(IJobExecutionContext context)
  56. {
  57. var xingtangCalls = await _db.Queryable<XingtangCall>()
  58. .Where(d => !string.IsNullOrEmpty(d.CallGuid) &&
  59. !string.IsNullOrEmpty(d.Caller) &&
  60. (d.IsSync == null || !d.IsSync) &&
  61. (d.Tries == null || d.Tries <= 50))
  62. .OrderBy(d => d.Id)
  63. .Take(10)
  64. .ToListAsync(context.CancellationToken);
  65. if (!xingtangCalls.Any()) return;
  66. var occupyCalls = new List<XingtangCall>();
  67. foreach (var call in xingtangCalls)
  68. {
  69. call.IsSync = true;
  70. call.Tries += 1;
  71. var rows = await _db.Updateable(call)
  72. .ExecuteCommandWithOptLockAsync();
  73. if (rows > 0)
  74. occupyCalls.Add(call);
  75. }
  76. if (!occupyCalls.Any()) return;
  77. try
  78. {
  79. if (occupyCalls.Any(m => m.CustomerId.IsNullOrEmpty() == true))
  80. {
  81. var calls = _mapper.Map<List<CallNative>>(occupyCalls);
  82. //填充user信息
  83. var staffNos = calls.Select(d => d.StaffNo).ToList();
  84. var users = await _userRepository.Queryable()
  85. .Where(d => staffNos.Contains(d.StaffNo) && d.StaffNo != "0")
  86. .ToListAsync(context.CancellationToken);
  87. foreach (var call in calls)
  88. {
  89. call.Id = await GetCallIdAsync(call.CallNo, context.CancellationToken);
  90. var user = users.FirstOrDefault(d => d.StaffNo == call.StaffNo && d.StaffNo != "0");
  91. if (user is not null)
  92. {
  93. call.UserId = user.Id;
  94. call.UserName = user.Name;
  95. }
  96. if (call.RingDuration == 0)
  97. {
  98. if (call.BeginRingTime != null)
  99. {
  100. if (call.EndRingTime != null)
  101. {
  102. call.RingDuration = call.EndRingTime.Value.GetDifferenceSeconds(call.BeginRingTime.Value);
  103. }
  104. else
  105. {
  106. call.RingDuration = call.EndTime.GetDifferenceSeconds(call.BeginRingTime.Value);
  107. }
  108. }
  109. }
  110. if (call.GroupId == "0" && call.CallState != ECallState.IVRNoAccept)
  111. {
  112. call.CallState = ECallState.Invalid;
  113. }
  114. }
  115. await _callRepository.AddRangeAsync(calls, context.CancellationToken);
  116. // 开关
  117. var unPushTime = _systemSettingCacheManager.CallSyncUnPushDateTime;
  118. calls = calls.Where(m => m.BeginIvrTime >= unPushTime).ToList();
  119. if (calls.Any())
  120. {
  121. //推省上
  122. //await _capPublisher.PublishAsync(EventNames.HotlineCallAdd, calls.Adapt<List<CallNativeDto>>());
  123. await PublishMessageAsync(calls);
  124. }
  125. _logger.LogInformation($"旧方法同步通话记录成功,数量:{calls.Count}");
  126. }
  127. else
  128. {
  129. var calls = new List<CallNative>();
  130. foreach (var occupyCall in occupyCalls)
  131. {
  132. var call = occupyCall.Adapt<CallNative>();
  133. call.Id = await GetCallIdAsync(call.CallNo, context.CancellationToken);
  134. var userSplit = occupyCall.CustomerId.Split(':');
  135. call.UserId = userSplit[0];
  136. call.UserName = userSplit[1];
  137. if (call.RingDuration == 0)
  138. {
  139. if (call.BeginRingTime != null)
  140. {
  141. if (call.EndRingTime != null)
  142. {
  143. call.RingDuration = call.EndRingTime.Value.GetDifferenceSeconds(call.BeginRingTime.Value);
  144. }
  145. else
  146. {
  147. call.RingDuration = call.EndTime.GetDifferenceSeconds(call.BeginRingTime.Value);
  148. }
  149. }
  150. }
  151. if (call.GroupId == "0" && call.CallState != ECallState.IVRNoAccept)
  152. {
  153. call.CallState = ECallState.Invalid;
  154. }
  155. calls.Add(call);
  156. }
  157. await _callRepository.AddRangeAsync(calls, context.CancellationToken);
  158. // 开关
  159. var unPushTime = _systemSettingCacheManager.CallSyncUnPushDateTime;
  160. calls = calls.Where(m => m.BeginIvrTime >= unPushTime).ToList();
  161. if (calls.Any())
  162. {
  163. //推省上
  164. await PublishMessageAsync(calls);
  165. // await _capPublisher.PublishAsync(EventNames.HotlineCallAdd, calls.Adapt<List<CallNativeDto>>());
  166. }
  167. _logger.LogInformation($"新方法同步通话记录成功,数量:{calls.Count}");
  168. }
  169. }
  170. catch (Exception e)
  171. {
  172. _logger.LogError($"获取通话记录异常:{e.Message} \n {e.StackTrace}");
  173. foreach (var occupyCall in occupyCalls)
  174. {
  175. occupyCall.IsSync = false;
  176. }
  177. await _db.Updateable(occupyCalls)
  178. .UpdateColumns(d => new { d.IsSync })
  179. .ExecuteCommandAsync(context.CancellationToken);
  180. }
  181. }
  182. private async Task PublishMessageAsync(List<CallNative> calls)
  183. {
  184. if (_systemSettingCacheManager.IsNoPushCallNativeOutNoFile)
  185. {
  186. var removeCalls = calls.Where(m => m.Direction == ECallDirection.Out && m.AudioFile.IsNullOrEmpty()).ToList();
  187. calls = calls.Except(removeCalls).ToList();
  188. }
  189. //推省上
  190. await _capPublisher.PublishAsync(EventNames.HotlineCallAdd, calls.Adapt<List<CallNativeDto>>());
  191. }
  192. private async Task<string> GetCallIdAsync(string callNo, CancellationToken cancellation)
  193. {
  194. if (string.IsNullOrEmpty(callNo)) return string.Empty;
  195. var relation = await _callApplication.GetRelationAsync(callNo, cancellation);
  196. if (relation is null)
  197. {
  198. relation = new CallidRelation
  199. {
  200. Id = callNo,
  201. CallId = Ulid.NewUlid().ToString(),
  202. IsUsed = true
  203. };
  204. await _callApplication.AddRelationAsync(relation, cancellation);
  205. return relation.CallId;
  206. }
  207. if (relation.IsUsed)
  208. return Ulid.NewUlid().ToString();
  209. relation.IsUsed = true;
  210. var rows = await _callApplication.UpdateRelationOptLockAsync(relation, cancellation);
  211. if (rows > 0)
  212. return relation.CallId;
  213. //重新取relation 重新判断isUsed
  214. return await GetCallIdAsync(callNo, cancellation);
  215. }
  216. /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
  217. public void Dispose()
  218. {
  219. //_logger.LogInformation($"{nameof(XingTangCallsSyncJob)} disposed");
  220. }
  221. }
  222. }