using System.Diagnostics; using System.Text; using DotNetCore.CAP; using Fake.DependencyInjection; using InterfaceForward.Domain.Shared.Helpers; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using RabbitMQ.Client.Events; using TrackCenter.Application.Dtos.TrackPull; using TrackCenter.Application.Events; using TrackCenter.Application.Helpers; using TrackCenter.Application.Services.TrackPull; using TrackCenter.Domain.Aggregates.OrderAggregate; using TrackCenter.Domain.Aggregates.TrackDetailsAggregate; using TrackCenter.Domain.Enums; namespace TrackCenter.Application.Rabbit; public class TrackRefreshEventHandler : ITransientDependency, IRabbitHandler { private readonly ICapPublisher _capPublisher; private readonly ILogger _logger; private readonly IOrderRepository _orderRepository; private readonly ITrackDetailsEsRepository _trackDetailsEsRepository; private readonly TrackPullCacheService _trackPullCacheService; public TrackRefreshEventHandler(IOrderRepository orderRepository, ICapPublisher capPublisher, TrackPullCacheService trackPullCacheService, ITrackDetailsEsRepository trackDetailsEsRepository, ILogger logger) { _orderRepository = orderRepository; _capPublisher = capPublisher; _trackPullCacheService = trackPullCacheService; _trackDetailsEsRepository = trackDetailsEsRepository; _logger = logger; } public ConsumeOptions Options() { return new ConsumeOptions() { Queue = GlobalConst.TrackRefreshSubscribe, }; } public async Task Handle(IServiceProvider sp, BasicDeliverEventArgs args, ConsumeOptions options) { var msg = Encoding.UTF8.GetString(args.Body.ToArray()); var @event = System.Text.Json.JsonSerializer.Deserialize(msg); if (@event == null) { _logger.LogWarning( $"rabbit on queue({options.Queue}) received msg can't convert to {nameof(InterfaceRelayForwardReplayEvent)}"); return; } await ConsumerAsync(@event); } public async Task ConsumerAsync(InterfaceRelayForwardReplayEvent @event) { if (!@event.IsSuccess) { _logger.LogWarning("请求id: {@RequestId},轨迹刷新失败", @event.RequestId); return; } var attach = Base64Helper.DeSerialize(@event.Attach); if (attach is null || @event.Data == null) { _logger.LogWarning("请求id: {@RequestId},轨迹消费失败,attach或data解析为空", @event.RequestId); return; } var config = await _trackPullCacheService.GetPullParamsWithContentAsync(attach.SubSystemId, attach.ServiceProviderCode); if (config == null) { _logger.LogWarning("请求id: {@RequestId},轨迹消费失败,找不到拉取配置:{@Attach}", attach.ToJson(), @event.RequestId); return; } var data = JObject.Parse(@event.Data); var orderToken = data.SelectToken(config.ParamConfig.OrderPath); if (orderToken is JArray orderTokens) { foreach (var token in orderTokens) { await HandleOrderAsync(token, config, attach); } } else if (orderToken is JObject) { await HandleOrderAsync(orderToken, config, attach); } } private async Task HandleOrderAsync(JToken orderToken, TrackPullParamsWithContentDto paramsWithContent, TrackRefreshAttach attach) { var paramConfig = paramsWithContent.ParamConfig; var orderNo = orderToken[paramConfig.OrderNoName]?.Value(); if (orderNo.IsNullOrWhiteSpace()) return; var trackToken = orderToken.SelectToken(paramConfig.TrackDetailsPath); if (trackToken is null) return; //回传单号可能是主单也可能是外部单号 //通过平台code和(外部单号/主单号)查询主单 var order = await _orderRepository.GetTrackOrderByProviderAndOrderNo(attach.ServiceProviderCode, orderNo!); if (order == default) { _logger.LogError($"请求id: {attach.ToJson()},轨迹消费失败,找不到主单,平台code:{attach.ServiceProviderCode},单号:{orderNo}"); return; } var context = new TrackRefreshContext { OrderId = order.MainOrderId, OrderNo = order.OrderNo, CustomId = order.CustomId, OrderType = attach.OrderType, SubSystemId = attach.SubSystemId, ServiceProviderCode = attach.ServiceProviderCode }; if (trackToken is JArray trackTokens) { foreach (var item in trackTokens) { await HandleTrackAsync(item, paramsWithContent, context); } } else if (trackToken is JObject) { await HandleTrackAsync(trackToken, paramsWithContent, context); } } private async Task HandleTrackAsync(JToken trackToken, TrackPullParamsWithContentDto paramsWithContent, TrackRefreshContext context) { var originTrackDataHash = StringHelper.GetHash(JsonConvert.SerializeObject(trackToken)); // 如果已经存在一模一样的报文了说明处理过了,直接return if (await _trackDetailsEsRepository.AnyAsync(context.OrderId, originTrackDataHash)) { return; } var paramConfig = paramsWithContent.ParamConfig; var contentConfigs = paramsWithContent.ContentConfigs; TrackPullContentConfigDto? matchedContentConfig = null; // 轨迹内容 var trackContent = paramConfig.TrackContentName == null ? null : trackToken[paramConfig.TrackContentName]?.Value(); // 1、匹配轨迹代码 // 2、匹配轨迹状态 if (matchedContentConfig == null && !paramConfig.TrackStatusName.IsNullOrWhiteSpace()) { var trackStatus = trackToken[paramConfig.TrackStatusName!]?.Value(); if (!trackStatus.IsNullOrWhiteSpace()) { matchedContentConfig = contentConfigs.FirstOrDefault(x => x.TrackStatusValues.Contains(trackStatus!)); } } // 3、匹配轨迹内容 if (matchedContentConfig == null && !paramConfig.TrackContentName.IsNullOrWhiteSpace()) { if (!trackContent.IsNullOrWhiteSpace()) { Debug.Assert(trackContent != null, nameof(trackContent) + " != null"); // 3.1 按内容直接匹配 // 3.2 按关键字分析轨迹内容 foreach (var contentConfig in contentConfigs) { foreach (var keyword in contentConfig.TrackKeywords) { if (trackContent.Contains(keyword, StringComparison.OrdinalIgnoreCase)) { matchedContentConfig = contentConfig; break; } } if (matchedContentConfig is null) continue; foreach (var keyword in contentConfig.TrackKeywordReverses) { if (trackContent.Contains(keyword, StringComparison.OrdinalIgnoreCase)) { matchedContentConfig = null; break; } } if (matchedContentConfig is not null) break; // 找到匹配的,跳出循环 } } } // 轨迹发生ISO时间 var trackIsoTime = paramConfig.TrackIsoTimeName == null ? null : trackToken[paramConfig.TrackIsoTimeName]?.ToObject(); // 轨迹发生时间 var trackTime = trackIsoTime?.DateTime ?? (paramConfig.TrackTimeName == null ? null : trackToken[paramConfig.TrackTimeName]?.ToObject()); // 轨迹发生时区 var trackTimeZone = (float?) trackIsoTime?.Offset.TotalHours ?? (paramConfig.TrackTimeZoneName == null ? null : trackToken[paramConfig.TrackTimeZoneName]?.ToObject()); // 轨迹发生地 var trackPlace = paramConfig.TrackPlaceName == null ? null : trackToken[paramConfig.TrackPlaceName]?.ToObject(); if (matchedContentConfig is null) { _logger.LogDebug("订单号:{OrderNo},未匹配到轨迹内容,轨迹报文:{TrackContent}", context.OrderNo, trackToken.ToString()); await InsertNotMappedTrackAsync(trackToken, context, trackPlace, trackTime, trackTimeZone, trackContent); return; } // 新增/更新轨迹 var trackUpsertEvent = new TrackUpsertEvent { OrderIdentifiers = new[] { new OrderIdentifier { OrderId = context.OrderId, OrderNo = context.OrderNo, OrderType = context.OrderType, } }, TrackRefreshData = new TrackRefreshStruct { ServiceProviderCode = context.ServiceProviderCode, OriginTrackDataHash = originTrackDataHash, OriginTrackContent = trackContent ?? GlobalConst.EmptyString, }, SubSystemId = context.SubSystemId, CustomId = context.CustomId, TrackCode = matchedContentConfig.TrackContentCode, TrackPlace = trackPlace ?? GlobalConst.EmptyString, TrackTime = trackTime ?? DateTime.Now, TrackTimeZone = trackTimeZone ?? GlobalConst.NoneTrackTimeZone, IsAdd = true, //服务商轨迹默认不对外 IsExternal = false, Source = (int) TrackSourceEnum.ExternalServiceProvide, Remarks = null, Files = null, Content = null, EnStatus = null, TrackPlaceCity = null, TrackPlaceCityId = null, TrackPlaceProvince = null, TrackPlaceProvinceId = null, TrackPlaceNation = null, TrackPlaceNationId = null, TrackPlacePostcode = null, DestinationTimeZone = null, EstimatedDeliveryDate = null, }; await _capPublisher.PublishAsync(GlobalConst.TrackUpsertForRefreshSubscribe, trackUpsertEvent); } private async Task InsertNotMappedTrackAsync(JToken trackToken, TrackRefreshContext context, string? trackPlace, DateTime? trackTime, float? trackTimeZone, string? trackContent) { // 新增服务商轨迹到es var track = new TrackDetailsIndex { IndexName = $"{GlobalConst.TrackDetailsIndex}-{DateTime.Now:yyyy.MM}", SubSystemId = context.SubSystemId, OrderId = context.OrderId, OrderType = context.OrderType, OrderNo = context.OrderNo, TrackPlace = trackPlace ?? GlobalConst.EmptyString, TrackTime = trackTime ?? DateTime.Now, TrackTimeZone = trackTimeZone ?? GlobalConst.NoneTrackTimeZone, ServiceProviderCode = context.ServiceProviderCode, OriginTrackDataHash = StringHelper.GetHash(JsonConvert.SerializeObject(trackToken)), OriginTrackContent = trackContent ?? GlobalConst.EmptyString, CreateUser = GlobalConst.SystemUser, CreateTime = DateTime.Now, //来源轨迹内容,第一次新增的时候使用轨迹内容表提供的 TrackStatusId = GlobalConst.NotExistId, TrackStatus = GlobalConst.EmptyString, TrackStatusCode = GlobalConst.EmptyString, TrackContentId = GlobalConst.NotExistId, TrackContent = GlobalConst.EmptyString, TrackEnContent = GlobalConst.EmptyString, //服务商轨迹默认不对外 IsExternal = false, Source = (int) TrackSourceEnum.ExternalServiceProvide, Remarks = null, Files = null, TrackPlaceCity = null, TrackPlaceCityId = null, TrackPlaceProvince = null, TrackPlaceProvinceId = null, TrackPlaceNation = null, TrackPlaceNationId = null, TrackPlacePostcode = null, DestinationTimeZone = null, EstimatedDeliveryDate = null, Extra = null }; track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1 ? track.TrackTime : track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); await _trackDetailsEsRepository.AddAsync(track); } }