diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackInput.cs
new file mode 100644
index 00000000..5616f912
--- /dev/null
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchDeleteTrackInput.cs
@@ -0,0 +1,25 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
+
+public class BatchDeleteTrackInput
+{
+ ///
+ /// 订单类型,必填
+ ///
+ [Required]
+ [Range(1, int.MaxValue)]
+ public int OrderType { get; set; }
+
+ ///
+ /// 订单号,必填
+ ///
+ [Required]
+ public List OrderNos { get; set; } = new();
+
+ ///
+ /// 轨迹code,必填
+ ///
+ [Required]
+ public List TrackCodes { get; set; } = new();
+}
\ No newline at end of file
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs
index 0e318811..bff3df6e 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/DeleteOrderInput.cs
@@ -1,4 +1,6 @@
-namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
+using System.ComponentModel.DataAnnotations;
+
+namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
public class DeleteOrderInput : OrderNoInfo
{
@@ -9,5 +11,6 @@ public class DeleteTrackInput : OrderNoInfo
///
/// 轨迹code
///
+ [Required]
public List TrackCodes { get; set; } = new();
}
\ No newline at end of file
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/LinkOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/LinkOrderInput.cs
index cf3e5b79..7d30b3c5 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/LinkOrderInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/LinkOrderInput.cs
@@ -22,7 +22,11 @@ public class LinkOrderInput
[Required]
public string OrderNo { get; set; }
- [Required] public int LinkOrderType { get; set; }
+ ///
+ /// 关联单类型
+ ///
+ [Required]
+ public int LinkOrderType { get; set; }
///
/// 关联的单号
diff --git a/src/SJZY.Track.Application.Contract/Events/OrderLinkAfterFillTrackEvent.cs b/src/SJZY.Track.Application.Contract/Events/OrderLinkAfterFillTrackEvent.cs
new file mode 100644
index 00000000..5caa784e
--- /dev/null
+++ b/src/SJZY.Track.Application.Contract/Events/OrderLinkAfterFillTrackEvent.cs
@@ -0,0 +1,19 @@
+namespace SJZY.Track.Application.Contract.Events;
+
+public class OrderLinkAfterFillTrackEvent
+{
+ ///
+ /// 关联订单id
+ ///
+ public int OrderId { get; set; }
+
+ ///
+ /// 子系统id
+ ///
+ public int SubSystemId { get; set; }
+
+ ///
+ /// 关联订单
+ ///
+ public List LinkedOrderIds { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/src/SJZY.Track.Application/EventHandlers/OrderLinkAfterFillTrackHandler.cs b/src/SJZY.Track.Application/EventHandlers/OrderLinkAfterFillTrackHandler.cs
new file mode 100644
index 00000000..4a014b49
--- /dev/null
+++ b/src/SJZY.Track.Application/EventHandlers/OrderLinkAfterFillTrackHandler.cs
@@ -0,0 +1,61 @@
+using DotNetCore.CAP;
+using SJZY.Track.Application.Contract.Events;
+using SJZY.Track.Domain.Aggregates.OrderAggregate;
+using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
+using Volo.Abp.DependencyInjection;
+
+namespace SJZY.Track.Application.EventHandlers;
+
+public class OrderLinkAfterFillTrackHandler : ITransientDependency, ICapSubscribe
+{
+ private readonly ITrackDetailsRepository _trackDetailsRepository;
+ private readonly ICapPublisher _capPublisher;
+ private readonly IOrderRepository _orderRepository;
+
+ public OrderLinkAfterFillTrackHandler(ITrackDetailsRepository trackDetailsRepository, ICapPublisher capPublisher,
+ IOrderRepository orderRepository)
+ {
+ _trackDetailsRepository = trackDetailsRepository;
+ _capPublisher = capPublisher;
+ _orderRepository = orderRepository;
+ }
+
+ [CapSubscribe(GlobalConst.OrderLinkAfterFillTrack)]
+ public async Task ConsumerAsync(OrderLinkAfterFillTrackEvent @event)
+ {
+ var tracks = await _trackDetailsRepository.GetListAsync(@event.OrderId);
+
+
+ foreach (var linkOrderId in @event.LinkedOrderIds)
+ {
+ var order = await _orderRepository.GetFirstAsync(x =>
+ x.Id == linkOrderId, x => new
+ {
+ x.OrderType, x.OrderNo, x.CustomId, x.IsPushCompleted, x.SubSystemId
+ });
+
+ if (order == default) continue;
+
+ // 补轨迹
+ foreach (var track in tracks)
+ {
+ var fillTrackEvent = new TrackUpsertEvent
+ {
+ OrderType = order.OrderType,
+ OrderNo = order.OrderNo,
+ TrackCode = track.TrackCode,
+ TrackPlace = track.TrackPlace,
+ TrackTime = track.TrackTime,
+ TrackTimeZone = track.TrackTimeZone,
+ OrderId = linkOrderId,
+ CustomId = order.CustomId,
+ SubSystemId = order.SubSystemId,
+ IsPushCompleted = order.IsPushCompleted,
+ UpSubSystemId = @event.SubSystemId,
+ };
+
+ await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, fillTrackEvent);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs
index 29e14bc2..db60129a 100644
--- a/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs
+++ b/src/SJZY.Track.Application/EventHandlers/TrackUpsertEventHandler.cs
@@ -68,6 +68,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
var orderIsCompleted = false;
if (track == default)
{
+ //todo:可以优化
// 根据轨迹code在订单模板内容中寻找匹配的
var trackContent = await _provideQueries.MatchTrackContentAsync(@event.OrderId, @event.TrackCode);
if (trackContent == default)
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderLinkService.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderLinkService.cs
index c4a6d1db..56741efe 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/OrderLinkService.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderLinkService.cs
@@ -1,4 +1,6 @@
-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.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Queries;
@@ -13,11 +15,14 @@ public class OrderLinkService : ApplicationService
{
private readonly IOrderRepository _orderRepository;
private readonly IBasicQuery _orderLinkQuery;
+ private readonly ICapPublisher _capPublisher;
- public OrderLinkService(IBasicQuery orderLinkQuery, IOrderRepository orderRepository)
+ public OrderLinkService(IBasicQuery orderLinkQuery, IOrderRepository orderRepository,
+ ICapPublisher capPublisher)
{
_orderLinkQuery = orderLinkQuery;
_orderRepository = orderRepository;
+ _capPublisher = capPublisher;
}
///
@@ -28,14 +33,17 @@ public class OrderLinkService : ApplicationService
[HttpPost("Order/Link")]
public async Task LinkOrderAsync(LinkOrderInput input)
{
- var orderId = await _orderRepository.GetFirstAsync(x =>
- x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => x.Id);
- if (orderId == default)
+ var order = await _orderRepository.GetFirstAsync(x =>
+ x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new
+ {
+ x.Id, x.SubSystemId
+ });
+ if (order == default)
{
throw new BusinessException(message: $"订单:{input.OrderNo}不存在");
}
- //todo:循环关联?
+ //tips:循环关联问题再消费时解决
if (input.OrderType == input.LinkOrderType)
{
throw new BusinessException(message: "不能同级关联");
@@ -52,10 +60,23 @@ public class OrderLinkService : ApplicationService
if (!input.IsLink) return await UnLinkOrderAsync(input);
// 关联订单
- return await DoLinkOrderAsync(input, orderId);
+ var linkedOrderIds = await DoLinkOrderAsync(input, order.Id);
+
+ // 补轨迹
+ if (linkedOrderIds.Count > 0)
+ {
+ await _capPublisher.PublishAsync(GlobalConst.OrderLinkAfterFillTrack, new OrderLinkAfterFillTrackEvent
+ {
+ OrderId = order.Id,
+ SubSystemId = order.SubSystemId,
+ LinkedOrderIds = linkedOrderIds,
+ });
+ }
+
+ return true;
}
- private async Task DoLinkOrderAsync(LinkOrderInput input, int orderId)
+ private async Task> DoLinkOrderAsync(LinkOrderInput input, int orderId)
{
// 获取已关联的订单
var linkOrderNos = await _orderLinkQuery.GetListAsync(x =>
@@ -70,6 +91,8 @@ public class OrderLinkService : ApplicationService
x.OrderType == input.LinkOrderType && noLinkOrderNos.Contains(x.OrderNo),
x => new { x.Id, x.OrderNo });
+ if (canLinkOrders.Count == 0) return new List();
+
await _orderRepository.LinkOrderAsync(canLinkOrders.Select(x => new OrderLinkEntity
{
OrderId = orderId,
@@ -80,9 +103,7 @@ public class OrderLinkService : ApplicationService
LinkOrderType = input.LinkOrderType
}).ToList());
- // todo:补轨迹
-
- return true;
+ return canLinkOrders.Select(x => x.Id).ToList();
}
private async Task UnLinkOrderAsync(LinkOrderInput input)
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
index 18adf7fa..298cc2a4 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
@@ -65,14 +65,19 @@ public class TrackService : ApplicationService
var order = await _orderRepository.GetFirstAsync(x =>
x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new
{
- x.Id, x.SubSystemId, x.IsPushCompleted, x.CustomId
+ x.Id, x.SubSystemId, x.IsCompleted
});
if (order == default)
{
throw new BusinessException(message: $"订单:{input.OrderNo}不存在");
}
- var codes = await _provideQueries.GetCanDeleteTrackCodesAsync(order.Id, input.TrackCodes);
+ if (order.IsCompleted)
+ {
+ throw new BusinessException(message: $"订单:{input.OrderNo}已完成无法删除轨迹");
+ }
+
+ var codes = await _provideQueries.GetCanDeleteTrackCodesAsync(new List(order.Id), input.TrackCodes);
if (codes.Count == 0)
{
@@ -83,11 +88,45 @@ public class TrackService : ApplicationService
var @event = new TrackDeleteEvent
{
OrderId = order.Id,
- TrackCodes = codes,
+ TrackCodes = codes.Select(x => x.TrackCode).ToList(),
SubSystemId = order.SubSystemId,
};
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event);
return true;
}
+
+ [HttpPost("Track/BatchDelete")]
+ public async Task BatchTrackAsync(BatchDeleteTrackInput input)
+ {
+ var orders = await _orderRepository.GetListAsync(x =>
+ x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo) && !x.IsPushCompleted
+ , x => new
+ {
+ x.Id, x.SubSystemId
+ });
+
+ var codes = await _provideQueries.GetCanDeleteTrackCodesAsync(
+ orders.Select(x => x.Id).ToList(), input.TrackCodes
+ );
+
+ if (codes.Count == 0)
+ {
+ throw new BusinessException(message: "没有一个轨迹代码是可删的");
+ }
+
+ // 删除轨迹
+ foreach (var group in codes.GroupBy(x => x.OrderId))
+ {
+ var @event = new TrackDeleteEvent
+ {
+ OrderId = group.Key,
+ TrackCodes = codes.Select(x => x.TrackCode).ToList(),
+ SubSystemId = orders.First(x => x.Id == group.Key).SubSystemId,
+ };
+ await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event);
+ }
+
+ return true;
+ }
}
\ No newline at end of file
diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsRepository.cs
index f6578023..4025579e 100644
--- a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsRepository.cs
+++ b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/ITrackDetailsRepository.cs
@@ -11,8 +11,8 @@ public interface ITrackDetailsRepository
Task> GetListAsync(int orderType, List orderNos);
Task<(List list, long total)> GetListAsync(TrackDetailsQueryInput input);
- Task?> GetListAsync(int orderId);
-
+ Task> GetListAsync(int orderId);
+
///
/// 删除轨迹
///
@@ -20,5 +20,6 @@ public interface ITrackDetailsRepository
///
///
Task DeleteTrackAsync(int orderId, List trackCodes);
+
Task?> GetListAsync(List orderIds);
}
\ No newline at end of file
diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/CanDeleteTrackCodeVO.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/CanDeleteTrackCodeVO.cs
new file mode 100644
index 00000000..b4376fe5
--- /dev/null
+++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/CanDeleteTrackCodeVO.cs
@@ -0,0 +1,7 @@
+namespace SJZY.Track.Domain.Dtos.TrackTemplate;
+
+public class CanDeleteTrackCodeVO
+{
+ public int OrderId { get; set; }
+ public string TrackCode { get; set; }
+}
\ No newline at end of file
diff --git a/src/SJZY.Track.Domain/GlobalConst.cs b/src/SJZY.Track.Domain/GlobalConst.cs
index 92545ea9..78fdd6a8 100644
--- a/src/SJZY.Track.Domain/GlobalConst.cs
+++ b/src/SJZY.Track.Domain/GlobalConst.cs
@@ -11,14 +11,14 @@ public class GlobalConst
/// 轨迹新增/更新 mq订阅名称
///
public const string TrackUpsertSubscribe = "SJZY.Track.TrackUpsert";
-
+
///
/// 轨迹删除 mq订阅名称
///
public const string TrackDeleteSubscribe = "SJZY.Track.TrackDelete";
///
- /// 接口通批量轨迹刷新订阅
+ /// 接口通批量轨迹刷新 mq订阅名称
///
public const string InterfaceRelayTrackRefreshSubscribe = "SJZY.Track.TrackRefresh";
@@ -27,6 +27,11 @@ public class GlobalConst
///
public const string UpdateOrderTrackSubscribe = "SJZY.Track.UpdateOrderTrack";
+ ///
+ /// 关联订单后补轨迹 mq订阅名称
+ ///
+ public const string OrderLinkAfterFillTrack = "SJZY.Track.OrderLinkAfterFillTrack";
+
///
/// 轨迹要推送的客户redis key前缀
///
diff --git a/src/SJZY.Track.Domain/Queries/IBasicQuery.cs b/src/SJZY.Track.Domain/Queries/IBasicQuery.cs
index 894e72a9..460e58be 100644
--- a/src/SJZY.Track.Domain/Queries/IBasicQuery.cs
+++ b/src/SJZY.Track.Domain/Queries/IBasicQuery.cs
@@ -9,7 +9,7 @@ public interface IBasicQuery where T : IEntity
///
Task GetFirstAsync(Expression> whereExpression);
- Task GetFirstAsync(Expression> whereExpression,
+ Task GetFirstAsync(Expression> whereExpression,
Expression> resultExpression);
///
diff --git a/src/SJZY.Track.Domain/Queries/IProvideQueries.cs b/src/SJZY.Track.Domain/Queries/IProvideQueries.cs
index 9c17d1d4..710cb3f4 100644
--- a/src/SJZY.Track.Domain/Queries/IProvideQueries.cs
+++ b/src/SJZY.Track.Domain/Queries/IProvideQueries.cs
@@ -1,4 +1,3 @@
-using SJZY.Track.Domain.Aggregates.TrackPullAggregate;
using SJZY.Track.Domain.Dtos.Order;
using SJZY.Track.Domain.Dtos.TrackDetails;
using SJZY.Track.Domain.Dtos.TrackTemplate;
@@ -32,14 +31,14 @@ public interface IProvideQueries
/// 轨迹代码
///
Task MatchTrackContentAsync(int orderId, string code);
-
+
///
/// 获取可删除的订单轨迹代码
///
- ///
+ ///
///
///
- Task> GetCanDeleteTrackCodesAsync(int orderId, List trackCodes);
+ Task> GetCanDeleteTrackCodesAsync(List orderIds, List trackCodes);
///
/// 根据子系统内容映射,得到映射后的轨迹code
diff --git a/src/SJZY.Track.Repository/Queries/BasicQuery.cs b/src/SJZY.Track.Repository/Queries/BasicQuery.cs
index 60a234ef..d8003be8 100644
--- a/src/SJZY.Track.Repository/Queries/BasicQuery.cs
+++ b/src/SJZY.Track.Repository/Queries/BasicQuery.cs
@@ -13,7 +13,7 @@ public class BasicQuery : SimpleClient, IBasicQuery where T : class, IE
Context = SqlsugarScopeBasic.GetContextSafely("default");
}
- public async Task GetFirstAsync(Expression> whereExpression,
+ public async Task GetFirstAsync(Expression> whereExpression,
Expression> resultExpression)
{
return await Context.Queryable().Where(whereExpression).Select(resultExpression).FirstAsync();
diff --git a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs
index 526d5e3d..78639986 100644
--- a/src/SJZY.Track.Repository/Queries/ProvideQueries.cs
+++ b/src/SJZY.Track.Repository/Queries/ProvideQueries.cs
@@ -80,14 +80,19 @@ public class ProvideQueries : ISugarRepository, IProvideQueries,
.FirstAsync();
}
- public async Task> GetCanDeleteTrackCodesAsync(int orderId, List trackCodes)
+ public async Task> GetCanDeleteTrackCodesAsync(List orderIds,
+ List trackCodes)
{
return await Context.Queryable()
.LeftJoin((x, a) => x.TrackTemplateId == a.TrackTemplateId && a.IsCanDelete)
.LeftJoin((x, a, b) => a.TrackContentId == b.Id)
- .Where((x, a, b) => x.OrderId == orderId
+ .Where((x, a, b) => orderIds.Contains(x.OrderId)
&& trackCodes.Contains(b.Code) && a.IsCanDelete)
- .Select((x, a, b) => b.Code)
+ .Select((x, a, b) => new CanDeleteTrackCodeVO
+ {
+ OrderId = x.OrderId,
+ TrackCode = b.Code
+ })
.ToListAsync();
}
diff --git a/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs
index 70f62f7e..da6f784a 100644
--- a/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs
+++ b/src/SJZY.Track.Repository/Repositories/TrackDetailsRepository.cs
@@ -86,7 +86,7 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract?> GetListAsync(int orderId)
+ public async Task> GetListAsync(int orderId)
{
var data = await Context.SearchAsync(x => x
.Query(q =>
@@ -95,7 +95,7 @@ internal class TrackDetailsRepository : ElasticSearchContextAbstract s.Field(f => f.TrackTime, SortOrder.Descending)));
- return data?.Documents?.ToList();
+ return data.Documents.ToList();
}
public async Task?> GetListAsync(List orderIds)