轨迹发生

This commit is contained in:
李鹏军 2024-03-02 15:34:26 +08:00
parent 38f69d0dc5
commit 5fa20966ab
14 changed files with 248 additions and 39 deletions

View File

@ -8,12 +8,22 @@ public class TrackUpsertEvent : UpsertTrackInput
/// 订单id /// 订单id
/// </summary> /// </summary>
public int OrderId { get; set; } public int OrderId { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
/// <summary> /// <summary>
/// 子系统id /// 子系统id
/// </summary> /// </summary>
public int SubSystemId { get; set; } public int SubSystemId { get; set; }
/// <summary>
/// 订单是否推送完成(异步维护)
/// </summary>
public bool IsPushCompleted { get; set; }
/// <summary> /// <summary>
/// 上游子系统id /// 上游子系统id
/// </summary> /// </summary>

View File

@ -0,0 +1,34 @@
namespace SJZY.Track.Application.Contract.Events;
public class UpdateOrderTrackEvent
{
/// <summary>
/// 订单Id
/// </summary>
public int OrderId { get; set; }
/// <summary>
/// 此次发生的轨迹是否意味完成
/// </summary>
public bool IsCompleted { get; set; }
/// <summary>
/// 轨迹内容
/// </summary>
public string TrackContent { get; set; } = null!;
/// <summary>
/// 轨迹内容英文
/// </summary>
public string TrackEnContent { get; set; } = null!;
/// <summary>
/// 轨迹发生地
/// </summary>
public string TrackPlace { get; set; } = null!;
/// <summary>
/// 轨迹发生时间
/// </summary>
public DateTime TrackTime { get; set; }
}

View File

@ -0,0 +1,18 @@
namespace SJZY.Track.Application.Contract.Services;
public interface ITrackPushCacheService
{
/// <summary>
/// 判断客户是否需要推送
/// </summary>
/// <param name="customId"></param>
/// <returns></returns>
Task<bool> IsPushAsync(int customId);
/// <summary>
/// 更新缓存
/// </summary>
/// <param name="customId"></param>
/// <param name="isPush"></param>
Task UpdateAsync(int customId, bool isPush);
}

View File

@ -1,6 +1,7 @@
using DotNetCore.CAP; using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.PublicMethords; using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Queries; using SJZY.Track.Domain.Queries;
@ -14,29 +15,33 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
private readonly IOrderRepository _orderRepository; private readonly IOrderRepository _orderRepository;
private readonly ITrackQueries _trackQueries; private readonly ITrackQueries _trackQueries;
private readonly ITrackDetailsRepository _trackDetailsRepository; private readonly ITrackDetailsRepository _trackDetailsRepository;
private readonly ITrackPushCacheService _trackPushCacheService;
private readonly ICapPublisher _capPublisher; private readonly ICapPublisher _capPublisher;
public TrackUpsertEventHandler(IOrderRepository orderRepository, ICapPublisher capPublisher, public TrackUpsertEventHandler(IOrderRepository orderRepository, ICapPublisher capPublisher,
ITrackQueries trackQueries, ITrackDetailsRepository trackDetailsRepository) ITrackQueries trackQueries, ITrackDetailsRepository trackDetailsRepository,
ITrackPushCacheService trackPushCacheService)
{ {
_orderRepository = orderRepository; _orderRepository = orderRepository;
_capPublisher = capPublisher; _capPublisher = capPublisher;
_trackQueries = trackQueries; _trackQueries = trackQueries;
_trackDetailsRepository = trackDetailsRepository; _trackDetailsRepository = trackDetailsRepository;
_trackPushCacheService = trackPushCacheService;
} }
[NonAction]
[CapSubscribe(GlobalConst.TrackUpsertSubscribe)] [CapSubscribe(GlobalConst.TrackUpsertSubscribe)]
public async Task ConsumerAsync(TrackUpsertEvent @event) public async Task ConsumerAsync(TrackUpsertEvent @event)
{ {
// 不同子系统需要做内容映射 // 不同子系统需要做内容映射
if (@event.UpSubSystemId != @event.SubSystemId) if (@event.UpSubSystemId != @event.SubSystemId)
{ {
var mapCode = await _trackQueries.MapTrackContentCodeAsync(@event.UpSubSystemId, @event.SubSystemId, @event.TrackCode); var mapCode = await _trackQueries
.MapTrackContentCodeAsync(@event.UpSubSystemId, @event.SubSystemId, @event.TrackCode);
if (mapCode == default) if (mapCode == default)
{ {
throw new BusinessException(message: "订单跨子系统,未配置内容映射,请联系管理员"); //throw new BusinessException(message: "订单跨子系统,未配置内容映射,请联系管理员");
return;
} }
@event.TrackCode = mapCode; @event.TrackCode = mapCode;
@ -50,15 +55,17 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
// 不存在则新增轨迹,存在则更新 // 不存在则新增轨迹,存在则更新
var track = await _trackDetailsRepository.GetFirstOrDefaultAsync(@event.OrderId, @event.TrackCode); var track = await _trackDetailsRepository.GetFirstOrDefaultAsync(@event.OrderId, @event.TrackCode);
var isPush = false; // 推送只做新增的,更新和删除的不做先 var orderIsCompleted = false;
if (track == default) if (track == default)
{ {
// 根据轨迹code在订单模板内容中寻找匹配的 // 根据轨迹code在订单模板内容中寻找匹配的
var trackContent = await _trackQueries.MatchTrackContentAsync(@event.OrderId, @event.TrackCode); var trackContent = await _trackQueries.MatchTrackContentAsync(@event.OrderId, @event.TrackCode);
if (trackContent == default) if (trackContent == default)
{ {
throw new BusinessException(message: $"订单:{@event.OrderNo} 所绑定的模板,没有一条内容可以匹配轨迹代码:{@event.TrackCode}"); //throw new BusinessException(message: $"订单:{@event.OrderNo} 所绑定的模板,没有一条内容可以匹配轨迹代码:{@event.TrackCode}");
return;
} }
orderIsCompleted = trackContent.IsCompleted;
track = new TrackDetailsIndex track = new TrackDetailsIndex
{ {
@ -72,22 +79,37 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
TrackPlace = @event.TrackPlace, TrackPlace = @event.TrackPlace,
TrackTime = @event.TrackTime, TrackTime = @event.TrackTime,
TraceTimeZone = @event.TraceTimeZone, TraceTimeZone = @event.TraceTimeZone,
CreateUserId = CurrentUserRequest.CurrentUser.UserId, CreateUser = CurrentUserRequest.CurrentUser.Name,
CreateTime = DateTime.Now CreateTime = DateTime.Now
}; };
isPush = true; // todo:推送只做新增的,更新和删除的不做先
if (!@event.IsPushCompleted && await _trackPushCacheService.IsPushAsync(@event.CustomId))
{
//await PushTrack();
}
} }
else else
{ {
track.TrackPlace = @event.TrackPlace; track.TrackPlace = @event.TrackPlace;
track.TrackTime = @event.TrackTime; track.TrackTime = @event.TrackTime;
track.TraceTimeZone = @event.TraceTimeZone; track.TraceTimeZone = @event.TraceTimeZone;
track.UpdateUserId = CurrentUserRequest.CurrentUser.UserId; track.UpdateUser = CurrentUserRequest.CurrentUser.Name;
track.UpdateTime = DateTime.Now; track.UpdateTime = DateTime.Now;
} }
await _trackDetailsRepository.UpsertAsync(track); await _trackDetailsRepository.UpsertAsync(track);
// 触发订单主表更新事件
await _capPublisher.PublishAsync(GlobalConst.UpdateOrderTrackSubscribe, new UpdateOrderTrackEvent
{
OrderId = track.OrderId,
IsCompleted = orderIsCompleted,
TrackContent = track.TrackContent,
TrackEnContent = track.TrackEnContent,
TrackPlace = track.TrackPlace,
TrackTime = track.TrackTime
});
// 根据订单关联关系异步向下刷 // 根据订单关联关系异步向下刷
var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderId); var linkedOrders = await _orderRepository.GetLinkedOrdersAsync(@event.OrderId);
@ -95,14 +117,13 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
{ {
var nextEvent = @event.DeepCopy(); var nextEvent = @event.DeepCopy();
nextEvent.OrderId = linkedOrder.OrderId; nextEvent.OrderId = linkedOrder.OrderId;
nextEvent.OrderType = linkedOrder.OrderType;
nextEvent.OrderNo = linkedOrder.OrderNo;
nextEvent.SubSystemId = linkedOrder.SubSystemId; nextEvent.SubSystemId = linkedOrder.SubSystemId;
nextEvent.IsPushCompleted = linkedOrder.IsPushCompleted;
nextEvent.CustomId = linkedOrder.CustomId;
nextEvent.UpSubSystemId = @event.SubSystemId; nextEvent.UpSubSystemId = @event.SubSystemId;
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, nextEvent); await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, nextEvent);
} }
if (isPush)
{
//await PushTrack();
}
} }
} }

View File

@ -0,0 +1,38 @@
using DotNetCore.CAP;
using SJZY.Track.Application.Contract.Events;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using Volo.Abp.DependencyInjection;
namespace SJZY.Track.Application.EventHandlers;
public class UpdateOrderTrackEventHandler : ITransientDependency, ICapSubscribe
{
private readonly IOrderRepository _orderRepository;
public UpdateOrderTrackEventHandler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
[CapSubscribe(GlobalConst.UpdateOrderTrackSubscribe)]
public async Task ConsumerAsync(UpdateOrderTrackEvent @event)
{
var order = await _orderRepository.GetFirstAsync(x => x.Id == @event.OrderId);
if (order == default) return;
if (order.IsCompleted) return;
if (order.LatestTrackTime > @event.TrackTime) return;
order.LatestTrackContent = @event.TrackContent;
order.LatestTrackEnContent = @event.TrackEnContent;
order.LatestTrackPlace = @event.TrackPlace;
order.LatestTrackTime = @event.TrackTime;
if (@event.IsCompleted) order.IsCompleted = true;
await _orderRepository.UpdateColumnAsync(order, x => new
{
x.IsCompleted, x.LatestTrackContent, x.LatestTrackEnContent, x.LatestTrackPlace, x.LatestTrackTime
});
}
}

View File

@ -27,9 +27,11 @@ public class OrderLinkService : ApplicationService
[HttpPost("Order/Link")] [HttpPost("Order/Link")]
public async Task<bool> LinkOrderAsync(LinkOrderInput input) public async Task<bool> LinkOrderAsync(LinkOrderInput input)
{ {
if (!await _orderRepository.IsAnyAsync(x => x.OrderType == input.OrderType && x.OrderNo == input.OrderNo)) var orderId = await _orderRepository.GetFirstAsync(x =>
x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => x.Id);
if (orderId == default)
{ {
throw new BusinessException(message: $"单号:{input.OrderNo}不存在"); throw new BusinessException(message: $"订单:{input.OrderNo}不存在");
} }
if (input.LinkOrderNos.Count < 1 || input.LinkOrderType == 0) return true; if (input.LinkOrderNos.Count < 1 || input.LinkOrderType == 0) return true;
@ -41,10 +43,10 @@ public class OrderLinkService : ApplicationService
if (!input.IsLink) return await UnLinkOrderAsync(input); if (!input.IsLink) return await UnLinkOrderAsync(input);
// 关联订单 // 关联订单
return await DoLinkOrderAsync(input); return await DoLinkOrderAsync(input, orderId);
} }
private async Task<bool> DoLinkOrderAsync(LinkOrderInput input) private async Task<bool> DoLinkOrderAsync(LinkOrderInput input, int orderId)
{ {
// 获取已关联的订单 // 获取已关联的订单
var linkOrderNos = await _orderLinkQuery.GetListAsync(x => var linkOrderNos = await _orderLinkQuery.GetListAsync(x =>
@ -55,15 +57,17 @@ public class OrderLinkService : ApplicationService
var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos); var noLinkOrderNos = input.LinkOrderNos.Except(linkOrderNos);
// 过滤掉不存在的订单 // 过滤掉不存在的订单
var canLinkOrderNos = await _orderRepository.GetListAsync(x => var canLinkOrders = await _orderRepository.GetListAsync(x =>
x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo), x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo),
x => x.OrderNo); x => new { x.Id, x.OrderNo });
await _orderRepository.LinkOrderAsync(canLinkOrderNos.Select(x => new OrderLinkEntity await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity
{ {
OrderId = orderId,
OrderNo = input.OrderNo, OrderNo = input.OrderNo,
OrderType = input.OrderType, OrderType = input.OrderType,
LinkOrderNo = x, LinkOrderId = x.Id,
LinkOrderNo = x.OrderNo,
LinkOrderType = input.LinkOrderType LinkOrderType = input.LinkOrderType
}).ToList()); }).ToList());

View File

@ -32,7 +32,7 @@ public class TrackService : ApplicationService
var order = await _orderRepository.GetFirstAsync(x => var order = await _orderRepository.GetFirstAsync(x =>
x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new
{ {
x.Id, x.SubSystemId, x.IsPushCompleted x.Id, x.SubSystemId, x.IsPushCompleted, x.CustomId
}); });
if (order == default) if (order == default)
{ {
@ -43,6 +43,8 @@ public class TrackService : ApplicationService
var @event = ObjectMapper.Map<UpsertTrackInput, TrackUpsertEvent>(input); var @event = ObjectMapper.Map<UpsertTrackInput, TrackUpsertEvent>(input);
@event.OrderId = order.Id; @event.OrderId = order.Id;
@event.SubSystemId = order.SubSystemId; @event.SubSystemId = order.SubSystemId;
@event.IsPushCompleted = order.IsPushCompleted;
@event.CustomId = order.CustomId;
await _trackUpsertEventHandler.UpsertTrackAsync(@event); await _trackUpsertEventHandler.UpsertTrackAsync(@event);
return true; return true;
} }

View File

@ -0,0 +1,38 @@
using SJZY.Expand.ABP.Core;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
using SJZY.Track.Domain.Queries;
using Volo.Abp.DependencyInjection;
namespace SJZY.Track.Application.Services.TrackPush;
public class TrackPushCacheService:ITrackPushCacheService, ITransientDependency
{
private readonly IBasicQuery<TrackPushConfigEntity> _trackPushConfigQuery;
private string RedisKey(int customId) => GlobalConst.TrackPushKeyPrefix + customId;
public TrackPushCacheService(IBasicQuery<TrackPushConfigEntity> trackPushConfigQuery)
{
_trackPushConfigQuery = trackPushConfigQuery;
}
public async Task<bool> IsPushAsync(int customId)
{
var isPush =
await RedisHelper.Client.GetAsync<bool?>(RedisKey(customId));
if (isPush == null)
{
isPush = await _trackPushConfigQuery.GetFirstAsync(x => x.CustomId == customId,
x => x.IsAutoPush);
await RedisHelper.Client.SetAsync(RedisKey(customId), isPush);
}
return (bool)isPush;
}
public async Task UpdateAsync(int customId, bool isPush)
{
await RedisHelper.Client.SetAsync(RedisKey(customId), isPush);
}
}

View File

@ -74,14 +74,14 @@ public class TrackDetailsIndex : IdBaseIndex
/// <summary>删除标记 0正常 1 已删除</summary> /// <summary>删除标记 0正常 1 已删除</summary>
public bool IsDeleted { get; set; } public bool IsDeleted { get; set; }
/// <summary>创建人id</summary> /// <summary>创建人</summary>
public int CreateUserId { get; set; } public string? CreateUser { get; set; }
/// <summary>创建时间</summary> /// <summary>创建时间</summary>
public DateTime CreateTime { get; set; } public DateTime CreateTime { get; set; }
/// <summary>修改人id</summary> /// <summary>修改人</summary>
public int? UpdateUserId { get; set; } public string? UpdateUser { get; set; }
/// <summary>修改时间</summary> /// <summary>修改时间</summary>
public DateTime? UpdateTime { get; set; } public DateTime? UpdateTime { get; set; }

View File

@ -6,9 +6,29 @@ public class LinkedOrderVO
/// 关联订单id /// 关联订单id
/// </summary> /// </summary>
public int OrderId { get; set; } public int OrderId { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string OrderNo { get; set; } = null!;
/// <summary>
/// 订单类型(主数据枚举TrackOrderType)
/// </summary>
public int OrderType { get; set; }
/// <summary> /// <summary>
/// 子系统id /// 子系统id
/// </summary> /// </summary>
public int SubSystemId { get; set; } public int SubSystemId { get; set; }
/// <summary>
/// 订单是否推送完成(异步维护)
/// </summary>
public bool IsPushCompleted { get; set; }
/// <summary>
/// 客户id
/// </summary>
public int CustomId { get; set; }
} }

View File

@ -16,4 +16,9 @@ public class MatchTrackContentDto
/// 轨迹状态 /// 轨迹状态
/// </summary> /// </summary>
public string Status { get; set; } = null!; public string Status { get; set; } = null!;
/// <summary>
/// 是否意味着完成
/// </summary>
public bool IsCompleted { get; set; }
} }

View File

@ -3,12 +3,23 @@
public class GlobalConst public class GlobalConst
{ {
/// <summary> /// <summary>
/// 轨迹明细es索引名称 /// 轨迹明细 es索引名称
/// </summary> /// </summary>
public const string TrackIndex = "sjzy_track_details"; public const string TrackIndex = "sjzy_track_details";
/// <summary> /// <summary>
/// 轨迹新增/更新cap订阅名称 /// 轨迹新增/更新 mq订阅名称
/// </summary> /// </summary>
public const string TrackUpsertSubscribe = "SJZY.Track.Upsert"; public const string TrackUpsertSubscribe = "SJZY.Track.TrackUpsert";
/// <summary>
/// 轨迹新增/更新后触发更新订单轨迹 mq订阅名称
/// </summary>
public const string UpdateOrderTrackSubscribe = "SJZY.Track.UpdateOrderTrack";
/// <summary>
/// 轨迹要推送的客户redis key前缀
/// </summary>
public const string TrackPushKeyPrefix = "TrackPush:";
} }

View File

@ -1,5 +1,6 @@
using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
using SJZY.Track.Domain.Aggregates.TrackFlagAggregate;
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate; using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate; using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
using SJZY.Track.Domain.Dtos.Order; using SJZY.Track.Domain.Dtos.Order;
@ -66,12 +67,14 @@ public class TrackQueries : ISugarRepository, ITrackQueries,
.LeftJoin<TrackTemplateContentEntity>((x, a) => x.TrackTemplateId == a.TrackTemplateId) .LeftJoin<TrackTemplateContentEntity>((x, a) => x.TrackTemplateId == a.TrackTemplateId)
.LeftJoin<TrackContentEntity>((x, a, b) => a.TrackContentId == b.Id) .LeftJoin<TrackContentEntity>((x, a, b) => a.TrackContentId == b.Id)
.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)
.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) => new MatchTrackContentDto .Select((x, a, b, c,d) => new MatchTrackContentDto
{ {
Content = b.Content, Content = b.Content,
EnContent = b.EnContent, EnContent = b.EnContent,
Status = c.Status Status = c.Status,
IsCompleted = d.IsCompleted
}) })
.FirstAsync(); .FirstAsync();
} }

View File

@ -55,13 +55,18 @@ public class OrderRepository : BasicRepository<OrderEntity>, IOrderRepository, I
public async Task<List<LinkedOrderVO>> GetLinkedOrdersAsync(int orderId) public async Task<List<LinkedOrderVO>> GetLinkedOrdersAsync(int orderId)
{ {
return await Context.Queryable<OrderEntity>() return await Context.Queryable<OrderLinkEntity>()
.LeftJoin<OrderLinkEntity>((a, b) => a.Id == b.OrderId) .LeftJoin<OrderLinkEntity>((a , b) => a.Id == b.OrderId)
.LeftJoin<OrderEntity>((a, b, c) => b.LinkOrderId == c.Id)
.Where(a => a.Id == orderId) .Where(a => a.Id == orderId)
.Select((a, b) => new LinkedOrderVO .Select((a, b,c) => new LinkedOrderVO
{ {
OrderId = b.LinkOrderId, OrderId = c.Id,
SubSystemId = a.SubSystemId OrderType = c.OrderType,
OrderNo = c.OrderNo,
SubSystemId = c.SubSystemId,
IsPushCompleted = c.IsPushCompleted,
CustomId = c.CustomId
}) })
.ToListAsync(); .ToListAsync();
} }