fix: 排货后创建轨迹订单转发创单时的 Authorization
All checks were successful
Build and Deploy / deploy (push) Successful in 1m1s
All checks were successful
Build and Deploy / deploy (push) Successful in 1m1s
消费端没有登录态会导致轨迹网关 401;创单时写入预报任务再带到轨迹事件。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a30958843b
commit
aa4c4a28e6
@ -72,7 +72,8 @@ public sealed class OrderBatchOrderActionHandler(IServiceScopeFactory scopeFacto
|
|||||||
message.OrderId,
|
message.OrderId,
|
||||||
message.PayloadJson,
|
message.PayloadJson,
|
||||||
message.OperatorUserId,
|
message.OperatorUserId,
|
||||||
cancellationToken);
|
cancellationToken,
|
||||||
|
message.Authorization);
|
||||||
return OrderBatchActionExecuteResult.Ok();
|
return OrderBatchActionExecuteResult.Ok();
|
||||||
|
|
||||||
case OrderBatchActionCodes.Reallocate:
|
case OrderBatchActionCodes.Reallocate:
|
||||||
|
|||||||
@ -2329,20 +2329,26 @@ public partial class OrderService
|
|||||||
await OrderRepository.UpdateAsync(order);
|
await OrderRepository.UpdateAsync(order);
|
||||||
|
|
||||||
var operatorId = operatorUserId ?? (CurrentUser.IsAuthenticated ? CurrentUser.GetId<int>() : 0);
|
var operatorId = operatorUserId ?? (CurrentUser.IsAuthenticated ? CurrentUser.GetId<int>() : 0);
|
||||||
|
var authorization = CaptureRequestAuthorization();
|
||||||
var publisher = LazyServiceProvider.GetRequiredService<IOrderBatchJobPublisher>();
|
var publisher = LazyServiceProvider.GetRequiredService<IOrderBatchJobPublisher>();
|
||||||
if (!publisher.IsEnabled)
|
if (!publisher.IsEnabled)
|
||||||
{
|
{
|
||||||
var payloadJson = JsonConvert.SerializeObject(new ForecastBillingJobPayload
|
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
|
else
|
||||||
{
|
{
|
||||||
var orderId = order.Id;
|
var orderId = order.Id;
|
||||||
var couponInstanceId = order.CouponInstanceId;
|
var couponInstanceId = order.CouponInstanceId;
|
||||||
await ScheduleForecastEnqueueAsync(orderId, couponInstanceId, operatorId);
|
await ScheduleForecastEnqueueAsync(orderId, couponInstanceId, operatorId, authorization);
|
||||||
}
|
}
|
||||||
|
|
||||||
await ScheduleForecastSideEffectsAsync(order.Id, operatorId);
|
await ScheduleForecastSideEffectsAsync(order.Id, operatorId);
|
||||||
@ -2663,7 +2669,8 @@ public partial class OrderService
|
|||||||
int orderId,
|
int orderId,
|
||||||
string? payloadJson = null,
|
string? payloadJson = null,
|
||||||
int operatorUserId = 0,
|
int operatorUserId = 0,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default,
|
||||||
|
string? authorization = null)
|
||||||
{
|
{
|
||||||
var order = await OrderRepository.FirstOrDefaultAsync(x => x.Id == orderId, cancellationToken);
|
var order = await OrderRepository.FirstOrDefaultAsync(x => x.Id == orderId, cancellationToken);
|
||||||
if (order == null)
|
if (order == null)
|
||||||
@ -2687,6 +2694,7 @@ public partial class OrderService
|
|||||||
var beforeSnap = await CaptureOrderAuditSnapshotAsync(order, includeFees: true, includeWeights: true);
|
var beforeSnap = await CaptureOrderAuditSnapshotAsync(order, includeFees: true, includeWeights: true);
|
||||||
|
|
||||||
int? couponInstanceId = order.CouponInstanceId;
|
int? couponInstanceId = order.CouponInstanceId;
|
||||||
|
string? trackAuthorization = authorization;
|
||||||
if (!string.IsNullOrWhiteSpace(payloadJson))
|
if (!string.IsNullOrWhiteSpace(payloadJson))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -2696,6 +2704,12 @@ public partial class OrderService
|
|||||||
{
|
{
|
||||||
couponInstanceId = payload.CouponInstanceId;
|
couponInstanceId = payload.CouponInstanceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(trackAuthorization)
|
||||||
|
&& !string.IsNullOrWhiteSpace(payload?.Authorization))
|
||||||
|
{
|
||||||
|
trackAuthorization = payload.Authorization.Trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -2829,9 +2843,10 @@ public partial class OrderService
|
|||||||
await OrderRepository.UpdateAsync(order);
|
await OrderRepository.UpdateAsync(order);
|
||||||
|
|
||||||
// 轨迹订单依赖排货后的渠道/ApiCode,只有排货成功才创建。
|
// 轨迹订单依赖排货后的渠道/ApiCode,只有排货成功才创建。
|
||||||
|
// 消费端没有 HttpContext,须用创单时捕获的 Authorization,否则轨迹网关返回 401。
|
||||||
if (allocated && !string.IsNullOrWhiteSpace(order.ChannelCode))
|
if (allocated && !string.IsNullOrWhiteSpace(order.ChannelCode))
|
||||||
{
|
{
|
||||||
await ScheduleTrackAfterAllocationAsync(order.Id);
|
await ScheduleTrackAfterAllocationAsync(order.Id, trackAuthorization);
|
||||||
}
|
}
|
||||||
|
|
||||||
var afterSnap = await CaptureOrderAuditSnapshotAsync(order, includeFees: true, includeWeights: true);
|
var afterSnap = await CaptureOrderAuditSnapshotAsync(order, includeFees: true, includeWeights: true);
|
||||||
@ -2850,6 +2865,11 @@ public partial class OrderService
|
|||||||
private sealed class ForecastBillingJobPayload
|
private sealed class ForecastBillingJobPayload
|
||||||
{
|
{
|
||||||
public int? CouponInstanceId { get; set; }
|
public int? CouponInstanceId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创单/预报请求的 Authorization,供排货后异步创建轨迹订单转发到轨迹网关。
|
||||||
|
/// </summary>
|
||||||
|
public string? Authorization { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -2868,6 +2888,8 @@ public partial class OrderService
|
|||||||
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("Oms.OrderParcelCreate");
|
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("Oms.OrderParcelCreate");
|
||||||
var platformCode = input.PlatformCode;
|
var platformCode = input.PlatformCode;
|
||||||
var couponInstanceId = input.CouponInstanceId;
|
var couponInstanceId = input.CouponInstanceId;
|
||||||
|
// 事务提交后 HttpContext 已不可用,这里先捕获登录态供轨迹网关使用。
|
||||||
|
var authorization = CaptureRequestAuthorization();
|
||||||
|
|
||||||
await OmsAfterCommit.ScheduleAsync(unitOfWorkManager, async () =>
|
await OmsAfterCommit.ScheduleAsync(unitOfWorkManager, async () =>
|
||||||
{
|
{
|
||||||
@ -2882,7 +2904,11 @@ public partial class OrderService
|
|||||||
forecastQueued = await OmsAfterCommit.RunStepAsync(scopeFactory, logger, "forecast-billing", async sp =>
|
forecastQueued = await OmsAfterCommit.RunStepAsync(scopeFactory, logger, "forecast-billing", async sp =>
|
||||||
{
|
{
|
||||||
var service = sp.GetRequiredService<OrderService>();
|
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 =>
|
await OmsAfterCommit.RunStepAsync(scopeFactory, logger, "label-generate", sp =>
|
||||||
sp.GetRequiredService<OrderService>().PublishForecastLabelAsync(orderId, operatorUserId));
|
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 unitOfWorkManager = LazyServiceProvider.GetRequiredService<IUnitOfWorkManager>();
|
||||||
var scopeFactory = LazyServiceProvider.GetRequiredService<IServiceScopeFactory>();
|
var scopeFactory = LazyServiceProvider.GetRequiredService<IServiceScopeFactory>();
|
||||||
@ -2916,7 +2946,8 @@ public partial class OrderService
|
|||||||
sp.GetRequiredService<OrderService>().EnqueueForecastBillingByIdAsync(
|
sp.GetRequiredService<OrderService>().EnqueueForecastBillingByIdAsync(
|
||||||
orderId,
|
orderId,
|
||||||
couponInstanceId,
|
couponInstanceId,
|
||||||
operatorUserId)));
|
operatorUserId,
|
||||||
|
authorization)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -2939,14 +2970,14 @@ public partial class OrderService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 预报计费事务提交后,再创建轨迹订单(此时已有渠道和 ApiCode)。
|
/// 预报计费事务提交后,再创建轨迹订单(此时已有渠道和 ApiCode)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task ScheduleTrackAfterAllocationAsync(int orderId)
|
private async Task ScheduleTrackAfterAllocationAsync(int orderId, string? authorization)
|
||||||
{
|
{
|
||||||
var unitOfWorkManager = LazyServiceProvider.GetRequiredService<IUnitOfWorkManager>();
|
var unitOfWorkManager = LazyServiceProvider.GetRequiredService<IUnitOfWorkManager>();
|
||||||
var scopeFactory = LazyServiceProvider.GetRequiredService<IServiceScopeFactory>();
|
var scopeFactory = LazyServiceProvider.GetRequiredService<IServiceScopeFactory>();
|
||||||
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("Oms.ForecastBilling");
|
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("Oms.ForecastBilling");
|
||||||
await OmsAfterCommit.ScheduleAsync(unitOfWorkManager, () =>
|
await OmsAfterCommit.ScheduleAsync(unitOfWorkManager, () =>
|
||||||
OmsAfterCommit.RunStepAsync(scopeFactory, logger, "track-upsert", sp =>
|
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)
|
private async Task PublishCustomsForOrderAsync(int orderId, string? platformCode)
|
||||||
@ -2961,7 +2992,11 @@ public partial class OrderService
|
|||||||
await ParcelCreateEventPublisher.PublishCustoms9610UpsertAsync(order, platformCode);
|
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);
|
var order = await OrderRepository.FirstOrDefaultAsync(x => x.Id == orderId);
|
||||||
if (order == null
|
if (order == null
|
||||||
@ -2970,7 +3005,7 @@ public partial class OrderService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await EnqueueForecastBillingAsync(order, couponInstanceId, operatorUserId);
|
await EnqueueForecastBillingAsync(order, couponInstanceId, operatorUserId, authorization);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task MarkForecastEnqueueFailedIfStillProcessingAsync(int orderId)
|
private async Task MarkForecastEnqueueFailedIfStillProcessingAsync(int orderId)
|
||||||
@ -2985,7 +3020,7 @@ public partial class OrderService
|
|||||||
await MarkParcelDraftFailedAsync(order, ForecastBillingEnqueueFailReason);
|
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);
|
var order = await OrderRepository.FirstOrDefaultAsync(x => x.Id == orderId);
|
||||||
if (order == null
|
if (order == null
|
||||||
@ -3000,7 +3035,7 @@ public partial class OrderService
|
|||||||
: null;
|
: null;
|
||||||
var request = await BuildSmallBagTrackUpsertRequestAsync(order, receiverInput: null);
|
var request = await BuildSmallBagTrackUpsertRequestAsync(order, receiverInput: null);
|
||||||
request.AppendInitialTrackOnSuccess = true;
|
request.AppendInitialTrackOnSuccess = true;
|
||||||
ApplyTrackAuthorization(request);
|
ApplyTrackAuthorization(request, authorization);
|
||||||
await ParcelCreateEventPublisher.PublishTrackUpsertAsync(order, request, customer?.Id);
|
await ParcelCreateEventPublisher.PublishTrackUpsertAsync(order, request, customer?.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3031,13 +3066,16 @@ public partial class OrderService
|
|||||||
private async Task EnqueueForecastBillingAsync(
|
private async Task EnqueueForecastBillingAsync(
|
||||||
Order order,
|
Order order,
|
||||||
int? couponInstanceId,
|
int? couponInstanceId,
|
||||||
int operatorUserId)
|
int operatorUserId,
|
||||||
|
string? authorization = null)
|
||||||
{
|
{
|
||||||
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>()
|
var logger = LazyServiceProvider.GetRequiredService<ILoggerFactory>()
|
||||||
.CreateLogger("Oms.ForecastBilling");
|
.CreateLogger("Oms.ForecastBilling");
|
||||||
|
authorization ??= CaptureRequestAuthorization();
|
||||||
var payloadJson = JsonConvert.SerializeObject(new ForecastBillingJobPayload
|
var payloadJson = JsonConvert.SerializeObject(new ForecastBillingJobPayload
|
||||||
{
|
{
|
||||||
CouponInstanceId = couponInstanceId
|
CouponInstanceId = couponInstanceId,
|
||||||
|
Authorization = authorization
|
||||||
});
|
});
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -3047,7 +3085,11 @@ public partial class OrderService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ProcessForecastBillingForBatchAsync(order.Id, payloadJson, operatorUserId);
|
await ProcessForecastBillingForBatchAsync(
|
||||||
|
order.Id,
|
||||||
|
payloadJson,
|
||||||
|
operatorUserId,
|
||||||
|
authorization: authorization);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -3073,7 +3115,8 @@ public partial class OrderService
|
|||||||
RequestId = requestId,
|
RequestId = requestId,
|
||||||
PayloadJson = payloadJson
|
PayloadJson = payloadJson
|
||||||
},
|
},
|
||||||
operatorUserId);
|
operatorUserId,
|
||||||
|
authorization);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -3375,18 +3418,37 @@ public partial class OrderService
|
|||||||
await ParcelCreateEventPublisher.PublishTrackUpsertAsync(order, request, customer?.Id);
|
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))
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -623,6 +623,7 @@ public partial class OrderService : ApplicationService
|
|||||||
/// <para>
|
/// <para>
|
||||||
/// 【预报计费消费后】计费重、应收、排货应付、营销快照 → 订单改已预报。
|
/// 【预报计费消费后】计费重、应收、排货应付、营销快照 → 订单改已预报。
|
||||||
/// 排货成功且已有 ChannelCode 时,再投递轨迹订单 + A0101(track-upsert);
|
/// 排货成功且已有 ChannelCode 时,再投递轨迹订单 + A0101(track-upsert);
|
||||||
|
/// 轨迹网关需要登录 Authorization,创单时写入预报任务 Payload,消费端原样转发;
|
||||||
/// 排货失败不阻断预报,也不建轨迹(可页面补做)。
|
/// 排货失败不阻断预报,也不建轨迹(可页面补做)。
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user