add 删除轨迹

This commit is contained in:
李鹏军 2024-03-04 15:30:57 +08:00
parent 3c6008a2b5
commit 4f72a4405c
12 changed files with 245 additions and 35 deletions

View File

@ -2,4 +2,12 @@
public class DeleteOrderInput : OrderNoInfo public class DeleteOrderInput : OrderNoInfo
{ {
}
public class DeleteTrackInput : OrderNoInfo
{
/// <summary>
/// 轨迹code
/// </summary>
public List<string> TrackCodes { get; set; } = new();
} }

View File

@ -0,0 +1,24 @@
namespace SJZY.Track.Application.Contract.Events;
public class TrackDeleteEvent
{
/// <summary>
/// 订单id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 轨迹代码
/// </summary>
public List<string> TrackCodes { get; set; } = null!;
/// <summary>
/// 子系统id
/// </summary>
public int SubSystemId { get; set; }
/// <summary>
/// 上游子系统id
/// </summary>
public int UpSubSystemId { get; set; }
}

View File

@ -0,0 +1,67 @@
using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Queries;
using Volo.Abp.DependencyInjection;
namespace SJZY.Track.Application.EventHandlers;
public class TrackDeleteEventHandler: ITransientDependency, ICapSubscribe
{
private readonly IOrderRepository _orderRepository;
private readonly IProvideQueries _provideQueries;
private readonly ITrackDetailsRepository _trackDetailsRepository;
private readonly ICapPublisher _capPublisher;
public TrackDeleteEventHandler(IProvideQueries provideQueries, ITrackDetailsRepository trackDetailsRepository, IOrderRepository orderRepository, ICapPublisher capPublisher)
{
_provideQueries = provideQueries;
_trackDetailsRepository = trackDetailsRepository;
_orderRepository = orderRepository;
_capPublisher = capPublisher;
}
[CapSubscribe(GlobalConst.TrackUpsertSubscribe)]
public async Task ConsumerAsync(TrackDeleteEvent @event)
{
// 不同子系统需要做内容映射
if (@event.UpSubSystemId != 0 && @event.UpSubSystemId != @event.SubSystemId)
{
var mapCodes = await _provideQueries
.MapTrackCodesAsync(@event.UpSubSystemId, @event.SubSystemId, @event.TrackCodes.ToArray());
if (mapCodes.Count == 0)
{
//throw new BusinessException(message: "订单跨子系统,未配置内容映射,请联系管理员");
return;
}
@event.TrackCodes = mapCodes;
}
await DeleteTrackAsync(@event);
}
private async Task DeleteTrackAsync(TrackDeleteEvent @event)
{
// 删除轨迹
await _trackDetailsRepository.DeleteTrackAsync(@event.OrderId, @event.TrackCodes);
// 根据订单关联关系异步向下刷
var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderId);
foreach (var linkedOrder in linkedOrders)
{
var nextEvent = new TrackDeleteEvent
{
OrderId = linkedOrder.OrderId,
TrackCodes = @event.TrackCodes,
SubSystemId = linkedOrder.SubSystemId,
UpSubSystemId = @event.SubSystemId
};
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, nextEvent);
}
}
}

View File

@ -33,10 +33,11 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
public async Task ConsumerAsync(TrackUpsertEvent @event) public async Task ConsumerAsync(TrackUpsertEvent @event)
{ {
// 不同子系统需要做内容映射 // 不同子系统需要做内容映射
if (@event.UpSubSystemId != @event.SubSystemId) if (@event.UpSubSystemId != 0 && @event.UpSubSystemId != @event.SubSystemId)
{ {
var mapCode = await _provideQueries var mapCode = (await _provideQueries
.MapTrackContentCodeAsync(@event.UpSubSystemId, @event.SubSystemId, @event.TrackCode); .MapTrackCodesAsync(@event.UpSubSystemId, @event.SubSystemId, @event.TrackCode))
.FirstOrDefault();
if (mapCode == default) if (mapCode == default)
{ {
@ -50,7 +51,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
await UpsertTrackAsync(@event); await UpsertTrackAsync(@event);
} }
internal async Task UpsertTrackAsync(TrackUpsertEvent @event) private async Task UpsertTrackAsync(TrackUpsertEvent @event)
{ {
// 不存在则新增轨迹,存在则更新 // 不存在则新增轨迹,存在则更新
var track = await _trackDetailsRepository.GetFirstOrDefaultAsync(@event.OrderId, @event.TrackCode); var track = await _trackDetailsRepository.GetFirstOrDefaultAsync(@event.OrderId, @event.TrackCode);
@ -65,6 +66,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
//throw new BusinessException(message: $"订单:{@event.OrderNo} 所绑定的模板,没有一条内容可以匹配轨迹代码:{@event.TrackCode}"); //throw new BusinessException(message: $"订单:{@event.OrderNo} 所绑定的模板,没有一条内容可以匹配轨迹代码:{@event.TrackCode}");
return; return;
} }
orderIsCompleted = trackContent.IsCompleted; orderIsCompleted = trackContent.IsCompleted;
track = new TrackDetailsIndex track = new TrackDetailsIndex
@ -82,7 +84,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
CreateUser = CurrentUserRequest.CurrentUser.Name, CreateUser = CurrentUserRequest.CurrentUser.Name,
CreateTime = DateTime.Now CreateTime = DateTime.Now
}; };
// todo:推送只做新增的,更新和删除的不做先 // todo:推送只做新增的,更新和删除的不做先
if (!@event.IsPushCompleted && await _trackPushCacheService.IsPushAsync(@event.CustomId)) if (!@event.IsPushCompleted && await _trackPushCacheService.IsPushAsync(@event.CustomId))
{ {
@ -99,7 +101,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
} }
await _trackDetailsRepository.UpsertAsync(track); await _trackDetailsRepository.UpsertAsync(track);
// 触发订单主表更新事件 // 触发订单主表更新事件
await _capPublisher.PublishAsync(GlobalConst.UpdateOrderTrackSubscribe, new UpdateOrderTrackEvent await _capPublisher.PublishAsync(GlobalConst.UpdateOrderTrackSubscribe, new UpdateOrderTrackEvent
{ {

View File

@ -16,11 +16,11 @@ public class OrderService : ApplicationService
private readonly ITrackDetailsRepository _trackDetailsRepository; private readonly ITrackDetailsRepository _trackDetailsRepository;
public OrderService(IOrderRepository orderRepository, public OrderService(IOrderRepository orderRepository,
ITrackDetailsRepository trackDetailsRepository ITrackDetailsRepository trackDetailsRepository
) )
{ {
_orderRepository = orderRepository; _orderRepository = orderRepository;
this._trackDetailsRepository=trackDetailsRepository; _trackDetailsRepository = trackDetailsRepository;
} }
/// <summary> /// <summary>

View File

@ -1,7 +1,8 @@
using SJZY.Track.Application.Contract.Dtos.ProvideServices; using DotNetCore.CAP;
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.EventHandlers;
using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Queries;
namespace SJZY.Track.Application.Services.ProvideServices; namespace SJZY.Track.Application.Services.ProvideServices;
@ -12,12 +13,14 @@ namespace SJZY.Track.Application.Services.ProvideServices;
public class TrackService : ApplicationService public class TrackService : ApplicationService
{ {
private readonly IOrderRepository _orderRepository; private readonly IOrderRepository _orderRepository;
private readonly TrackUpsertEventHandler _trackUpsertEventHandler; private readonly IProvideQueries _provideQueries;
private readonly ICapPublisher _capPublisher;
public TrackService(IOrderRepository orderRepository, TrackUpsertEventHandler trackUpsertEventHandler) public TrackService(IOrderRepository orderRepository, IProvideQueries provideQueries, ICapPublisher capPublisher)
{ {
_orderRepository = orderRepository; _orderRepository = orderRepository;
_trackUpsertEventHandler = trackUpsertEventHandler; _provideQueries = provideQueries;
_capPublisher = capPublisher;
} }
/// <summary> /// <summary>
@ -45,7 +48,45 @@ public class TrackService : ApplicationService
@event.SubSystemId = order.SubSystemId; @event.SubSystemId = order.SubSystemId;
@event.IsPushCompleted = order.IsPushCompleted; @event.IsPushCompleted = order.IsPushCompleted;
@event.CustomId = order.CustomId; @event.CustomId = order.CustomId;
await _trackUpsertEventHandler.UpsertTrackAsync(@event); await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
return true;
}
/// <summary>
/// 删除轨迹
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="BusinessException"></exception>
[HttpPost("Track/Delete")]
public async Task<bool> DeleteTrackAsync(DeleteTrackInput input)
{
var order = await _orderRepository.GetFirstAsync(x =>
x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new
{
x.Id, x.SubSystemId, x.IsPushCompleted, x.CustomId
});
if (order == default)
{
throw new BusinessException(message: $"订单:{input.OrderNo}不存在");
}
var codes = await _provideQueries.GetCanDeleteTrackCodesAsync(order.Id, input.TrackCodes);
if (codes.Count == 0)
{
throw new BusinessException(message: "没有一个轨迹代码是可删的");
}
// 删除轨迹
var @event = new TrackDeleteEvent
{
OrderId = order.Id,
TrackCodes = codes,
SubSystemId = order.SubSystemId,
};
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
return true; return true;
} }
} }

View File

@ -4,7 +4,7 @@ namespace SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
public interface ITrackDetailsRepository public interface ITrackDetailsRepository
{ {
Task<TrackDetailsIndex?> GetFirstOrDefaultAsync(int orderId, string inputTrackCode); Task<TrackDetailsIndex?> GetFirstOrDefaultAsync(int orderId, string trackCode);
Task UpsertAsync(TrackDetailsIndex index); Task UpsertAsync(TrackDetailsIndex index);
@ -12,4 +12,12 @@ public interface ITrackDetailsRepository
Task<(List<TrackDetailsIndex> list, long total)> GetListAsync(TrackDetailsQueryInput input); Task<(List<TrackDetailsIndex> list, long total)> GetListAsync(TrackDetailsQueryInput input);
Task<List<TrackDetailsIndex>> GetListAsync(int orderId); Task<List<TrackDetailsIndex>> GetListAsync(int orderId);
/// <summary>
/// 删除轨迹
/// </summary>
/// <param name="orderId"></param>
/// <param name="trackCodes"></param>
/// <returns></returns>
Task DeleteTrackAsync(int orderId, List<string> trackCodes);
} }

View File

@ -0,0 +1,14 @@
namespace SJZY.Track.Domain.Dtos.TrackDetails;
public class MatchTrackContentsDto
{
/// <summary>
/// 轨迹代码
/// </summary>
public string TrackCode { get; set; } = null!;
/// <summary>
/// 是否支持删除
/// </summary>
public bool IsCanDelete { get; set; }
}

View File

@ -11,6 +11,11 @@ public class GlobalConst
/// 轨迹新增/更新 mq订阅名称 /// 轨迹新增/更新 mq订阅名称
/// </summary> /// </summary>
public const string TrackUpsertSubscribe = "SJZY.Track.TrackUpsert"; public const string TrackUpsertSubscribe = "SJZY.Track.TrackUpsert";
/// <summary>
/// 轨迹删除 mq订阅名称
/// </summary>
public const string TrackDeleteSubscribe = "SJZY.Track.TrackDelete";
/// <summary> /// <summary>
/// 接口通批量轨迹刷新订阅 /// 接口通批量轨迹刷新订阅

View File

@ -32,15 +32,23 @@ public interface IProvideQueries
/// <param name="code">轨迹代码</param> /// <param name="code">轨迹代码</param>
/// <returns></returns> /// <returns></returns>
Task<MatchTrackContentDto?> MatchTrackContentAsync(int orderId, string code); Task<MatchTrackContentDto?> MatchTrackContentAsync(int orderId, string code);
/// <summary>
/// 获取可删除的订单轨迹代码
/// </summary>
/// <param name="orderId"></param>
/// <param name="trackCodes"></param>
/// <returns></returns>
Task<List<string>> GetCanDeleteTrackCodesAsync(int orderId, List<string> trackCodes);
/// <summary> /// <summary>
/// 根据子系统内容映射,得到映射后的轨迹code /// 根据子系统内容映射,得到映射后的轨迹code
/// </summary> /// </summary>
/// <param name="upSubSystemId"></param> /// <param name="upSubSystemId"></param>
/// <param name="subSystemId"></param> /// <param name="subSystemId"></param>
/// <param name="trackCode"></param> /// <param name="trackCodes"></param>
/// <returns></returns> /// <returns></returns>
Task<string?> MapTrackContentCodeAsync(int upSubSystemId, int subSystemId, string trackCode); Task<List<string>> MapTrackCodesAsync(int upSubSystemId, int subSystemId, params string[] trackCodes);
/// <summary> /// <summary>
/// 获取服务商模板配置 /// 获取服务商模板配置

View File

@ -70,7 +70,7 @@ public class ProvideQueries : ISugarRepository, IProvideQueries,
.LeftJoin<TrackStatusEntity>((x, a, b, c) => b.TrackStatusId == c.Id) .LeftJoin<TrackStatusEntity>((x, a, b, c) => b.TrackStatusId == c.Id)
.LeftJoin<TrackFlagEntity>((x, a, b, c, d) => b.TrackFlagId == d.Id) .LeftJoin<TrackFlagEntity>((x, a, b, c, d) => b.TrackFlagId == d.Id)
.Where((x, a, b) => x.OrderId == orderId && b.Code == code) .Where((x, a, b) => x.OrderId == orderId && b.Code == code)
.Select((x, a, b, c,d) => new MatchTrackContentDto .Select((x, a, b, c, d) => new MatchTrackContentDto
{ {
Content = b.Content, Content = b.Content,
EnContent = b.EnContent, EnContent = b.EnContent,
@ -80,13 +80,24 @@ public class ProvideQueries : ISugarRepository, IProvideQueries,
.FirstAsync(); .FirstAsync();
} }
public async Task<string?> MapTrackContentCodeAsync(int upSubSystemId, int subSystemId, string trackCode) public async Task<List<string>> GetCanDeleteTrackCodesAsync(int orderId, List<string> trackCodes)
{
return await Context.Queryable<OrderTemplateEntity>()
.LeftJoin<TrackTemplateContentEntity>((x, a) => x.TrackTemplateId == a.TrackTemplateId && a.IsCanDelete)
.LeftJoin<TrackContentEntity>((x, a, b) => a.TrackContentId == b.Id)
.Where((x, a, b) => x.OrderId == orderId
&& trackCodes.Contains(b.Code))
.Select((x, a, b) => b.Code)
.ToListAsync();
}
public async Task<List<string>> MapTrackCodesAsync(int upSubSystemId, int subSystemId, params string[] trackCodes)
{ {
return await Context.Queryable<TrackContentMapEntity>() return await Context.Queryable<TrackContentMapEntity>()
.Where(x => x.SubSystemId == upSubSystemId && x.MapSubSystemId == subSystemId && .Where(x => x.SubSystemId == upSubSystemId && x.MapSubSystemId == subSystemId &&
x.TrackContentCode == trackCode) trackCodes.Contains(x.TrackContentCode))
.Select(x => x.MapTrackContentCode) .Select(x => x.MapTrackContentCode)
.FirstAsync(); .ToListAsync();
} }
public async Task<List<TrackPullContentConfigVO>> GetPullContentConfigsAsync(int serviceProviderId) public async Task<List<TrackPullContentConfigVO>> GetPullContentConfigsAsync(int serviceProviderId)

View File

@ -22,6 +22,7 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
.Query(q => .Query(q =>
q.Term(t => t.Field(f => f.OrderId).Value(orderId)) q.Term(t => t.Field(f => f.OrderId).Value(orderId))
&& q.Term(t => t.Field(f => f.TrackCode).Value(trackCode)) && q.Term(t => t.Field(f => f.TrackCode).Value(trackCode))
&& q.Term(t => t.Field(f => f.IsDeleted).Value(true))
) )
); );
@ -39,7 +40,7 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
.Index(IndexName) .Index(IndexName)
.Doc(index) .Doc(index)
.DocAsUpsert() .DocAsUpsert()
//.Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见 //.Refresh(Refresh.True) // 可选:立即刷新索引使更改立即可见
); );
if (!response.IsValid) if (!response.IsValid)
throw new Exception($"数据修改失败,原因:{response.DebugInformation}"); throw new Exception($"数据修改失败,原因:{response.DebugInformation}");
@ -62,7 +63,9 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
q.Terms(t => t q.Terms(t => t
.Field(f => f.OrderNo) .Field(f => f.OrderNo)
.Terms(orderNos)) .Terms(orderNos))
&& q.Term(f => f.OrderType, orderType)) && q.Term(f => f.OrderType, orderType)
&& q.Term(t => t.Field(f => f.IsDeleted).Value(true))
)
); );
return data.Documents.ToList(); return data.Documents.ToList();
@ -71,18 +74,34 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
public async Task<List<TrackDetailsIndex>> GetListAsync(int orderId) public async Task<List<TrackDetailsIndex>> GetListAsync(int orderId)
{ {
var data = await Context.SearchAsync<TrackDetailsIndex>(x => x var data = await Context.SearchAsync<TrackDetailsIndex>(x => x
.Source(s => s.Includes(fd => fd .Source(s => s.Includes(fd => fd
.Field(f => f.TrackStatus) .Field(f => f.TrackStatus)
.Field(f => f.TrackCode) .Field(f => f.TrackCode)
.Field(f => f.TrackContent) .Field(f => f.TrackContent)
.Field(f => f.TrackPlace) .Field(f => f.TrackPlace)
.Field(f => f.TrackTime) .Field(f => f.TrackTime)
.Field(f => f.TraceTimeZone) .Field(f => f.TraceTimeZone)
)).Query(q => q.Terms(t => t.Field(f => f.OrderId).Terms(orderId)))); )).Query(q =>
q.Terms(t => t.Field(f => f.OrderId).Terms(orderId))
&& q.Term(t => t.Field(f => f.IsDeleted).Value(true))
)
);
return data?.Documents?.ToList(); return data?.Documents?.ToList();
} }
public async Task DeleteTrackAsync(int orderId, List<string> trackCodes)
{
await Context.UpdateByQueryAsync<TrackDetailsIndex>(x => x
.Query(
q =>
q.Term(t => t.OrderId, orderId)
&& q.Terms(t => t.Field(f => f.TrackCode).Terms(trackCodes)))
.Script(s => s
.Source("ctx._source.IsDeleted = true"))
);
}
public async Task<(List<TrackDetailsIndex> list, long total)> GetListAsync(TrackDetailsQueryInput input) public async Task<(List<TrackDetailsIndex> list, long total)> GetListAsync(TrackDetailsQueryInput input)
{ {
if (input.OrderNos.Count < 1) return default; if (input.OrderNos.Count < 1) return default;
@ -91,9 +110,12 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract<TrackDetail
var finalSize = input.PageSize > 500 ? 500 : input.PageSize; var finalSize = input.PageSize > 500 ? 500 : input.PageSize;
var data = await Context.SearchAsync<TrackDetailsIndex>(x => x var data = await Context.SearchAsync<TrackDetailsIndex>(x => x
.Query(q => q.Terms(t => t .Query(q =>
.Field(f => f.OrderNo) q.Terms(t => t
.Terms(distinctOrderNumbers))) .Field(f => f.OrderNo)
.Terms(distinctOrderNumbers))
&& q.Term(t => t.Field(f => f.IsDeleted).Value(true))
)
.Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending)) .Sort(s => s.Field(f => f.CreateTime, SortOrder.Descending))
.From((input.PageIndex - 1) * input.PageSize) .From((input.PageIndex - 1) * input.PageSize)
.Size(finalSize) .Size(finalSize)