admin/src/Oms.Application/Integrations/Itfx/ItfxCreateOrderOneDataParser.cs
zzh 6f436f795f Fix downstream forecast success detection and persist provider service no.
Treat itfx body code/msg as business result, store full request/response, and write Data.serviceNo/trackNo back to the order.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-28 10:21:23 +08:00

146 lines
4.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Text.Json;
using Oms.Domain.OrdersAggregate.Entities;
namespace Oms.Application.Integrations.Itfx;
/// <summary>
/// 解析 itfx createOrderOne 成功响应中的 Data 字段,并回写订单。
/// </summary>
internal static class ItfxCreateOrderOneDataParser
{
public sealed class CreateOrderOneData
{
public string? ServiceNo { get; init; }
public string? TrackNo { get; init; }
public string? ClientNo { get; init; }
public string? LabelUrl { get; init; }
}
public static bool TryParse(string? responseBody, out CreateOrderOneData? data)
{
data = null;
if (string.IsNullOrWhiteSpace(responseBody))
{
return false;
}
try
{
using var doc = JsonDocument.Parse(responseBody);
var root = doc.RootElement;
if (root.ValueKind != JsonValueKind.Object)
{
return false;
}
if (!TryGetPropertyIgnoreCase(root, out var dataElement, "data", "Data")
|| dataElement.ValueKind != JsonValueKind.Object)
{
return false;
}
data = new CreateOrderOneData
{
ServiceNo = ReadString(dataElement, "serviceNo", "ServiceNo"),
TrackNo = ReadString(dataElement, "trackNo", "TrackNo"),
ClientNo = ReadString(dataElement, "clientNo", "ClientNo"),
LabelUrl = ReadString(dataElement, "labelUrl", "LabelUrl"),
};
return !string.IsNullOrWhiteSpace(data.ServiceNo)
|| !string.IsNullOrWhiteSpace(data.TrackNo)
|| !string.IsNullOrWhiteSpace(data.ClientNo)
|| !string.IsNullOrWhiteSpace(data.LabelUrl);
}
catch
{
return false;
}
}
/// <summary>
/// 将下游返回写入订单:服务商单号 ← Data.serviceNo,跟踪号 ← Data.trackNo。
/// 空值不覆盖已有字段。
/// </summary>
public static bool ApplyToOrder(Order order, CreateOrderOneData data)
{
var changed = false;
if (!string.IsNullOrWhiteSpace(data.ServiceNo))
{
var value = data.ServiceNo.Trim();
if (!string.Equals(order.DownstreamServiceNo, value, StringComparison.Ordinal))
{
order.DownstreamServiceNo = value;
changed = true;
}
}
if (!string.IsNullOrWhiteSpace(data.TrackNo))
{
var value = data.TrackNo.Trim();
if (!string.Equals(order.TrackNo, value, StringComparison.Ordinal))
{
order.TrackNo = value;
changed = true;
}
}
if (!string.IsNullOrWhiteSpace(data.LabelUrl))
{
var value = data.LabelUrl.Trim();
if (!string.Equals(order.LabelUrl, value, StringComparison.Ordinal))
{
order.LabelUrl = value;
changed = true;
}
}
return changed;
}
private static bool TryGetPropertyIgnoreCase(JsonElement root, out JsonElement value, params string[] names)
{
foreach (var name in names)
{
if (root.TryGetProperty(name, out value))
{
return true;
}
}
foreach (var prop in root.EnumerateObject())
{
foreach (var name in names)
{
if (prop.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
{
value = prop.Value;
return true;
}
}
}
value = default;
return false;
}
private static string? ReadString(JsonElement root, params string[] names)
{
if (!TryGetPropertyIgnoreCase(root, out var prop, names))
{
return null;
}
return prop.ValueKind switch
{
JsonValueKind.String => prop.GetString()?.Trim(),
JsonValueKind.Number => prop.GetRawText(),
JsonValueKind.Null => null,
_ => null
};
}
}