1.05 #7

Merged
zzh merged 19 commits from test into master 2026-10-15 13:59:09 +08:00
3 changed files with 92 additions and 28 deletions
Showing only changes of commit aa4c4a28e6 - Show all commits

View File

@ -72,7 +72,8 @@ public sealed class OrderBatchOrderActionHandler(IServiceScopeFactory scopeFacto
message.OrderId,
message.PayloadJson,
message.OperatorUserId,
cancellationToken);
cancellationToken,
message.Authorization);
return OrderBatchActionExecuteResult.Ok();
case OrderBatchActionCodes.Reallocate:

View File

@ -2329,20 +2329,26 @@ public partial class OrderService
await OrderRepository.UpdateAsync(order);
var operatorId = operatorUserId ?? (CurrentUser.IsAuthenticated ? CurrentUser.GetId<int>() : 0);
var authorization = CaptureRequestAuthorization();
var publisher = LazyServiceProvider.GetRequiredService<IOrderBatchJobPublisher>();
if (!publisher.IsEnabled)
{
var payloadJson = JsonConvert.SerializeObject(new ForecastBillingJobPayload
{
CouponInstanceId = order.CouponInstanceId
CouponInstanceId = order.CouponInstanceId,
Authorization = authorization
});
await ProcessForecastBillingForBatchAsync(order.Id, payloadJson, operatorId);
await ProcessForecastBillingForBatchAsync(
order.Id,
payloadJson,
operatorId,
authorization: authorization);
}
else
{
var orderId = order.Id;
var couponInstanceId = order.CouponInstanceId;
await ScheduleForecastEnqueueAsync(orderId, couponInstanceId, operatorId);
await ScheduleForecastEnqueueAsync(orderId, couponInstanceId, operatorId, authorization);
}
await ScheduleForecastSideEffectsAsync(order.Id, operatorId);
@ -2663,7 +2669,8 @@ public partial class OrderService
int orderId,
string? payloadJson = null,
int operatorUserId = 0,
CancellationToken cancellationToken = default)
CancellationToken cancellationToken = default,
string? authorization = null)
{
var order = await OrderRepository.FirstOrDefaultAsync(x => x.Id == orderId, cancellationToken);
if (order == null)
@ -2687,6 +2694,7 @@ public partial class OrderService
var beforeSnap = await CaptureOrderAuditSnapshotAsync(order, includeFees: true, includeWeights: true);
int? couponInstanceId = order.CouponInstanceId;
string? trackAuthorization = authorization;
if (!string.IsNullOrWhiteSpace(payloadJson))
{
try
@ -2696,6 +2704,12 @@ public partial class OrderService
{
couponInstanceId = payload.CouponInstanceId;
}
if (string.IsNullOrWhiteSpace(trackAuthorization)
&& !string.IsNullOrWhiteSpace(payload?.Authorization))
{
trackAuthorization = payload.Authorization.Trim();
}
}
catch
{
@ -2829,9 +2843,10 @@ public partial class OrderService
await OrderRepository.UpdateAsync(order);
// 轨迹订单依赖排货后的渠道/ApiCode,只有排货成功才创建。
// 消费端没有 HttpContext,须用创单时捕获的 Authorization,否则轨迹网关返回 401。
if (allocated && !string.IsNullOrWhiteSpace(order.ChannelCode))
{
await ScheduleTrackAfterAllocationAsync(order.Id);
await ScheduleTrackAfterAllocationAsync(order.Id, trackAuthorization);
}
var afterSnap = await CaptureOrderAuditSnapshotAsync(order, includeFees: true, includeWeights: true);
@ -2850,6 +2865,11 @@ public partial class OrderService
private sealed class ForecastBillingJobPayload
{
public int? CouponInstanceId { get; set; }
/// <summary>
/// 创单/预报请求的 Authorization,供排货后异步创建轨迹订单转发到轨迹网关。
/// </summary>
public string? Authorization { get; set; }
}
/// <summary>
@ -2868,6 +2888,8 @@ public partial class OrderService
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("Oms.OrderParcelCreate");
var platformCode = input.PlatformCode;
var couponInstanceId = input.CouponInstanceId;
// 事务提交后 HttpContext 已不可用,这里先捕获登录态供轨迹网关使用。
var authorization = CaptureRequestAuthorization();
await OmsAfterCommit.ScheduleAsync(unitOfWorkManager, async () =>
{
@ -2882,7 +2904,11 @@ public partial class OrderService
forecastQueued = await OmsAfterCommit.RunStepAsync(scopeFactory, logger, "forecast-billing", async sp =>
{
var service = sp.GetRequiredService<OrderService>();
await service.EnqueueForecastBillingByIdAsync(orderId, couponInstanceId, operatorUserId);
await service.EnqueueForecastBillingByIdAsync(
orderId,
couponInstanceId,
operatorUserId,
authorization);
});
await OmsAfterCommit.RunStepAsync(scopeFactory, logger, "label-generate", sp =>
sp.GetRequiredService<OrderService>().PublishForecastLabelAsync(orderId, operatorUserId));
@ -2906,7 +2932,11 @@ public partial class OrderService
});
}
private async Task ScheduleForecastEnqueueAsync(int orderId, int? couponInstanceId, int operatorUserId)
private async Task ScheduleForecastEnqueueAsync(
int orderId,
int? couponInstanceId,
int operatorUserId,
string? authorization)
{
var unitOfWorkManager = LazyServiceProvider.GetRequiredService<IUnitOfWorkManager>();
var scopeFactory = LazyServiceProvider.GetRequiredService<IServiceScopeFactory>();
@ -2916,7 +2946,8 @@ public partial class OrderService
sp.GetRequiredService<OrderService>().EnqueueForecastBillingByIdAsync(
orderId,
couponInstanceId,
operatorUserId)));
operatorUserId,
authorization)));
}
/// <summary>
@ -2939,14 +2970,14 @@ public partial class OrderService
/// <summary>
/// 预报计费事务提交后,再创建轨迹订单(此时已有渠道和 ApiCode)。
/// </summary>
private async Task ScheduleTrackAfterAllocationAsync(int orderId)
private async Task ScheduleTrackAfterAllocationAsync(int orderId, string? authorization)
{
var unitOfWorkManager = LazyServiceProvider.GetRequiredService<IUnitOfWorkManager>();
var scopeFactory = LazyServiceProvider.GetRequiredService<IServiceScopeFactory>();
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("Oms.ForecastBilling");
await OmsAfterCommit.ScheduleAsync(unitOfWorkManager, () =>
OmsAfterCommit.RunStepAsync(scopeFactory, logger, "track-upsert", sp =>
sp.GetRequiredService<OrderService>().PublishForecastTrackAsync(orderId)));
sp.GetRequiredService<OrderService>().PublishForecastTrackAsync(orderId, authorization)));
}
private async Task PublishCustomsForOrderAsync(int orderId, string? platformCode)
@ -2961,7 +2992,11 @@ public partial class OrderService
await ParcelCreateEventPublisher.PublishCustoms9610UpsertAsync(order, platformCode);
}
private async Task EnqueueForecastBillingByIdAsync(int orderId, int? couponInstanceId, int operatorUserId)
private async Task EnqueueForecastBillingByIdAsync(
int orderId,
int? couponInstanceId,
int operatorUserId,
string? authorization)
{
var order = await OrderRepository.FirstOrDefaultAsync(x => x.Id == orderId);
if (order == null
@ -2970,7 +3005,7 @@ public partial class OrderService
return;
}
await EnqueueForecastBillingAsync(order, couponInstanceId, operatorUserId);
await EnqueueForecastBillingAsync(order, couponInstanceId, operatorUserId, authorization);
}
private async Task MarkForecastEnqueueFailedIfStillProcessingAsync(int orderId)
@ -2985,7 +3020,7 @@ public partial class OrderService
await MarkParcelDraftFailedAsync(order, ForecastBillingEnqueueFailReason);
}
private async Task PublishForecastTrackAsync(int orderId)
private async Task PublishForecastTrackAsync(int orderId, string? authorization = null)
{
var order = await OrderRepository.FirstOrDefaultAsync(x => x.Id == orderId);
if (order == null
@ -3000,7 +3035,7 @@ public partial class OrderService
: null;
var request = await BuildSmallBagTrackUpsertRequestAsync(order, receiverInput: null);
request.AppendInitialTrackOnSuccess = true;
ApplyTrackAuthorization(request);
ApplyTrackAuthorization(request, authorization);
await ParcelCreateEventPublisher.PublishTrackUpsertAsync(order, request, customer?.Id);
}
@ -3031,13 +3066,16 @@ public partial class OrderService
private async Task EnqueueForecastBillingAsync(
Order order,
int? couponInstanceId,
int operatorUserId)
int operatorUserId,
string? authorization = null)
{
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>()
.CreateLogger("Oms.ForecastBilling");
authorization ??= CaptureRequestAuthorization();
var payloadJson = JsonConvert.SerializeObject(new ForecastBillingJobPayload
{
CouponInstanceId = couponInstanceId
CouponInstanceId = couponInstanceId,
Authorization = authorization
});
try
@ -3047,7 +3085,11 @@ public partial class OrderService
{
try
{
await ProcessForecastBillingForBatchAsync(order.Id, payloadJson, operatorUserId);
await ProcessForecastBillingForBatchAsync(
order.Id,
payloadJson,
operatorUserId,
authorization: authorization);
}
catch (Exception ex)
{
@ -3073,7 +3115,8 @@ public partial class OrderService
RequestId = requestId,
PayloadJson = payloadJson
},
operatorUserId);
operatorUserId,
authorization);
}
catch (Exception ex)
{
@ -3375,18 +3418,37 @@ public partial class OrderService
await ParcelCreateEventPublisher.PublishTrackUpsertAsync(order, request, customer?.Id);
}
private void ApplyTrackAuthorization(SmallBagTrackUpsertRequest request)
private void ApplyTrackAuthorization(SmallBagTrackUpsertRequest request, string? authorization = null)
{
var authorization = LazyServiceProvider
.GetRequiredService<IHttpContextAccessor>()
.HttpContext?
.Request
.Headers
.Authorization
.ToString();
if (!string.IsNullOrWhiteSpace(authorization))
{
request.Authorization = authorization;
request.Authorization = authorization.Trim();
return;
}
var fromRequest = CaptureRequestAuthorization();
if (!string.IsNullOrWhiteSpace(fromRequest))
{
request.Authorization = fromRequest;
}
}
private string? CaptureRequestAuthorization()
{
try
{
var authorization = LazyServiceProvider
.GetRequiredService<IHttpContextAccessor>()
.HttpContext?
.Request
.Headers
.Authorization
.ToString();
return string.IsNullOrWhiteSpace(authorization) ? null : authorization.Trim();
}
catch (ObjectDisposedException)
{
return null;
}
}

View File

@ -623,6 +623,7 @@ public partial class OrderService : ApplicationService
/// <para>
/// 【预报计费消费后】计费重、应收、排货应付、营销快照 → 订单改已预报。
/// 排货成功且已有 ChannelCode 时,再投递轨迹订单 + A0101(track-upsert);
/// 轨迹网关需要登录 Authorization,创单时写入预报任务 Payload,消费端原样转发;
/// 排货失败不阻断预报,也不建轨迹(可页面补做)。
/// </para>
/// </summary>