admin/src/Oms.Application/Services/Orders/OrderService.DownstreamForward.cs
zzh 32156dcfe0
All checks were successful
Build and Deploy / deploy (push) Successful in 1m1s
fix: 轨迹订单 trackNo 仅取跟踪号,变更后重新 Upsert
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 19:20:09 +08:00

179 lines
6.5 KiB
C#

using Fake.Application;
using Fake.Domain.Exceptions;
using Fake.UnitOfWork;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Orders;
using Oms.Application.Integrations.Itfx;
using Oms.Application.Shared;
namespace Oms.Application.Services.Orders;
public partial class OrderService
{
private OrderDownstreamCredentialResolver OrderDownstreamCredentialResolver =>
LazyServiceProvider.GetRequiredService<OrderDownstreamCredentialResolver>();
private IItfxForwardClient ItfxForwardClient =>
LazyServiceProvider.GetRequiredService<IItfxForwardClient>();
/// <summary>
/// 按订单 Id 从数据库组装 createOrderOne 请求体(预览,不调用下游)。
/// </summary>
[HttpGet("/order/downstream-create-one-body")]
public async Task<OrderDownstreamCreateOneBodyOutput> GetDownstreamCreateOneBodyAsync([FromQuery] int id)
{
var (order, body) = await LoadDownstreamCreateOneContextAsync(id);
var creds = await OrderDownstreamCredentialResolver.ResolveAsync(order);
return new OrderDownstreamCreateOneBodyOutput
{
OrderId = order.Id,
ServiceNo = order.ServiceNo,
SupplierCode = creds.SupplierCode,
Body = body
};
}
/// <summary>
/// 按订单 Id 组装 createOrderOne 并转发至 itfx 下游。
/// </summary>
[HttpPost("/order/downstream-forward-create-one")]
[UnitOfWork(IsTransactional = true)]
public async Task<OrderDownstreamForwardResult> DownstreamForwardCreateOneAsync([FromBody] OrderActionInput input)
{
var (order, body) = await LoadDownstreamCreateOneContextAsync(input.Id);
if (string.IsNullOrWhiteSpace(order.ServiceNo))
{
throw new BusinessException("订单运单号为空,无法预报下游");
}
var creds = await OrderDownstreamCredentialResolver.ResolveAsync(order);
var forward = await ItfxForwardClient.ForwardCreateOrderOneAsync(
creds.SupplierCode,
creds.AppKey,
creds.AppSecret,
body);
if (forward.Success
&& ItfxCreateOrderOneDataParser.TryParse(forward.ResponseBody, out var data)
&& data != null)
{
var previousTrackNo = order.TrackNo;
if (ItfxCreateOrderOneDataParser.ApplyToOrder(order, data))
{
await OrderRepository.UpdateAsync(order);
await EnqueueSmallBagTrackUpsertWhenTrackNoChangedAsync(order, previousTrackNo);
}
if (!string.IsNullOrWhiteSpace(data.LabelUrl))
{
await OrderFileManager.AddOrReplaceDownstreamLabelAsync(
order.Id,
data.LabelUrl!,
CurrentUser.IsAuthenticated ? CurrentUser.GetId<int>() : 0);
}
}
return new OrderDownstreamForwardResult
{
Success = forward.Success,
SupplierCode = creds.SupplierCode,
Url = forward.Url,
RequestJson = forward.RequestJson,
StatusCode = forward.StatusCode,
ResponseBody = forward.ResponseBody,
DownstreamServiceNo = order.DownstreamServiceNo,
TrackNo = order.TrackNo,
};
}
/// <summary>
/// 按订单 Id 组装 getFile 并转发至 itfx 下游;成功时转存文件并回写单号。
/// </summary>
[HttpPost("/order/downstream-forward-get-file")]
public async Task<OrderDownstreamGetFileResult> DownstreamForwardGetFileAsync(
[FromBody] OrderDownstreamGetFileInput input)
{
if (!ItfxGetFileDataParser.TryResolveFileType(input.Type, out var fileType))
{
throw new BusinessException("不支持的文件类型,请选择下游面单/末端面单/POD");
}
var order = await GetOrderOrThrowAsync(input.Id);
var creds = await OrderDownstreamCredentialResolver.ResolveAsync(order);
var body = new ItfxGetFileBody
{
ClientNo = order.ClientNo?.Trim() ?? string.Empty,
TrackNo = order.TrackNo?.Trim() ?? string.Empty,
ServiceNo = order.DownstreamServiceNo?.Trim() ?? string.Empty,
Type = input.Type
};
var forward = await ItfxForwardClient.ForwardWithSubscribeAsync(
ItfxGetFileDataParser.StandardCode,
creds.SupplierCode,
creds.AppKey,
creds.AppSecret,
body);
string? storedFileUrl = null;
if (forward.Success
&& ItfxGetFileDataParser.TryParse(forward.ResponseBody, out var data)
&& data != null)
{
var previousTrackNo = order.TrackNo;
if (ItfxGetFileDataParser.ApplyToOrder(order, data))
{
await OrderRepository.UpdateAsync(order);
await EnqueueSmallBagTrackUpsertWhenTrackNoChangedAsync(order, previousTrackNo);
}
if (!string.IsNullOrWhiteSpace(data.Url))
{
var saved = await OrderFileManager.AddOrReplaceFromRemoteUrlAsync(
order.Id,
fileType,
data.Url!,
CurrentUser.IsAuthenticated ? CurrentUser.GetId<int>() : 0);
storedFileUrl = saved.FileUrl;
}
}
return new OrderDownstreamGetFileResult
{
Success = forward.Success,
SupplierCode = creds.SupplierCode,
Type = input.Type,
FileType = fileType,
Url = forward.Url,
RequestJson = forward.RequestJson,
StatusCode = forward.StatusCode,
ResponseBody = forward.ResponseBody,
StoredFileUrl = storedFileUrl,
DownstreamServiceNo = order.DownstreamServiceNo,
TrackNo = order.TrackNo,
};
}
private async Task<(Domain.OrdersAggregate.Entities.Order order, ItfxCreateOrderOneBody body)> LoadDownstreamCreateOneContextAsync(
int orderId)
{
var bundles = await OrderRepository.GetDownstreamCreateOneBundlesAsync([orderId]);
if (!bundles.TryGetValue(orderId, out var bundle))
{
throw new BusinessException("订单不存在");
}
var body = await OrderDownstreamCreateOneBodyBuilder.BuildAsync(
bundle.Order,
bundle.Sender,
bundle.Recipient,
bundle.Declarations,
bundle.Weights,
CountryRepository,
ServiceChannelRepository,
FileStorage);
return (bundle.Order, body);
}
}