feat(wxapi): 新增微信小店连接小程序相关接口

This commit is contained in:
Fu Diwei 2025-07-11 10:03:19 +08:00
parent f4a99a517e
commit e331b6ea53
18 changed files with 565 additions and 8 deletions

View File

@ -45,13 +45,5 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Events
[System.Text.Json.Serialization.JsonPropertyName("settlement_time")]
[System.Xml.Serialization.XmlElement("settlement_time", IsNullable = true)]
public long? SettlementTimestamp { get; set; }
/// <summary>
/// 获取或设置消息文本内容。
/// </summary>
[Newtonsoft.Json.JsonProperty("msg")]
[System.Text.Json.Serialization.JsonPropertyName("msg")]
[System.Xml.Serialization.XmlElement("msg", IsNullable = true)]
public string? Message { get; set; }
}
}

View File

@ -4153,6 +4153,43 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
return await client.SendFlurlRequestAsJsonAsync<Models.ChannelsECOpenGetDownloadUrlResponse>(flurlReq, data: request, cancellationToken: cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// <para>异步调用 [POST] /channels/ec/open/upload 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/cooperation_shop/upload.html ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.ChannelsECOpenUploadResponse> ExecuteChannelsECOpenUploadAsync(this WechatApiClient client, Models.ChannelsECOpenUploadRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
if (request.FileName is null)
request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".png";
if (request.FileContentType is null)
request.FileContentType = MimeTypes.GetMimeMapping(request.FileName!);
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Post, "channels", "ec", "open", "upload")
.SetQueryParam("access_token", request.AccessToken);
if (request.UploadType == 0)
{
using var httpContent = Utilities.HttpContentBuilder.BuildWithFile(fileName: request.FileName, fileBytes: request.FileBytes!, fileContentType: request.FileContentType, formDataName: "file");
return await client.SendFlurlRequestAsync<Models.ChannelsECOpenUploadResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken).ConfigureAwait(false);
}
else
{
return await client.SendFlurlRequestAsJsonAsync<Models.ChannelsECOpenUploadResponse>(flurlReq, data: request, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
#endregion
#region ECOrder
@ -4567,6 +4604,77 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
}
#endregion
#region ECOrder/PresentOrder
/// <summary>
/// <para>异步调用 [POST] /channels/ec/order/presentorder/create 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/cooperation_shop/create_present_order.html ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.ChannelsECOrderPresentOrderCreateResponse> ExecuteChannelsECOrderPresentOrderCreateAsync(this WechatApiClient client, Models.ChannelsECOrderPresentOrderCreateRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Post, "channels", "ec", "order", "presentorder", "create")
.SetQueryParam("access_token", request.AccessToken);
return await client.SendFlurlRequestAsJsonAsync<Models.ChannelsECOrderPresentOrderCreateResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
/// <summary>
/// <para>异步调用 [POST] /channels/ec/order/presentorderlist/get 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/cooperation_shop/list_present_order.html ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.ChannelsECOrderPresentOrderListGetResponse> ExecuteChannelsECOrderPresentOrderListGetAsync(this WechatApiClient client, Models.ChannelsECOrderPresentOrderListGetRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Post, "channels", "ec", "order", "presentorderlist", "get")
.SetQueryParam("access_token", request.AccessToken);
return await client.SendFlurlRequestAsJsonAsync<Models.ChannelsECOrderPresentOrderListGetResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
/// <summary>
/// <para>异步调用 [POST] /channels/ec/order/presentorder/get 接口。</para>
/// <para>
/// REF: <br/>
/// <![CDATA[ https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/cooperation_shop/get_present_order.html ]]>
/// </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.ChannelsECOrderPresentOrderGetResponse> ExecuteChannelsECOrderPresentOrderGetAsync(this WechatApiClient client, Models.ChannelsECOrderPresentOrderGetRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateFlurlRequest(request, HttpMethod.Post, "channels", "ec", "order", "presentorder", "get")
.SetQueryParam("access_token", request.AccessToken);
return await client.SendFlurlRequestAsJsonAsync<Models.ChannelsECOrderPresentOrderGetResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
#endregion
#region ECOrder/PreshipmentChangeSKU
/// <summary>
/// <para>异步调用 [POST] /channels/ec/order/preshipmentchangesku/approve 接口。</para>

View File

@ -0,0 +1,50 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.Models
{
/// <summary>
/// <para>表示 [POST] /channels/ec/open/upload 接口的请求。</para>
/// </summary>
public class ChannelsECOpenUploadRequest : WechatApiRequest, IInferable<ChannelsECOpenUploadRequest, ChannelsECOpenUploadResponse>
{
/// <summary>
/// 获取或设置用户的 OpenId。
/// </summary>
[Newtonsoft.Json.JsonProperty("openid")]
[System.Text.Json.Serialization.JsonPropertyName("openid")]
public string OpenId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置返回数据类型。
/// </summary>
[Newtonsoft.Json.JsonProperty("upload_type")]
[System.Text.Json.Serialization.JsonPropertyName("upload_type")]
public int UploadType { get; set; }
/// <summary>
/// 获取或设置文件字节数组。与字段 <see cref="FileUrl"/> 二选一。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public byte[]? FileBytes { get; set; }
/// <summary>
/// 获取或设置文件名。如果不指定将由系统自动生成。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string? FileName { get; set; }
/// <summary>
/// 获取或设置文件 Conent-Type。如果不指定将由系统自动生成。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string? FileContentType { get; set; }
/// <summary>
/// 获取或设置文件 URL。与字段 <see cref="FileBytes"/> 二选一。
/// </summary>
[Newtonsoft.Json.JsonProperty("file_url")]
[System.Text.Json.Serialization.JsonPropertyName("file_url")]
public string? FileUrl { get; set; }
}
}

View File

@ -0,0 +1,15 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.Models
{
/// <summary>
/// <para>表示 [POST] /channels/ec/open/upload 接口的响应。</para>
/// </summary>
public class ChannelsECOpenUploadResponse : WechatApiResponse
{
/// <summary>
/// 获取或设置 MediaId。
/// </summary>
[Newtonsoft.Json.JsonProperty("media_id")]
[System.Text.Json.Serialization.JsonPropertyName("media_id")]
public string MediaId { get; set; } = default!;
}
}

View File

@ -0,0 +1,74 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.Models
{
/// <summary>
/// <para>表示 [POST] /channels/ec/order/presentorder/create 接口的请求。</para>
/// </summary>
public class ChannelsECOrderPresentOrderCreateRequest : WechatApiRequest, IInferable<ChannelsECOrderPresentOrderCreateRequest, ChannelsECOrderPresentOrderCreateResponse>
{
public static class Types
{
public class AuditItem
{
/// <summary>
/// 获取或设置审核项名称。
/// </summary>
[Newtonsoft.Json.JsonProperty("item_name")]
[System.Text.Json.Serialization.JsonPropertyName("item_name")]
public string ItemName { get; set; } = string.Empty;
/// <summary>
/// 获取或设置审核项值。
/// </summary>
[Newtonsoft.Json.JsonProperty("item_value")]
[System.Text.Json.Serialization.JsonPropertyName("item_value")]
public string ItemValue { get; set; } = string.Empty;
}
}
/// <summary>
/// 获取或设置活动 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("activity_id")]
[System.Text.Json.Serialization.JsonPropertyName("activity_id")]
public string ActivityId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置用户的 OpenId。
/// </summary>
[Newtonsoft.Json.JsonProperty("openid")]
[System.Text.Json.Serialization.JsonPropertyName("openid")]
public string OpenId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置合作小店 AppId。
/// </summary>
[Newtonsoft.Json.JsonProperty("shop_appid")]
[System.Text.Json.Serialization.JsonPropertyName("shop_appid")]
public string ShopAppId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置祝福语。
/// </summary>
[Newtonsoft.Json.JsonProperty("wishmessage")]
[System.Text.Json.Serialization.JsonPropertyName("wishmessage")]
public string? WishMessage { get; set; }
/// <summary>
/// 获取或设置商品 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("product_id")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.TextualNumberConverter))]
[System.Text.Json.Serialization.JsonPropertyName("product_id")]
[System.Text.Json.Serialization.JsonNumberHandling(System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString)]
public long ProductId { get; set; }
/// <summary>
/// 获取或设置 SKU ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("sku_id")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.TextualNumberConverter))]
[System.Text.Json.Serialization.JsonPropertyName("sku_id")]
[System.Text.Json.Serialization.JsonNumberHandling(System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString)]
public long SKUId { get; set; }
}
}

View File

@ -0,0 +1,15 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.Models
{
/// <summary>
/// <para>表示 [POST] /channels/ec/order/presentorder/create 接口的响应。</para>
/// </summary>
public class ChannelsECOrderPresentOrderCreateResponse : WechatApiResponse
{
/// <summary>
/// 获取或设置礼物订单 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("present_order_id")]
[System.Text.Json.Serialization.JsonPropertyName("present_order_id")]
public string PresentOrderId { get; set; } = default!;
}
}

View File

@ -0,0 +1,22 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.Models
{
/// <summary>
/// <para>表示 [POST] /channels/ec/order/presentorder/get 接口的请求。</para>
/// </summary>
public class ChannelsECOrderPresentOrderGetRequest : WechatApiRequest, IInferable<ChannelsECOrderPresentOrderGetRequest, ChannelsECOrderPresentOrderGetResponse>
{
/// <summary>
/// 获取或设置礼物订单 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("present_order_id")]
[System.Text.Json.Serialization.JsonPropertyName("present_order_id")]
public string PresentOrderId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置用户的 OpenId。
/// </summary>
[Newtonsoft.Json.JsonProperty("open_id")]
[System.Text.Json.Serialization.JsonPropertyName("open_id")]
public string? OpenId { get; set; }
}
}

View File

@ -0,0 +1,116 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.Models
{
/// <summary>
/// <para>表示 [POST] /channels/ec/order/presentorder/get 接口的响应。</para>
/// </summary>
public class ChannelsECOrderPresentOrderGetResponse : WechatApiResponse
{
public static class Types
{
public class PresentOrder
{
public static class Types
{
public class ECGiftInfo
{
public static class Types
{
public class GiftList
{
/// <summary>
/// 获取或设置礼品列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("gift")]
[System.Text.Json.Serialization.JsonPropertyName("gift")]
public GiftItem[] Items { get; set; } = default!;
}
public class GiftItem
{
/// <summary>
/// 获取或设置礼物订单 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("order_id")]
[System.Text.Json.Serialization.JsonPropertyName("order_id")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.NumericalStringReadOnlyConverter))]
public string PresentOrderId { get; set; } = default!;
/// <summary>
/// 获取或设置礼物状态。
/// </summary>
[Newtonsoft.Json.JsonProperty("giftstatus")]
[System.Text.Json.Serialization.JsonPropertyName("giftstatus")]
public int GiftStatus { get; set; }
/// <summary>
/// 获取或设置祝福语。
/// </summary>
[Newtonsoft.Json.JsonProperty("wishmessage")]
[System.Text.Json.Serialization.JsonPropertyName("wishmessage")]
public string? WishMessage { get; set; }
/// <summary>
/// 获取或设置过期时间戳。
/// </summary>
[Newtonsoft.Json.JsonProperty("expired_time")]
[System.Text.Json.Serialization.JsonPropertyName("expired_time")]
public long? ExpireTimestamp { get; set; }
}
}
/// <summary>
/// 获取或设置礼品列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("gifts")]
[System.Text.Json.Serialization.JsonPropertyName("gifts")]
public Types.GiftList GiftList { get; set; } = default!;
/// <summary>
/// 获取或设置用户视角类型。
/// </summary>
[Newtonsoft.Json.JsonProperty("user_type")]
[System.Text.Json.Serialization.JsonPropertyName("user_type")]
public int UserType { get; set; }
/// <summary>
/// 获取或设置祝福语。
/// </summary>
[Newtonsoft.Json.JsonProperty("wishmessage")]
[System.Text.Json.Serialization.JsonPropertyName("wishmessage")]
public string? WishMessage { get; set; }
}
}
/// <summary>
/// 获取或设置礼物信息。
/// </summary>
[Newtonsoft.Json.JsonProperty("ecsgift")]
[System.Text.Json.Serialization.JsonPropertyName("ecsgift")]
public Types.ECGiftInfo ECGiftInfo { get; set; } = default!;
/// <summary>
/// 获取或设置是否不能收礼。
/// </summary>
[Newtonsoft.Json.JsonProperty("cannot_receive")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.NumericalBooleanConverter))]
[System.Text.Json.Serialization.JsonPropertyName("cannot_receive")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.NumericalBooleanConverter))]
public bool IsCannotReceive { get; set; }
/// <summary>
/// 获取或设置不能收礼原因。
/// </summary>
[Newtonsoft.Json.JsonProperty("cannot_receive_tips")]
[System.Text.Json.Serialization.JsonPropertyName("cannot_receive_tips")]
public string? CannotReceiveTips { get; set; }
}
}
/// <summary>
/// 获取或设置礼物订单信息。
/// </summary>
[Newtonsoft.Json.JsonProperty("present_order_info")]
[System.Text.Json.Serialization.JsonPropertyName("present_order_info")]
public Types.PresentOrder PresentOrder { get; set; } = default!;
}
}

View File

@ -0,0 +1,58 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.Models
{
/// <summary>
/// <para>表示 [POST] /channels/ec/order/presentorderlist/get 接口的请求。</para>
/// </summary>
public class ChannelsECOrderPresentOrderListGetRequest : WechatApiRequest, IInferable<ChannelsECOrderPresentOrderListGetRequest, ChannelsECOrderPresentOrderListGetResponse>
{
public static class Types
{
public class TimeRange : ChannelsECOrderListGetRequest.Types.TimeRange
{
}
}
/// <summary>
/// 获取或设置合作小店 AppId。
/// </summary>
[Newtonsoft.Json.JsonProperty("shop_appid")]
[System.Text.Json.Serialization.JsonPropertyName("shop_appid")]
public string ShopAppId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置用户的 OpenId。
/// </summary>
[Newtonsoft.Json.JsonProperty("open_id")]
[System.Text.Json.Serialization.JsonPropertyName("open_id")]
public string? OpenId { get; set; }
/// <summary>
/// 获取或设置创建订单时间范围。
/// </summary>
[Newtonsoft.Json.JsonProperty("create_time_range")]
[System.Text.Json.Serialization.JsonPropertyName("create_time_range")]
public Types.TimeRange? CreateTimeRange { get; set; }
/// <summary>
/// 获取或设置更新订单时间范围。
/// </summary>
[Newtonsoft.Json.JsonProperty("update_time_range")]
[System.Text.Json.Serialization.JsonPropertyName("update_time_range")]
public Types.TimeRange? UpdateTimeRange { get; set; }
/// <summary>
/// 获取或设置分页每页数量。
/// <para>默认值10</para>
/// </summary>
[Newtonsoft.Json.JsonProperty("page_size")]
[System.Text.Json.Serialization.JsonPropertyName("page_size")]
public int Limit { get; set; } = 10;
/// <summary>
/// 获取或设置翻页标记。
/// </summary>
[Newtonsoft.Json.JsonProperty("next_key")]
[System.Text.Json.Serialization.JsonPropertyName("next_key")]
public string? Cursor { get; set; }
}
}

View File

@ -0,0 +1,43 @@
namespace SKIT.FlurlHttpClient.Wechat.Api.Models
{
/// <summary>
/// <para>表示 [POST] /channels/ec/order/presentorderlist/get 接口的响应。</para>
/// </summary>
public class ChannelsECOrderPresentOrderListGetResponse : WechatApiResponse
{
public static class Types
{
public class PresentOrder
{
/// <summary>
/// 获取或设置礼物订单 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("present_order_id")]
[System.Text.Json.Serialization.JsonPropertyName("present_order_id")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.NumericalStringReadOnlyConverter))]
public string PresentOrderId { get; set; } = default!;
/// <summary>
/// 获取或设置订单 ID 列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("order_id")]
[System.Text.Json.Serialization.JsonPropertyName("order_id")]
public string[] OrderIdList { get; set; } = default!;
}
}
/// <summary>
/// 获取或设置礼物订单列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("present_order_list")]
[System.Text.Json.Serialization.JsonPropertyName("present_order_list")]
public Types.PresentOrder[] PresentOrderList { get; set; } = default!;
/// <summary>
/// 获取或设置翻页标记。
/// </summary>
[Newtonsoft.Json.JsonProperty("next_key")]
[System.Text.Json.Serialization.JsonPropertyName("next_key")]
public string? NextCursor { get; set; }
}
}

View File

@ -0,0 +1,4 @@
{
"openid": "xxx",
"file_url": "xxx"
}

View File

@ -0,0 +1,5 @@
{
"errcode": 0,
"errmsg": "成功",
"media_id": "892AERDPD2323"
}

View File

@ -0,0 +1,8 @@
{
"activity_id": "22123",
"openid": "oDiTs6x9ccP19TfQH5OvKOWeXAeo",
"shop_appid": "wxxxxxxxxxxxxxxxxx",
"wishmessage": "祝福你",
"product_id": "10000239729501",
"sku_id": "3623160014"
}

View File

@ -0,0 +1,5 @@
{
"errcode": 0,
"errmsg": "ok",
"present_order_id": "4226341196275658752"
}

View File

@ -0,0 +1,4 @@
{
"present_order_id": "4226341196275658752",
"open_id": "OPENID"
}

View File

@ -0,0 +1,18 @@
{
"errcode": 0,
"errmsg": "ok",
"present_order_info": {
"ecsgift": {
"gifts": {
"gift": [
{
"order_id": 4226341196275658752,
"wishmessage": "祝福你",
"giftstatus": 0
}
]
},
"user_type": 1
}
}
}

View File

@ -0,0 +1,10 @@
{
"shop_appid": "wxxxxxxxxxxxxxxxxx",
"open_id": "OPENID",
"create_time_range": {
"start_time": "1749007175",
"end_time": "1749008175"
},
"page_size": 10,
"next_key": "THE_NEXT_KEY"
}

View File

@ -0,0 +1,10 @@
{
"errcode": 0,
"errmsg": "ok",
"present_order_list": [
{
"present_order_id": "4226341196275658752",
"order_id": [ "3805363027490897920", "3805363027490897924" ]
}
]
}