Support 1 pickup to N logistics orders with create/pay/schedule APIs, parcel inboundMethod auto-attach, plus allocation-trace and inbound-billing updates already in tree. Co-authored-by: Cursor <cursoragent@cursor.com>
220 lines
7.9 KiB
C#
220 lines
7.9 KiB
C#
using Fake.Application;
|
|
using Fake.Security.Claims;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Oms.Application.Dtos.Orders;
|
|
using Oms.Application.Dtos.Shared;
|
|
using Oms.Application.Services.Orders.Batch;
|
|
using Oms.Application.Messaging;
|
|
using Oms.Application.Shared;
|
|
using Oms.Domain.CustomersAggregate.Repositories;
|
|
using Oms.Domain.OrdersAggregate.Consts;
|
|
|
|
namespace Oms.Application.Services.Orders;
|
|
|
|
public partial class OrderService
|
|
{
|
|
private OrderBatchJobCoordinator BatchJobCoordinator =>
|
|
LazyServiceProvider.GetRequiredService<OrderBatchJobCoordinator>();
|
|
|
|
/// <summary>
|
|
/// 创建订单批量异步任务并入队 RabbitMQ。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/jobs")]
|
|
public Task<OrderBatchJobOutput> CreateBatchJobAsync([FromBody] OrderBatchJobCreateInput input)
|
|
{
|
|
return BatchJobCoordinator.CreateAndEnqueueAsync(input, CurrentUser.GetId<int>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询批量任务进度。
|
|
/// </summary>
|
|
[HttpGet("/order/batch/jobs/{id:int}")]
|
|
public async Task<OrderBatchJobOutput> GetBatchJobAsync([FromRoute] int id)
|
|
{
|
|
var job = await BatchJobCoordinator.GetJobAsync(id);
|
|
if (job == null)
|
|
{
|
|
throw new BusinessException("批量任务不存在");
|
|
}
|
|
|
|
return job;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 分页查询批量任务列表。
|
|
/// </summary>
|
|
[HttpGet("/order/batch/jobs")]
|
|
public async Task<OmsPageResult<OrderBatchJobOutput>> GetBatchJobListAsync([FromQuery] OrderBatchJobListInput input)
|
|
{
|
|
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(
|
|
LazyServiceProvider.GetRequiredService<ICustomerRepository>(),
|
|
CurrentUser,
|
|
null);
|
|
return await BatchJobCoordinator.GetJobListAsync(input, customerId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询批量任务子项明细。
|
|
/// </summary>
|
|
[HttpGet("/order/batch/jobs/{id:int}/items")]
|
|
public async Task<List<OrderBatchJobItemOutput>> GetBatchJobItemsAsync([FromRoute] int id)
|
|
{
|
|
var job = await BatchJobCoordinator.GetJobEntityAsync(id);
|
|
if (job == null)
|
|
{
|
|
throw new BusinessException("批量任务不存在");
|
|
}
|
|
|
|
return await BatchJobCoordinator.GetJobItemsAsync(id);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 异步批量创建轨迹订单(替代前端逐条调用)。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/track-upsert")]
|
|
public Task<OrderBatchJobOutput> BatchTrackUpsertAsync([FromBody] OrderBatchJobCreateInput input)
|
|
{
|
|
input.Action = OrderBatchActionCodes.TrackUpsertSmallBag;
|
|
var authorization = LazyServiceProvider
|
|
.GetRequiredService<IHttpContextAccessor>()
|
|
.HttpContext?
|
|
.Request
|
|
.Headers
|
|
.Authorization
|
|
.ToString();
|
|
|
|
return BatchJobCoordinator.CreateAndEnqueueAsync(
|
|
input,
|
|
CurrentUser.GetId<int>(),
|
|
string.IsNullOrWhiteSpace(authorization) ? null : authorization);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 异步批量预报下游订单。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/downstream-forward")]
|
|
public Task<OrderBatchJobOutput> BatchDownstreamForwardAsync([FromBody] OrderBatchJobCreateInput input)
|
|
{
|
|
input.Action = OrderBatchActionCodes.DownstreamForwardCreateOne;
|
|
var authorization = LazyServiceProvider
|
|
.GetRequiredService<IHttpContextAccessor>()
|
|
.HttpContext?
|
|
.Request
|
|
.Headers
|
|
.Authorization
|
|
.ToString();
|
|
|
|
return BatchJobCoordinator.CreateAndEnqueueAsync(
|
|
input,
|
|
CurrentUser.GetId<int>(),
|
|
string.IsNullOrWhiteSpace(authorization) ? null : authorization);
|
|
}
|
|
|
|
private Task<OrderBatchJobOutput> EnqueueOrderBatchAsync(string action, OrderBatchJobCreateInput input)
|
|
{
|
|
input.Action = action;
|
|
return BatchJobCoordinator.CreateAndEnqueueAsync(input, CurrentUser.GetId<int>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 异步批量支付订单。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/pay")]
|
|
public Task<OrderBatchJobOutput> BatchPayAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.Pay, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量预报订单。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/pre-declare")]
|
|
public Task<OrderBatchJobOutput> BatchPreDeclareAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.PreDeclare, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量拦截订单。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/intercept")]
|
|
public Task<OrderBatchJobOutput> BatchInterceptAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.Intercept, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量取消拦截。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/cancel-intercept")]
|
|
public Task<OrderBatchJobOutput> BatchCancelInterceptAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.CancelIntercept, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量删除订单。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/delete")]
|
|
public Task<OrderBatchJobOutput> BatchDeleteAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.Delete, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量打印面单。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/print")]
|
|
public Task<OrderBatchJobOutput> BatchPrintAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.Print, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量标记问题件。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/mark-problematic")]
|
|
public Task<OrderBatchJobOutput> BatchMarkProblematicAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.MarkProblematic, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量重新排货。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/reallocate")]
|
|
public Task<OrderBatchJobOutput> BatchReallocateAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.Reallocate, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量标记已认领。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/mark-claimed")]
|
|
public Task<OrderBatchJobOutput> BatchMarkClaimedAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.MarkClaimed, input);
|
|
|
|
/// <summary>
|
|
/// 异步批量更新处理状态。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/handle-status-update")]
|
|
public Task<OrderBatchJobOutput> BatchHandleStatusUpdateAsync([FromBody] OrderBatchJobCreateInput input) =>
|
|
EnqueueOrderBatchAsync(OrderBatchActionCodes.HandleStatusUpdate, input);
|
|
|
|
/// <summary>
|
|
/// 查询 RabbitMQ 队列与 DLX 堆积情况。
|
|
/// </summary>
|
|
[HttpGet("/order/batch/dlx/stats")]
|
|
public Task<OrderBatchDlxStatsOutput> GetBatchDlxStatsAsync()
|
|
{
|
|
var inspector = LazyServiceProvider.GetRequiredService<IOrderBatchQueueInspector>();
|
|
return inspector.GetStatsAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重新投递失败子项。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/jobs/{id:int}/retry-failed")]
|
|
public Task<OrderBatchJobManageOutput> RetryFailedBatchJobAsync(
|
|
[FromRoute] int id,
|
|
[FromBody] OrderBatchJobRetryFailedInput? input)
|
|
{
|
|
return BatchJobCoordinator.RetryFailedAsync(id, input, CurrentUser.GetId<int>());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 取消尚未执行的 pending 子项。
|
|
/// </summary>
|
|
[HttpPost("/order/batch/jobs/{id:int}/cancel")]
|
|
public Task<OrderBatchJobManageOutput> CancelBatchJobAsync([FromRoute] int id)
|
|
{
|
|
return BatchJobCoordinator.CancelPendingAsync(id, CurrentUser.GetId<int>());
|
|
}
|
|
}
|