All checks were successful
Build and Deploy / deploy (push) Successful in 1m1s
Co-authored-by: Cursor <cursoragent@cursor.com>
179 lines
6.5 KiB
C#
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);
|
|
}
|
|
}
|