|
@@ -1,6 +1,8 @@
|
|
-using CallCenter.Calls;
|
|
|
|
|
|
+using CallCenter.Caches;
|
|
|
|
+using CallCenter.Calls;
|
|
using CallCenter.NewRock.Handlers;
|
|
using CallCenter.NewRock.Handlers;
|
|
using CallCenter.Notifications;
|
|
using CallCenter.Notifications;
|
|
|
|
+using CallCenter.Realtimes;
|
|
using CallCenter.Share.Dtos;
|
|
using CallCenter.Share.Dtos;
|
|
using CallCenter.Share.Enums;
|
|
using CallCenter.Share.Enums;
|
|
using MediatR;
|
|
using MediatR;
|
|
@@ -22,8 +24,10 @@ namespace CallCenter.Application.Handlers
|
|
private readonly IOptionsSnapshot<SendCallRecord> _sendCallRecordOptions;
|
|
private readonly IOptionsSnapshot<SendCallRecord> _sendCallRecordOptions;
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
private readonly ILogger<CdrNotificationHandler> _logger;
|
|
private readonly ILogger<CdrNotificationHandler> _logger;
|
|
|
|
+ private readonly IRealtimeService _realtimeService;
|
|
|
|
+ private readonly IUserCacheManager _userCacheManager;
|
|
|
|
|
|
- public CdrNotificationHandler(ICallRecordRepository callRecordRepository, ICallDetailRepository callDetailRepository, ICallRepository callRepository, IOptionsSnapshot<SendCallRecord> sendCallRecordOptions, IHttpClientFactory httpClientFactory,ILogger<CdrNotificationHandler> logger)
|
|
|
|
|
|
+ public CdrNotificationHandler(ICallRecordRepository callRecordRepository, ICallDetailRepository callDetailRepository, ICallRepository callRepository, IOptionsSnapshot<SendCallRecord> sendCallRecordOptions, IHttpClientFactory httpClientFactory,ILogger<CdrNotificationHandler> logger,IRealtimeService realtimeService,IUserCacheManager userCacheManager)
|
|
{
|
|
{
|
|
_callRecordRepository = callRecordRepository;
|
|
_callRecordRepository = callRecordRepository;
|
|
_callDetailRepository = callDetailRepository;
|
|
_callDetailRepository = callDetailRepository;
|
|
@@ -31,128 +35,152 @@ namespace CallCenter.Application.Handlers
|
|
_sendCallRecordOptions = sendCallRecordOptions;
|
|
_sendCallRecordOptions = sendCallRecordOptions;
|
|
_httpClientFactory = httpClientFactory;
|
|
_httpClientFactory = httpClientFactory;
|
|
_logger = logger;
|
|
_logger = logger;
|
|
|
|
+ _realtimeService = realtimeService;
|
|
|
|
+ _userCacheManager = userCacheManager;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task Handle(CdrNotification notification, CancellationToken cancellationToken)
|
|
public async Task Handle(CdrNotification notification, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
- var callDetail = await
|
|
|
|
- _callDetailRepository.GetAsync(x => x.OMCallId == notification.CallId,true,x=>x.CreationTime, cancellationToken);
|
|
|
|
-
|
|
|
|
- if (callDetail!=null)
|
|
|
|
- {
|
|
|
|
- var model = new CallRecord()
|
|
|
|
- {
|
|
|
|
- CallId = callDetail.CallId,
|
|
|
|
- CdrId = notification.Id,
|
|
|
|
- CDRCallId = notification.CallId,
|
|
|
|
- TimeStart = notification.TimeStart,
|
|
|
|
- Group = notification.Group,
|
|
|
|
- Type = (ECDRType)Enum.Parse(typeof(ECDRType), notification.Type),
|
|
|
|
- Route = (ECDRRoute)Enum.Parse(typeof(ECDRRoute), notification.Route),
|
|
|
|
- CPN = notification.CPN,
|
|
|
|
- CDPN = notification.CDPN,
|
|
|
|
- TimeEnd = notification.TimeEnd,
|
|
|
|
- Duration = notification.Duration,
|
|
|
|
- TrunkNumber = notification.TrunkNumber,
|
|
|
|
- Recording = notification.Recording,
|
|
|
|
- RecCodec = notification.RecCodec,
|
|
|
|
- IsDown = false
|
|
|
|
- };
|
|
|
|
- if (!string.IsNullOrEmpty(notification.VisitorId))
|
|
|
|
- model.VisitorId = notification.VisitorId;
|
|
|
|
|
|
|
|
- if (!string.IsNullOrEmpty(notification.OuterId))
|
|
|
|
- model.OuterId = notification.OuterId;
|
|
|
|
-
|
|
|
|
- await _callRecordRepository.AddAsync(model,cancellationToken);
|
|
|
|
- var callModel = await _callRepository.GetAsync(x => x.Id == callDetail.CallId, cancellationToken);
|
|
|
|
-
|
|
|
|
- bool ishave = false;
|
|
|
|
- if (callModel.CallType == ECallType.ExtToOuter)
|
|
|
|
|
|
+ if (notification.Type == "LO")
|
|
|
|
+ {
|
|
|
|
+ //通知前端主叫
|
|
|
|
+ //获取主叫工作信息
|
|
|
|
+ var fromWork = _userCacheManager.GetWorkByTel(notification.CPN);
|
|
|
|
+ if (fromWork != null)
|
|
{
|
|
{
|
|
- ishave = true;
|
|
|
|
|
|
+ await _realtimeService.ByeAsync(fromWork.UserId, new ByeDto() { Id = notification.CPN }, cancellationToken);
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+ //通知前端被叫
|
|
|
|
+ var toWork = _userCacheManager.GetWorkByTel(notification.CDPN);
|
|
|
|
+ if (toWork != null)
|
|
{
|
|
{
|
|
- ishave = await _callDetailRepository.AnyAsync(x => (x.EventName == "RING" || x.EventName == "INCOMING") && x.OMCallId == notification.CallId && x.FromNo == notification.CPN && x.ToNo == notification.CDPN);
|
|
|
|
|
|
+ await _realtimeService.ByeAsync(toWork.UserId, new ByeDto() { Id = notification.CDPN }, cancellationToken);
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (ishave)
|
|
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ var callDetail = await
|
|
|
|
+ _callDetailRepository.GetAsync(x => x.OMCallId == notification.CallId, true, x => x.CreationTime, cancellationToken);
|
|
|
|
+
|
|
|
|
+ if (callDetail != null)
|
|
{
|
|
{
|
|
- if (callModel != null)
|
|
|
|
|
|
+ var model = new CallRecord()
|
|
{
|
|
{
|
|
- callModel.Duration = double.Parse(model.Duration);
|
|
|
|
- await _callRepository.UpdateAsync(callModel, cancellationToken);
|
|
|
|
|
|
+ CallId = callDetail.CallId,
|
|
|
|
+ CdrId = notification.Id,
|
|
|
|
+ CDRCallId = notification.CallId,
|
|
|
|
+ TimeStart = notification.TimeStart,
|
|
|
|
+ Group = notification.Group,
|
|
|
|
+ Type = (ECDRType)Enum.Parse(typeof(ECDRType), notification.Type),
|
|
|
|
+ Route = (ECDRRoute)Enum.Parse(typeof(ECDRRoute), notification.Route),
|
|
|
|
+ CPN = notification.CPN,
|
|
|
|
+ CDPN = notification.CDPN,
|
|
|
|
+ TimeEnd = notification.TimeEnd,
|
|
|
|
+ Duration = notification.Duration,
|
|
|
|
+ TrunkNumber = notification.TrunkNumber,
|
|
|
|
+ Recording = notification.Recording,
|
|
|
|
+ RecCodec = notification.RecCodec,
|
|
|
|
+ IsDown = false
|
|
|
|
+ };
|
|
|
|
+ if (!string.IsNullOrEmpty(notification.VisitorId))
|
|
|
|
+ model.VisitorId = notification.VisitorId;
|
|
|
|
|
|
- var call = await _callRepository.GetExtAsync(callModel.Id, x => x.Includes(d => d.CallDetails));
|
|
|
|
- //TODO 推送通话报告
|
|
|
|
- OutCallDto callDto = new OutCallDto();
|
|
|
|
- callDto.CallId = callDetail.CallId;
|
|
|
|
- callDto.InfoType = EInfoType.Call;
|
|
|
|
- callDto.Direction = callModel.CallDirection;
|
|
|
|
- callDto.Cpn = callModel.FromNo ?? "";
|
|
|
|
- callDto.Cdpn = callModel.ToNo ?? "";
|
|
|
|
- if (callDto.Direction == ECallDirection.In)
|
|
|
|
- {
|
|
|
|
- callDto.Answered = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.AnswerNo ?? call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
|
|
|
|
- callDto.OnTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.CreationTime ?? call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime ?? null;
|
|
|
|
- callDto.OnState = call.CallDetails?.Any(x => x.EventName == "ANSWER" || x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- //callDto.Answered = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
|
|
|
|
- //callDto.OnTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime;
|
|
|
|
- //callDto.OnState = call.CallDetails?.Any(x => x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
|
|
|
|
- callDto.Answered = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.AnswerNo ?? call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
|
|
|
|
- callDto.OnTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.CreationTime ?? call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime ?? null;
|
|
|
|
- callDto.OnState = call.CallDetails?.Any(x => x.EventName == "ANSWER" || x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
|
|
|
|
- }
|
|
|
|
- callDto.BeginTime = call.CreationTime;
|
|
|
|
- callDto.ByeTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "BYE")?.CreationTime ?? DateTime.Now;
|
|
|
|
- callDto.TalkTime = call.Duration;
|
|
|
|
- callDto.SoundFileName = model.Recording;
|
|
|
|
- if (string.IsNullOrEmpty(callDto.SoundFileName))
|
|
|
|
- {
|
|
|
|
- callDto.SoundFileName = call.CallDetails?.FirstOrDefault(x => x.EventName == "BYE" && !string.IsNullOrEmpty(x.Recording))?.Recording;
|
|
|
|
- }
|
|
|
|
- if (string.IsNullOrEmpty(callDto.SoundFileName))
|
|
|
|
- {
|
|
|
|
- callDto.SoundFileName = (await _callRecordRepository.GetAsync(x => x.CallId == callModel.Id && !string.IsNullOrEmpty(x.Recording)))?.Recording;
|
|
|
|
- }
|
|
|
|
- callDto.EvaluateResult = call.CallDetails?.FirstOrDefault(x=>x.EventName== "EVALUATE")?.Remark;
|
|
|
|
- callDto.EndBy = call.EndBy;
|
|
|
|
- callDto.InIvrTime = call.InIvrTime;
|
|
|
|
- callDto.OutIvrTime = call.OutIvrTime;
|
|
|
|
- callDto.InGroupTime = call.InGroupTime;
|
|
|
|
- callDto.OutGroupTime = call.OutGroupTime;
|
|
|
|
- callDto.InSeaTime = call.InSeaTime;
|
|
|
|
- callDto.ConnSeaTime = call.ConnSeaTime;
|
|
|
|
|
|
+ if (!string.IsNullOrEmpty(notification.OuterId))
|
|
|
|
+ model.OuterId = notification.OuterId;
|
|
|
|
|
|
- var list = new List<OutCallDto>();
|
|
|
|
- list.Add(callDto);
|
|
|
|
|
|
+ await _callRecordRepository.AddAsync(model, cancellationToken);
|
|
|
|
+ var callModel = await _callRepository.GetAsync(x => x.Id == callDetail.CallId, cancellationToken);
|
|
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- var client = _httpClientFactory.CreateClient();
|
|
|
|
- client.DefaultRequestHeaders.ConnectionClose = true;
|
|
|
|
- var requestContent = JsonSerializer.Serialize(list);
|
|
|
|
- _logger.LogInformation(requestContent);
|
|
|
|
- var content = new StringContent(requestContent, Encoding.UTF8, "application/json");
|
|
|
|
- var responseMessage = await client.PostAsync(_sendCallRecordOptions.Value.FwUrl, content, cancellationToken);
|
|
|
|
- var respContent = responseMessage.Content;
|
|
|
|
- var respContentString = await respContent.ReadAsStringAsync(cancellationToken);
|
|
|
|
- var result = JsonSerializer.Deserialize<FwResult>(respContentString);
|
|
|
|
- _logger.LogInformation("推送报告结果:" + respContentString);
|
|
|
|
- }
|
|
|
|
- catch (Exception ex)
|
|
|
|
|
|
+ bool ishave = false;
|
|
|
|
+ if (callModel.CallType == ECallType.ExtToOuter)
|
|
|
|
+ {
|
|
|
|
+ ishave = true;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ ishave = await _callDetailRepository.AnyAsync(x => (x.EventName == "RING" || x.EventName == "INCOMING") && x.OMCallId == notification.CallId && x.FromNo == notification.CPN && x.ToNo == notification.CDPN);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ishave)
|
|
|
|
+ {
|
|
|
|
+ if (callModel != null)
|
|
{
|
|
{
|
|
- throw new UserFriendlyException(ex.Message);
|
|
|
|
|
|
+ callModel.Duration = double.Parse(model.Duration);
|
|
|
|
+ await _callRepository.UpdateAsync(callModel, cancellationToken);
|
|
|
|
+
|
|
|
|
+ var call = await _callRepository.GetExtAsync(callModel.Id, x => x.Includes(d => d.CallDetails));
|
|
|
|
+ //TODO 推送通话报告
|
|
|
|
+ OutCallDto callDto = new OutCallDto();
|
|
|
|
+ callDto.CallId = callDetail.CallId;
|
|
|
|
+ callDto.InfoType = EInfoType.Call;
|
|
|
|
+ callDto.Direction = callModel.CallDirection;
|
|
|
|
+ callDto.Cpn = callModel.FromNo ?? "";
|
|
|
|
+ callDto.Cdpn = callModel.ToNo ?? "";
|
|
|
|
+ if (callDto.Direction == ECallDirection.In)
|
|
|
|
+ {
|
|
|
|
+ callDto.Answered = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.AnswerNo ?? call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
|
|
|
|
+ callDto.OnTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.CreationTime ?? call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime ?? null;
|
|
|
|
+ callDto.OnState = call.CallDetails?.Any(x => x.EventName == "ANSWER" || x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ //callDto.Answered = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
|
|
|
|
+ //callDto.OnTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime;
|
|
|
|
+ //callDto.OnState = call.CallDetails?.Any(x => x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
|
|
|
|
+ callDto.Answered = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.AnswerNo ?? call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
|
|
|
|
+ callDto.OnTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.CreationTime ?? call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime ?? null;
|
|
|
|
+ callDto.OnState = call.CallDetails?.Any(x => x.EventName == "ANSWER" || x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
|
|
|
|
+ }
|
|
|
|
+ callDto.BeginTime = call.CreationTime;
|
|
|
|
+ callDto.ByeTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "BYE")?.CreationTime ?? DateTime.Now;
|
|
|
|
+ callDto.TalkTime = call.Duration;
|
|
|
|
+ callDto.SoundFileName = model.Recording;
|
|
|
|
+ if (string.IsNullOrEmpty(callDto.SoundFileName))
|
|
|
|
+ {
|
|
|
|
+ callDto.SoundFileName = call.CallDetails?.FirstOrDefault(x => x.EventName == "BYE" && !string.IsNullOrEmpty(x.Recording))?.Recording;
|
|
|
|
+ }
|
|
|
|
+ if (string.IsNullOrEmpty(callDto.SoundFileName))
|
|
|
|
+ {
|
|
|
|
+ callDto.SoundFileName = (await _callRecordRepository.GetAsync(x => x.CallId == callModel.Id && !string.IsNullOrEmpty(x.Recording)))?.Recording;
|
|
|
|
+ }
|
|
|
|
+ callDto.EvaluateResult = call.CallDetails?.FirstOrDefault(x => x.EventName == "EVALUATE")?.Remark;
|
|
|
|
+ callDto.EndBy = call.EndBy;
|
|
|
|
+ callDto.InIvrTime = call.InIvrTime;
|
|
|
|
+ callDto.OutIvrTime = call.OutIvrTime;
|
|
|
|
+ callDto.InGroupTime = call.InGroupTime;
|
|
|
|
+ callDto.OutGroupTime = call.OutGroupTime;
|
|
|
|
+ callDto.InSeaTime = call.InSeaTime;
|
|
|
|
+ callDto.ConnSeaTime = call.ConnSeaTime;
|
|
|
|
+
|
|
|
|
+ var list = new List<OutCallDto>();
|
|
|
|
+ list.Add(callDto);
|
|
|
|
+
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ var client = _httpClientFactory.CreateClient();
|
|
|
|
+ client.DefaultRequestHeaders.ConnectionClose = true;
|
|
|
|
+ var requestContent = JsonSerializer.Serialize(list);
|
|
|
|
+ _logger.LogInformation(requestContent);
|
|
|
|
+ var content = new StringContent(requestContent, Encoding.UTF8, "application/json");
|
|
|
|
+ var responseMessage = await client.PostAsync(_sendCallRecordOptions.Value.FwUrl, content, cancellationToken);
|
|
|
|
+ var respContent = responseMessage.Content;
|
|
|
|
+ var respContentString = await respContent.ReadAsStringAsync(cancellationToken);
|
|
|
|
+ var result = JsonSerializer.Deserialize<FwResult>(respContentString);
|
|
|
|
+ _logger.LogInformation("推送报告结果:" + respContentString);
|
|
|
|
+ }
|
|
|
|
+ catch (Exception ex)
|
|
|
|
+ {
|
|
|
|
+ throw new UserFriendlyException(ex.Message);
|
|
|
|
+ }
|
|
|
|
+ //HttpContent content = new
|
|
}
|
|
}
|
|
- //HttpContent content = new
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|