feat(track): return reproducible curl in UpsertSmallBag result

Expose CurlCommand in SmallBagTrackUpsertResult so track sync dialog can show the exact curl used for the request.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-06-29 13:00:11 +08:00
parent 3046f26837
commit bc0bde72bc
3 changed files with 45 additions and 14 deletions

View File

@ -0,0 +1,37 @@
using System.Text;
using System.Text.Json;
namespace Oms.Application.Integrations.SmallBagTrack;
internal static class SmallBagTrackCurlBuilder
{
public static string Build(
string url,
string appKey,
long timestamp,
string sign,
string? authorization,
object body,
JsonSerializerOptions jsonOptions)
{
var bodyJson = JsonSerializer.Serialize(body, jsonOptions);
var sb = new StringBuilder();
sb.AppendLine($"curl --location --request POST '{url}' \\");
sb.AppendLine($"--header 'appKey: {appKey}' \\");
sb.AppendLine($"--header 'timestamp: {timestamp}' \\");
sb.AppendLine($"--header 'sign: {sign}' \\");
if (!string.IsNullOrWhiteSpace(authorization))
{
sb.AppendLine($"--header 'Authorization: {authorization.Trim()}' \\");
}
sb.AppendLine("--header 'Content-Type: application/json' \\");
sb.Append("--data-raw '");
sb.Append(EscapeForSingleQuotedShell(bodyJson));
sb.Append('\'');
return sb.ToString();
}
private static string EscapeForSingleQuotedShell(string value) =>
value.Replace("'", "'\\''", StringComparison.Ordinal);
}

View File

@ -72,20 +72,8 @@ internal sealed class SmallBagTrackOrderClient(
var body = SmallBagTrackUpsertApiRequest.FromBusinessRequest(request);
var url = SmallBagTrackUpsertApiRequest.BuildEndpointUrl(settings.BaseUrl);
var authorization = ResolveAuthorization(request);
var requestJson = JsonSerializer.Serialize(
new
{
auth = new
{
appKey,
timestamp,
sign,
transport = "header",
authorizationForwarded = !string.IsNullOrWhiteSpace(authorization)
},
body
},
JsonOptions);
var curlCommand = SmallBagTrackCurlBuilder.Build(url, appKey, timestamp, sign, authorization, body, JsonOptions);
var requestJson = JsonSerializer.Serialize(body, JsonOptions);
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, url);
httpRequest.Headers.TryAddWithoutValidation("appKey", appKey);
@ -105,6 +93,7 @@ internal sealed class SmallBagTrackOrderClient(
Success = response.IsSuccessStatusCode,
Url = url,
RequestJson = requestJson,
CurlCommand = curlCommand,
StatusCode = (int)response.StatusCode,
ResponseBody = responseBody
};

View File

@ -15,6 +15,11 @@ public class SmallBagTrackUpsertResult
public string RequestJson { get; set; } = string.Empty;
/// <summary>
/// 可复现的 curl 命令(含 appKey/timestamp/sign/Authorization 与业务 body)。
/// </summary>
public string CurlCommand { get; set; } = string.Empty;
public int? StatusCode { get; set; }
public string ResponseBody { get; set; } = string.Empty;