fix: 修复删除轨迹失败

This commit is contained in:
云龙 王 2024-11-25 18:16:42 +08:00
parent c98e1e7d8a
commit ea77583ce4
11 changed files with 168 additions and 32 deletions

View File

@ -5,9 +5,9 @@ namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
public class BatchDeleteTrackInput : OrderNosInfo public class BatchDeleteTrackInput : OrderNosInfo
{ {
/// <summary> /// <summary>
/// 轨迹code,必填 /// 轨迹标识符集合,必填
/// </summary> /// </summary>
[Required] [Required]
[MaxLength(500)] [MaxLength(500)]
public List<string> TrackCodes { get; set; } = new(); public List<TrackIdentifierDto> TrackIdentifiers { get; set; } = new();
} }

View File

@ -9,8 +9,8 @@ public class DeleteOrderInput : OrderNoInfo
public class DeleteTrackInput : OrderNoInfo public class DeleteTrackInput : OrderNoInfo
{ {
/// <summary> /// <summary>
/// 轨迹code /// 轨迹标识符集合,必填
/// </summary> /// </summary>
[Required] [Required]
public List<string> TrackCodes { get; set; } = new(); public List<TrackIdentifierDto> TrackIdentifiers { get; set; } = new();
} }

View File

@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
/// <summary>
/// 轨迹标识符,用于唯一标识一个轨迹
/// </summary>
public sealed class TrackIdentifierDto
{
/// <summary>
/// 轨迹code
/// </summary>
[Required]
public string TrackCode { get; set; }
/// <summary>
/// 轨迹发生时间
/// </summary>
[Required]
public DateTime TrackTime { get; set; }
}

View File

@ -1,3 +1,5 @@
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
namespace SJZY.Track.Application.Contract.Events; namespace SJZY.Track.Application.Contract.Events;
public class TrackDeleteEvent public class TrackDeleteEvent
@ -18,9 +20,9 @@ public class TrackDeleteEvent
public int[] OrderIds { get; set; } = null!; public int[] OrderIds { get; set; } = null!;
/// <summary> /// <summary>
/// 轨迹代码 /// 轨迹标识符
/// </summary> /// </summary>
public List<string> TrackCodes { get; set; } = null!; public List<TrackIdentifierDto> TrackIdentifiers { get; set; } = null!;
/// <summary> /// <summary>
/// 操作人 /// 操作人
@ -40,6 +42,6 @@ public class TrackDeleteEvent
public override string ToString() public override string ToString()
{ {
return $"[TrackDelete by {OperationMan}] SubSystemId: {SubSystemId}, OrderIds: {string.Join(",", return $"[TrackDelete by {OperationMan}] SubSystemId: {SubSystemId}, OrderIds: {string.Join(",",
OrderIds)}, TrackCodes: {string.Join(",", TrackCodes)}"; OrderIds)}, TrackCodes: {string.Join(",", TrackIdentifiers.Select(x=>x.TrackCode))}";
} }
} }

View File

@ -3,6 +3,7 @@ using BSI.Stack.Rabbit;
using DotNetCore.CAP; using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.Logger; using SJZY.Expand.ABP.Core.Logger;
using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
@ -67,22 +68,29 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
{ {
var nextEvent = @event.DeepCopy(); var nextEvent = @event.DeepCopy();
nextEvent.Visited.AddRange(@event.OrderIds); nextEvent.Visited.AddRange(@event.OrderIds);
nextEvent.TrackCodes = @event.TrackCodes; nextEvent.TrackIdentifiers = @event.TrackIdentifiers;
nextEvent.SubSystemId = group.Key; nextEvent.SubSystemId = group.Key;
// 不同子系统需要做内容映射 // 不同子系统需要做内容映射
if (@event.SubSystemId != nextEvent.SubSystemId) if (@event.SubSystemId != nextEvent.SubSystemId)
{ {
var mapCodes = await _provideQueries var codeMaps = await _provideQueries
.MapTrackCodesAsync(@event.SubSystemId, nextEvent.SubSystemId, @event.TrackCodes.ToArray()); .GetTrackCodeMapsAsync(@event.SubSystemId, nextEvent.SubSystemId,
@event.TrackIdentifiers.Select(x => x.TrackCode).ToArray());
if (mapCodes.Count == 0) if (codeMaps.Count == 0)
{ {
LogHelper.Warn($"订单跨子系统,未配置内容映射,请联系管理员:{@event}", true); LogHelper.Warn($"订单跨子系统,未配置内容映射,请联系管理员:{@event}", true);
continue; continue;
} }
nextEvent.TrackCodes = mapCodes; //映射轨迹code
foreach (var trackIdentity in nextEvent.TrackIdentifiers)
{
var match = codeMaps.FirstOrDefault(x => x.MapTrackContentCode == trackIdentity.TrackCode);
if (match == null) continue;
trackIdentity.TrackCode = match.TrackContentCode;
}
} }
var identifiers = group.Select(x => x.OrderId).ToList(); var identifiers = group.Select(x => x.OrderId).ToList();
@ -172,7 +180,11 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
tracks = await _trackDetailsEsRepository.GetDataByIds(@event.EsIds); tracks = await _trackDetailsEsRepository.GetDataByIds(@event.EsIds);
orderIds = tracks.Select(m => m.OrderId).Distinct().ToList(); orderIds = tracks.Select(m => m.OrderId).Distinct().ToList();
@event.OrderIds = orderIds.ToArray(); @event.OrderIds = orderIds.ToArray();
@event.TrackCodes = tracks.Select(x => x.TrackCode).Distinct().ToList(); @event.TrackIdentifiers = tracks.Select(x => new TrackIdentifierDto
{
TrackCode = x.TrackCode,
TrackTime = x.TrackTime
}).ToList();
// 外部api获取的轨迹不允许删除 // 外部api获取的轨迹不允许删除
if (tracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode())) if (tracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode()))
@ -189,11 +201,24 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
} }
else //原有逻辑,根据轨迹code和订单进行删除 else //原有逻辑,根据轨迹code和订单进行删除
{ {
var trackCodes = @event.TrackIdentifiers.Select(x => x.TrackCode).ToList();
// 删除轨迹(删的是同子系统下的单,所以code是统一的) // 删除轨迹(删的是同子系统下的单,所以code是统一的)
tracks = await _trackDetailsEsRepository.GetLatestListAsync(@event.OrderIds, @event.TrackCodes); tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds, trackCodes,null);
orderIds = await _trackDetailsEsRepository.DeleteTrackAsync(@event.OrderIds, @event.TrackCodes); //构建标识符集合
if (orderIds.Count == 0) return tracks; var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime}").ToList();
//根据标识符选出要删除的轨迹明细
var deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime}")).ToList();
if (deleteTracks.Count == 0) return deleteTracks;
foreach (var track in deleteTracks)
{
await _trackDetailsEsRepository.DeleteTrackByIdAsync(track.Id, track.IndexName);
}
orderIds = tracks.Select(m => m.OrderId).Distinct().ToList();
tracks = deleteTracks;
} }

View File

@ -163,8 +163,14 @@ public partial class TrackService : ApplicationService, ITrackService
//删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误
var tracks = await _trackDetailsEsRepository var tracks = await _trackDetailsEsRepository
.GetListAsync(new[] { orderId }, input.TrackCodes, TrackSourceEnum.ExternalServiceProvide); .GetListAsync(new[] { orderId },
if (tracks.Count > 0) input.TrackIdentifiers.Select(x => x.TrackCode).ToList(),
TrackSourceEnum.ExternalServiceProvide);
//当要删除的轨迹标识出现交叉则不允许删除
var intersect = tracks.Select(x => $"{x.TrackCode}{x.TrackTime}")
.Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList();
if (intersect.Count > 0)
{ {
throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除");
} }
@ -173,7 +179,7 @@ public partial class TrackService : ApplicationService, ITrackService
var @event = new TrackDeleteEvent var @event = new TrackDeleteEvent
{ {
OrderIds = new[] { orderId }, OrderIds = new[] { orderId },
TrackCodes = input.TrackCodes, TrackIdentifiers = input.TrackIdentifiers,
SubSystemId = input.SubSystemId, SubSystemId = input.SubSystemId,
OperationMan = name OperationMan = name
}; };
@ -254,8 +260,14 @@ public partial class TrackService : ApplicationService, ITrackService
//删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误
var tracks = await _trackDetailsEsRepository var tracks = await _trackDetailsEsRepository
.GetListAsync(orderIds.ToArray(), input.TrackCodes, TrackSourceEnum.ExternalServiceProvide); .GetListAsync(orderIds.ToArray(),
if (tracks.Count > 0) input.TrackIdentifiers.Select(x => x.TrackCode).ToList(),
TrackSourceEnum.ExternalServiceProvide);
//当要删除的轨迹标识出现交叉则不允许删除
var intersect = tracks.Select(x => $"{x.TrackCode}{x.TrackTime}")
.Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList();
if (intersect.Count > 0)
{ {
throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除");
} }
@ -264,7 +276,7 @@ public partial class TrackService : ApplicationService, ITrackService
var @event = new TrackDeleteEvent var @event = new TrackDeleteEvent
{ {
OrderIds = orderIds.ToArray(), OrderIds = orderIds.ToArray(),
TrackCodes = input.TrackCodes, TrackIdentifiers = input.TrackIdentifiers,
SubSystemId = input.SubSystemId, SubSystemId = input.SubSystemId,
OperationMan = userInfo.Data.UserName, OperationMan = userInfo.Data.UserName,
}; };

View File

@ -1,4 +1,5 @@
using SJZY.Expand.ElasticSearch.Services; using SJZY.Expand.ElasticSearch.Services;
using SJZY.Track.Domain.Dtos.TrackContents;
using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Enums;
namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
@ -23,7 +24,7 @@ public interface ITrackDetailsEsRepository : IElasticsearchClientService<TrackDe
Task<List<TrackDetailsIndex>> GetListAsync(int orderId); Task<List<TrackDetailsIndex>> GetListAsync(int orderId);
Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, List<string> trackCodes, TrackSourceEnum source); Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, List<string> trackCodes, TrackSourceEnum? source);
Task<List<int>> DeleteTrackAsync(int[] orderIds, List<string> trackCodes); Task<List<int>> DeleteTrackAsync(int[] orderIds, List<string> trackCodes);

View File

@ -0,0 +1,27 @@
namespace SJZY.Track.Domain.Dtos.TrackContents;
/// <summary>
/// 轨迹代码映射
/// </summary>
public sealed class TrackCodeMapVO
{
/// <summary>
/// 源子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 源轨迹内容code
/// </summary>
public string TrackContentCode { get; set; } = null!;
/// <summary>
/// 映射子系统id
/// </summary>
public int MapSubSystemId { get; set; }
/// <summary>
/// 映射轨迹内容code
/// </summary>
public string MapTrackContentCode { get; set; } = null!;
}

View File

@ -18,6 +18,14 @@ public interface IProvideQueries
/// <returns></returns> /// <returns></returns>
Task<List<string>> MapTrackCodesAsync(int upSubSystemId, int subSystemId, params string[] trackCodes); Task<List<string>> MapTrackCodesAsync(int upSubSystemId, int subSystemId, params string[] trackCodes);
/// <summary>
/// 获取子系统内容Code映射
/// </summary>
/// <param name="upSubSystemId"></param>
/// <param name="subSystemId"></param>
/// <param name="trackCodes"></param>
/// <returns></returns>
Task<List<TrackCodeMapVO>> GetTrackCodeMapsAsync(int upSubSystemId, int subSystemId, params string[] trackCodes);
/// <summary> /// <summary>
/// 根据订单模板找对应服务商 /// 根据订单模板找对应服务商
/// </summary> /// </summary>

View File

@ -33,6 +33,22 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, ITransientDepen
.ToListAsync(); .ToListAsync();
} }
public async Task<List<TrackCodeMapVO>> GetTrackCodeMapsAsync(int upSubSystemId, int subSystemId, params string[] trackCodes)
{
// 根据上游code得到下游code
return await Context.Queryable<TrackContentMapEntity>()
.Where(x => x.SubSystemId == subSystemId && x.MapSubSystemId == upSubSystemId &&
trackCodes.Contains(x.MapTrackContentCode))
.Select(x => new TrackCodeMapVO()
{
SubSystemId = x.SubSystemId,
TrackContentCode = x.TrackContentCode,
MapSubSystemId = x.MapSubSystemId,
MapTrackContentCode = x.MapTrackContentCode
})
.ToListAsync();
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<List<OrderWithServiceProviderVO>> FindOrderWithServiceProviderAsync(int subSystemId, public async Task<List<OrderWithServiceProviderVO>> FindOrderWithServiceProviderAsync(int subSystemId,
List<string> orderNos) List<string> orderNos)
@ -46,7 +62,7 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, ITransientDepen
.Select((a, b, c) => new OrderWithServiceProviderVO .Select((a, b, c) => new OrderWithServiceProviderVO
{ {
//优先使用第三方的订单号,为空时才使用主单号 //优先使用第三方的订单号,为空时才使用主单号
OrderNo = b.OrderNo ?? a.OrderNo, OrderNo = b.OrderNo.IsNullOrWhiteSpace() ? a.OrderNo : b.OrderNo!,
OrderType = a.OrderType, OrderType = a.OrderType,
SubSystemId = a.SubSystemId, SubSystemId = a.SubSystemId,
ServiceProviderCode = b.ServiceProviderCode, ServiceProviderCode = b.ServiceProviderCode,
@ -67,7 +83,7 @@ public class ProvideQueries : ISugarRepository, IProvideQueries, ITransientDepen
.Select((a, b) => new OrderWithServiceProviderVO .Select((a, b) => new OrderWithServiceProviderVO
{ {
//优先使用第三方的订单号,为空时才使用主单号 //优先使用第三方的订单号,为空时才使用主单号
OrderNo = b.OrderNo ?? a.OrderNo, OrderNo = b.OrderNo.IsNullOrWhiteSpace() ? a.OrderNo : b.OrderNo!,
OrderType = a.OrderType, OrderType = a.OrderType,
SubSystemId = a.SubSystemId, SubSystemId = a.SubSystemId,
ServiceProviderCode = b.ServiceProviderCode ServiceProviderCode = b.ServiceProviderCode

View File

@ -3,6 +3,7 @@ using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Expand.ElasticSearch.Services; using SJZY.Expand.ElasticSearch.Services;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Consts; using SJZY.Track.Domain.Consts;
using SJZY.Track.Domain.Dtos.TrackContents;
using SJZY.Track.Domain.Enums; using SJZY.Track.Domain.Enums;
namespace SJZY.Track.Repository.Repositories; namespace SJZY.Track.Repository.Repositories;
@ -75,6 +76,8 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
.Field(f => f.TrackTimeZone) .Field(f => f.TrackTimeZone)
.Field(f => f.OrderId) .Field(f => f.OrderId)
.Field(f => f.TrackCode) .Field(f => f.TrackCode)
.Field(f => f.Id)
.Field(f => f.IndexName)
)) ))
.Query(q => q .Query(q => q
.Bool(b => b .Bool(b => b
@ -99,6 +102,17 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
.Sort(so => so .Sort(so => so
.Field(f => f.ZeroTrackTime, SortOrder.Descending) .Field(f => f.ZeroTrackTime, SortOrder.Descending)
) )
.Source(s2 => s2.Includes(fd2 => fd2
.Field(f => f.TrackEnContent)
.Field(f => f.TrackContent)
.Field(f => f.TrackPlace)
.Field(f => f.TrackTime)
.Field(f => f.TrackTimeZone)
.Field(f => f.OrderId)
.Field(f => f.TrackCode)
.Field(f => f.Id)
.Field(f => f.IndexName)
))
) )
) )
) )
@ -343,15 +357,26 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
return r.ToIdList(); return r.ToIdList();
} }
public async Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, List<string> trackCodes, TrackSourceEnum source) public async Task<List<TrackDetailsIndex>> GetListAsync(int[] orderIds, List<string> trackCodes, TrackSourceEnum? source)
{ {
var query = new QueryContainer();
if (orderIds.Length > 0)
{
query &= Query<TrackDetailsIndex>.Terms(t => t.Field(f => f.OrderId).Terms(orderIds));
}
if (trackCodes.Count > 0)
{
query &= Query<TrackDetailsIndex>.Terms(t => t.Field(f => f.TrackCode.Suffix("keyword")).Terms(trackCodes));
}
if (source.HasValue)
{
query &= Query<TrackDetailsIndex>.Term(t => t.Field(f => f.Source).Value(source.Value));
}
var r = await Context.SearchAsync<TrackDetailsIndex>(x => x var r = await Context.SearchAsync<TrackDetailsIndex>(x => x
.Index(GlobalConst.TrackDetailsIndex) .Index(GlobalConst.TrackDetailsIndex)
.Query(q => .Query(q => query)
q.Terms(t => t.Field(f => f.OrderId).Terms(orderIds))
&& q.Terms(t => t.Field(f => f.TrackCode.Suffix("keyword")).Terms(trackCodes))
&& q.Term(t => t.Source, (int) source)
)
.Size(SafelyLimit) .Size(SafelyLimit)
.Sort(s => s.Field(f => f.ZeroTrackTime, SortOrder.Descending))); .Sort(s => s.Field(f => f.ZeroTrackTime, SortOrder.Descending)));
@ -474,5 +499,4 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract<TrackDetail
return res.Documents.FirstOrDefault(); return res.Documents.FirstOrDefault();
} }
} }