diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs index 1b5dab76..d695a433 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackPushEventHandler.cs @@ -95,7 +95,6 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe private async Task DoPushAsync(TrackPushEvent @event) { - // todo: 轨迹中台推送逻辑致使的未推送,也需要广播到mq,告知业务系统缘故 var items = new List(); TrackPushContentConfigDto? config; var isSystemPush = @event.OperationMan == null; @@ -357,14 +356,22 @@ public class TrackPushEventHandler : ITransientDependency, ICapSubscribe body = DeserializeForTextJson(history.PushContent); if (config.IsAllPushWithLatest) { + //同code同比较字段保证唯一 var old = body!.Data - .Where(x => x["code"] == cur["code"]) - .WhereIf(!compareFields.IsNullOrWhiteSpace(), x => + .Where(x => + { + //反序列化出的JsonElement和字典字符串类型做比较 + var a = ((JsonElement) x["code"]!).GetString(); + var b = cur["code"]!.ToString(); //tips: 需要要将object类型的字符串转为string类型,否则使用的是引用比较,反序列化出的string一定和本地string引用不同 + return a == b; + }).WhereIf(!compareFields.IsNullOrWhiteSpace(), x => { if (x["extra"] == null || log.Extra == null) return false; - return EqExtraByFieldForTextJson(x["extra"]!, DeserializeForTextJson(log.Extra)!, compareFields!); + return EqExtraByFieldForTextJson(x["extra"]!, DeserializeForTextJson(log.Extra), compareFields!); }) .FirstOrDefault(); + + if (old != null) { body.Data.Remove(old); diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs index 3bf950a9..dc8a327f 100644 --- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs +++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs @@ -176,6 +176,14 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe // 批量add to es await _trackDetailsEsRepository.AddManyAsync(insertTracks); + //批量写入订单操作日志 + _ = _orderOperationRecordEsRepository + .AddManyAsync(insertTracks.Select(t => BuildOrderOperationRecord(@event, t, new OrderIdentifier + { + OrderNo = t.OrderNo, + OrderId = t.OrderId + })).ToList()); + // 添加轨迹触发订单拉取状态更新 await _orderRepository.UpdatePullStatusToSilenceAsync(insertTracks.Select(x => x.OrderId).ToList(), @event.TrackCode); @@ -243,7 +251,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe var insertTracks = new List(); var updateTracks = new List(); - + var operationRecords = new List(); foreach (var order in @event.OrderIdentifiers) { // fast path: by update with es id case @@ -277,7 +285,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe { var oldExtraDict = GetExtraDictForTextJson(x.Extra); // tips:注意兼容性,历史轨迹的字段可能为空 - if (oldExtraDict == null|| !oldExtraDict.TryGetValue(@event.CompareFields, out var oldValue)) + if (oldExtraDict == null || !oldExtraDict.TryGetValue(@event.CompareFields, out var oldValue)) { return false; } @@ -301,6 +309,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe if (track == null) continue; // 不存在不让改 updateTracks.Add(BuiltUpdateTrack(@event, track, order, trackContent)); + operationRecords.Add(BuildOrderOperationRecord(@event, track, order)); } else { @@ -317,6 +326,8 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe { //批量差异化更新轨迹 await _trackDetailsEsRepository.BulkUpdateAsync(updateTracks); + //批量写入操作日志 + _ = _orderOperationRecordEsRepository.AddManyAsync(operationRecords); } return insertTracks; @@ -363,19 +374,6 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe track.EstimatedDeliveryDate = @event.EstimatedDeliveryDate; track.Extra = @event.Extra; - // todo:如果后面写es异常了,这里日志不就不准了,这里应该和写轨迹一样,做成批量的,放到写完轨迹只会写日志 - // 写入操作日志 - _ = _orderOperationRecordEsRepository.AddAsync(new OrderOperationRecordIndex - { - OrderId = order.OrderId, - OrderNo = order.OrderNo, - OptionType = OrderOperationType.修改轨迹.ToString(), - Content = track.ToJson(), - CreateUserId = @event.OperationManId, - CreateUserName = @event.OperationMan ?? "", - CreateTime = DateTime.Now - }); - return track; } @@ -429,19 +427,6 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe ? track.TrackTime : track.TrackTime.Subtract(TimeSpan.FromHours(track.TrackTimeZone)); - // todo:如果后面写es异常了,这里日志不就不准了,这里应该和写轨迹一样,做成批量的,放到写完轨迹只会写日志 - // 写入操作日志 - _ = _orderOperationRecordEsRepository.AddAsync(new OrderOperationRecordIndex - { - OrderId = order.OrderId, - OrderNo = order.OrderNo, - OptionType = OrderOperationType.创建轨迹.ToString(), - Content = track.ToJson(), - CreateUserId = @event.OperationManId, - CreateUserName = @event.OperationMan ?? "", - CreateTime = DateTime.Now - }); - return track; } @@ -461,4 +446,18 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe return false; } + + private OrderOperationRecordIndex BuildOrderOperationRecord(TrackUpsertEvent @event, TrackDetailsIndex track, OrderIdentifier order) + { + return new OrderOperationRecordIndex + { + OrderId = order.OrderId, + OrderNo = order.OrderNo, + OptionType = @event.IsAdd ? OrderOperationType.创建轨迹.ToString() : OrderOperationType.修改轨迹.ToString(), + Content = track.ToJson(), + CreateUserId = @event.OperationManId, + CreateUserName = @event.OperationMan ?? "", + CreateTime = DateTime.Now + }; + } } diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs index 0af5624e..4923b7d2 100644 --- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs +++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs @@ -157,7 +157,7 @@ public partial class TrackService : ApplicationService, ITrackService var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { - //todo:保留之前的方式 后续可去除 + //todo:保留之前的方式(FBA在用) 后续可能去除 userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(input.OptionUserId); if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) @@ -225,12 +225,32 @@ public partial class TrackService : ApplicationService, ITrackService var trackCodes = input.TrackIdentifiers?.Select(x => x.TrackCode).ToList(); var trackIds = input.TrackIdentifiers?.Select(y => $"{y.TrackCode}{y.TrackTime}").ToHashSet(); //没有任何需要操作的轨迹 - if (trackIds == null || trackIds.Count == 0) goto NO_DELETE_TRACK; + if (trackIds == null || trackIds.Count == 0) + { + throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数"); + } + //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 tracks = await _trackDetailsEsRepository.GetListAsync(new[] { orderId }, trackCodes); //检查删除的轨迹中是否包含外部轨迹 existsExternal = tracks .Where(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide) + .WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y => + { + if (string.IsNullOrWhiteSpace(y.Extra)) + { + throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹"); + } + + var extraDict = System.Text.Json.JsonSerializer.Deserialize>(y.Extra); + if (extraDict!.TryGetValue(input.CompareFields!, out var compareValue)) + { + //tips:可能会有问题 + return compareValue.Equals(input.CompareValue); + } + + return false; + }) .Select(x => $"{x.TrackCode}{x.TrackTime}") .Any(x => trackIds.Contains(x)); } @@ -240,24 +260,23 @@ public partial class TrackService : ApplicationService, ITrackService throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); } - - // todo:非必须不用goto,除非是在写算法,业务逻辑理论上都能通过if和方法规避 - NO_DELETE_TRACK: if (tracks.Count == 0) { throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数"); } // 删除轨迹 - var @event = new TrackDeleteEvent - { - EsIds = input.EsIds?.ToArray(), - OrderIds = new[] { orderId }, - TrackIdentifiers = input.TrackIdentifiers, - SubSystemId = input.SubSystemId, - OperationMan = name - }; - await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); + await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, + new TrackDeleteEvent + { + EsIds = input.EsIds?.ToArray(), + OrderIds = new[] { orderId }, + CompareFields = input.CompareFields, + CompareValue = input.CompareValue, + TrackIdentifiers = input.TrackIdentifiers, + SubSystemId = input.SubSystemId, + OperationMan = name + }); return new UnifyResultDto(true, true); } @@ -351,6 +370,8 @@ public partial class TrackService : ApplicationService, ITrackService { OrderIds = orderIds.ToArray(), TrackIdentifiers = input.TrackIdentifiers, + CompareFields = input.CompareFields, + CompareValue = input.CompareValue, SubSystemId = input.SubSystemId, OperationMan = userInfo.Data.UserName, }; @@ -360,7 +381,6 @@ public partial class TrackService : ApplicationService, ITrackService } - // todo:代码封装性太差了,拆小一点 /// /// 批量新增、更新轨迹 diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderOperationRecordEsRepository.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderOperationRecordEsRepository.cs index 9f3af683..eb97ddae 100644 --- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderOperationRecordEsRepository.cs +++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/IOrderOperationRecordEsRepository.cs @@ -9,6 +9,13 @@ public interface IOrderOperationRecordEsRepository /// Task AddAsync(OrderOperationRecordIndex index); + /// + /// 添加订单操作记录(批量) + /// + /// + /// + Task AddManyAsync(List indexes); + /// /// 获取订单操作记录 /// diff --git a/src/SJZY.Track.Repository/Repositories/OrderOperationRecordEsRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderOperationRecordEsRepository.cs index 99d71604..0c30c860 100644 --- a/src/SJZY.Track.Repository/Repositories/OrderOperationRecordEsRepository.cs +++ b/src/SJZY.Track.Repository/Repositories/OrderOperationRecordEsRepository.cs @@ -29,6 +29,24 @@ public class OrderOperationRecordEsRepository : ElasticSearchContextAbstract indexes) + { + // 按天写入es + var indexName = $"{GlobalConst.OrderOperationRecordIndex}-{DateTime.Now:yyyy.MM.dd}"; + indexes.ForEach(x => + { + x.IndexName = indexName; + x.CreateTime = DateTime.Now; + }); + + var r = await Context.IndexManyAsync(indexes, indexName); + + if (!r.IsValid) + { + throw new InvalidOperationException($"{indexes.Count}条订单变更记录写入失败,原因:{r.DebugInformation}。"); + } + } + public async Task> GetOrderOperationsByIdAsync(int orderId) { var data = await Context.SearchAsync(x => x