From ccf19fc20e3ec884c58336fe4e3c0df806c588d7 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 15 Feb 2023 21:50:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(wxapi):=20=E6=96=B0=E5=A2=9E=E5=B0=8F?= =?UTF-8?q?=E6=B8=B8=E6=88=8F=E8=99=9A=E6=8B=9F=E6=94=AF=E4=BB=98=202.0=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Constants/MidasSignMethods.cs | 7 + .../MiniGameCoinDeliverCompletedEvent.cs | 47 +++++ ...ApiClientExecuteCgibinExpressExtensions.cs | 28 +-- ...atApiClientExecuteCgibinMidasExtensions.cs | 119 ++++++------ ...WechatApiClientExecuteWxaGameExtensions.cs | 171 ++++++++++++++++++ .../Abstractions/CgibinMidasRequestBase.cs | 42 ++--- .../CgibinMidasCancelPayRequest.cs | 12 +- .../CgibinMidasCancelPayResponse.cs | 4 +- .../CgibinMidasGetBalanceRequest.cs | 11 +- .../CgibinMidas/CgibinMidasPayRequest.cs | 26 ++- .../CgibinMidas/CgibinMidasPresentRequest.cs | 12 +- .../CgibinMidas/CgibinMidasPresentResponse.cs | 4 +- .../CgibinMidasSandboxCancelPayRequest.cs | 6 +- .../CgibinMidasSandboxGetBalanceRequest.cs | 6 +- .../Sandbox/CgibinMidasSandboxPayRequest.cs | 6 +- .../CgibinMidasSandboxPresentRequest.cs | 6 +- .../CgibinMidasSandboxPresentResponse.cs | 2 +- .../WxaBusinessGetPayForOrderRequest.cs | 9 +- .../Abstractions/WxaGameRequestBase.cs | 78 ++++++++ .../Models/WxaGame/WxaGameCancelPayRequest.cs | 34 ++++ .../WxaGame/WxaGameCancelPayResponse.cs | 15 ++ .../WxaGame/WxaGameGetBalanceRequest.cs | 13 ++ .../WxaGame/WxaGameGetBalanceResponse.cs | 57 ++++++ .../Models/WxaGame/WxaGamePayRequest.cs | 41 +++++ .../Models/WxaGame/WxaGamePayResponse.cs | 29 +++ .../Models/WxaGame/WxaGamePresentRequest.cs | 27 +++ .../Models/WxaGame/WxaGamePresentResponse.cs | 22 +++ .../Settings/Credentials.cs | 20 +- .../WechatApiClientOptions.cs | 23 ++- .../MiniGameCoinDeliverCompletedEvent.xml | 10 + .../WxaGame/WxaGameCancelPayRequest.json | 10 + .../WxaGame/WxaGameCancelPayResponse.json | 5 + .../WxaGame/WxaGameGetBalanceRequest.json | 7 + .../WxaGame/WxaGameGetBalanceResponse.json | 11 ++ .../WxaGame/WxaGamePayRequest.json | 11 ++ .../WxaGame/WxaGamePayResponse.json | 7 + .../WxaGame/WxaGamePresentRequest.json | 9 + .../WxaGame/WxaGamePresentResponse.json | 6 + .../TestCase_DeliveryRequestSignatureTests.cs | 27 --- .../TestCase_MidasRequestSignatureTests.cs | 30 --- .../TestCase_RequestSignatureTests.cs | 85 +++++++++ 41 files changed, 918 insertions(+), 177 deletions(-) create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Constants/MidasSignMethods.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Events/WxaGame/MiniGameCoinDeliverCompletedEvent.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteWxaGameExtensions.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/Abstractions/WxaGameRequestBase.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameCancelPayRequest.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameCancelPayResponse.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameGetBalanceRequest.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameGetBalanceResponse.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePayRequest.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePayResponse.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePresentRequest.cs create mode 100644 src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePresentResponse.cs create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/EventSamples/WxaGame/MiniGameCoinDeliverCompletedEvent.xml create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameCancelPayRequest.json create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameCancelPayResponse.json create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameGetBalanceRequest.json create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameGetBalanceResponse.json create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePayRequest.json create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePayResponse.json create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePresentRequest.json create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePresentResponse.json delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_DeliveryRequestSignatureTests.cs delete mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_MidasRequestSignatureTests.cs create mode 100644 test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_RequestSignatureTests.cs diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Constants/MidasSignMethods.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Constants/MidasSignMethods.cs new file mode 100644 index 00000000..8c5f3833 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Constants/MidasSignMethods.cs @@ -0,0 +1,7 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Constants +{ + public static class MidasSignMethods + { + public const string HMAC_SHA256 = "hmac_sha256"; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Events/WxaGame/MiniGameCoinDeliverCompletedEvent.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Events/WxaGame/MiniGameCoinDeliverCompletedEvent.cs new file mode 100644 index 00000000..17e847fb --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Events/WxaGame/MiniGameCoinDeliverCompletedEvent.cs @@ -0,0 +1,47 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Events +{ + /// + /// 表示 EVENT.minigame_coin_deliver_completed 事件的数据。 + /// https://docs.qq.com/doc/DVVZZdHFsYkttYmxl + /// + public class MiniGameCoinDeliverCompletedEvent : WechatApiEvent, WechatApiEvent.Serialization.IJsonSerializable, WechatApiEvent.Serialization.IXmlSerializable + { + public static class Types + { + public class EventData + { + /// + /// 获取或设置携带的具体内容。 + /// + [Newtonsoft.Json.JsonProperty("Payload")] + [System.Text.Json.Serialization.JsonPropertyName("Payload")] + [System.Xml.Serialization.XmlElement("Payload")] + public string Payload { get; set; } = default!; + + /// + /// 获取或设置支付签名。 + /// + [Newtonsoft.Json.JsonProperty("PayEventSig")] + [System.Text.Json.Serialization.JsonPropertyName("PayEventSig")] + [System.Xml.Serialization.XmlElement("PayEventSig")] + public string PaySign { get; set; } = default!; + + /// + /// 获取或设置是否是模拟数据。 + /// + [Newtonsoft.Json.JsonProperty("IsMock")] + [System.Text.Json.Serialization.JsonPropertyName("IsMock")] + [System.Xml.Serialization.XmlElement("IsMock")] + public bool IsMock { get; set; } + } + } + + /// + /// 获取或设置事件数据。 + /// + [Newtonsoft.Json.JsonProperty("MiniGame")] + [System.Text.Json.Serialization.JsonPropertyName("MiniGame")] + [System.Xml.Serialization.XmlElement("MiniGame")] + public Types.EventData EventData { get; set; } = default!; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinExpressExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinExpressExtensions.cs index 264986af..9fa16372 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinExpressExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinExpressExtensions.cs @@ -9,7 +9,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api { public static class WechatApiClientExecuteCgibinExpressExtensions { - private static T InitRequest(WechatApiClient client, ref T request) + private static T PreprocessRequest(WechatApiClient client, ref T request) where T : Models.CgibinExpressLocalBusinessRequestBase, new() { if (client == null) throw new ArgumentNullException(nameof(request)); @@ -22,8 +22,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (request.DeliverySignature == null) { - string plainText = $"{request.ShopId}{request.ShopOrderId}{client.Credentials.ImmeDeliveryAppSecret}"; - request.DeliverySignature = Utilities.SHA1Utility.Hash(plainText).ToLower(); + string msgText = $"{request.ShopId}{request.ShopOrderId}{client.Credentials.ImmeDeliveryAppSecret}"; + request.DeliverySignature = Utilities.SHA1Utility.Hash(msgText).ToLower(); } return request; @@ -43,7 +43,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "order", "pre_add") @@ -65,7 +65,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "order", "add") @@ -87,7 +87,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "order", "readd") @@ -109,7 +109,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "order", "addtips") @@ -131,7 +131,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "order", "get") @@ -153,7 +153,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "order", "precancel") @@ -175,7 +175,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "order", "cancel") @@ -197,7 +197,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "order", "confirm_return") @@ -279,7 +279,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "test_update_order") @@ -301,7 +301,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "realmock_update_order") @@ -343,7 +343,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "express", "local", "business", "update_order") diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinMidasExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinMidasExtensions.cs index c37c0b57..348b21f3 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinMidasExtensions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteCgibinMidasExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; @@ -12,12 +12,10 @@ namespace SKIT.FlurlHttpClient.Wechat.Api { public static class WechatApiClientExecuteCgibinMidasExtensions { - private static T InitRequest(WechatApiClient client, string method, string reqLoc, ref T request) + private static T PreprocessRequest(WechatApiClient client, ref T request) where T : Models.CgibinMidasRequestBase, new() { if (client == null) throw new ArgumentNullException(nameof(request)); - if (method == null) throw new ArgumentNullException(nameof(method)); - if (reqLoc == null) throw new ArgumentNullException(nameof(reqLoc)); if (request == null) throw new ArgumentNullException(nameof(request)); if (request.AppId == null) @@ -25,6 +23,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Api request.AppId = client.Credentials.AppId; } + if (request.MidasOfferId == null) + { + request.MidasOfferId = client.Credentials.MidasOfferId; + } + if (request.Timestamp == null) { request.Timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds(); @@ -43,38 +46,16 @@ namespace SKIT.FlurlHttpClient.Wechat.Api { "ts", request.Timestamp.ToString()! } } ); - string plainText = string.Join("&", paramMap.Select(e => $"{e.Key}={e.Value}")) - + $"&org_loc={reqLoc}" - + $"&method={method.ToUpper()}" + string msgText = string.Join("&", paramMap.Select(e => $"{e.Key}={e.Value}")) + + $"&org_loc={request.GetRequestPath()}" + + $"&method={request.GetRequestMethod()}" + $"&secret={client.Credentials.MidasAppKey}"; - request.Signature = Utilities.HMACUtility.HashWithSHA256(client.Credentials.MidasAppKey ?? string.Empty, plainText).ToLower(); + request.Signature = Utilities.HMACUtility.HashWithSHA256(client.Credentials.MidasAppKey ?? string.Empty, msgText).ToLower(); } return request; } - /// - /// 异步调用 [POST] /cgi-bin/midas/cancelpay 接口。 - /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/midas-payment/midas.cancelPay.html - /// - /// - /// - /// - /// - public static async Task ExecuteCgibinMidasCancelPayAsync(this WechatApiClient client, Models.CgibinMidasCancelPayRequest request, CancellationToken cancellationToken = default) - { - if (client is null) throw new ArgumentNullException(nameof(client)); - if (request is null) throw new ArgumentNullException(nameof(request)); - - InitRequest(client, HttpMethod.Post.Method, "/cgi-bin/midas/cancelpay", ref request); - - IFlurlRequest flurlReq = client - .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "cancelpay") - .SetQueryParam("access_token", request.AccessToken); - - return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); - } - /// /// 异步调用 [POST] /cgi-bin/midas/getbalance 接口。 /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/midas-payment/midas.getBalance.html @@ -88,7 +69,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, HttpMethod.Post.Method, "/cgi-bin/midas/getbalance", ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "getbalance") @@ -110,7 +91,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, HttpMethod.Post.Method, "/cgi-bin/midas/pay", ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "pay") @@ -119,6 +100,28 @@ namespace SKIT.FlurlHttpClient.Wechat.Api return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); } + /// + /// 异步调用 [POST] /cgi-bin/midas/cancelpay 接口。 + /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/midas-payment/midas.cancelPay.html + /// + /// + /// + /// + /// + public static async Task ExecuteCgibinMidasCancelPayAsync(this WechatApiClient client, Models.CgibinMidasCancelPayRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + PreprocessRequest(client, ref request); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "cancelpay") + .SetQueryParam("access_token", request.AccessToken); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + /// /// 异步调用 [POST] /cgi-bin/midas/present 接口。 /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/midas-payment/midas.present.html @@ -132,7 +135,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, HttpMethod.Post.Method, "/cgi-bin/midas/present", ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "present") @@ -142,28 +145,6 @@ namespace SKIT.FlurlHttpClient.Wechat.Api } #region Sandbox - /// - /// 异步调用 [POST] /cgi-bin/midas/sandbox/cancelpay 接口。 - /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/midas-payment/midas.cancelPay.html - /// - /// - /// - /// - /// - public static async Task ExecuteCgibinMidasSandboxCancelPayAsync(this WechatApiClient client, Models.CgibinMidasSandboxCancelPayRequest request, CancellationToken cancellationToken = default) - { - if (client is null) throw new ArgumentNullException(nameof(client)); - if (request is null) throw new ArgumentNullException(nameof(request)); - - InitRequest(client, HttpMethod.Post.Method, "/cgi-bin/midas/sandbox/cancelpay", ref request); - - IFlurlRequest flurlReq = client - .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "sandbox", "cancelpay") - .SetQueryParam("access_token", request.AccessToken); - - return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); - } - /// /// 异步调用 [POST] /cgi-bin/midas/sandbox/getbalance 接口。 /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/midas-payment/midas.getBalance.html @@ -177,7 +158,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, HttpMethod.Post.Method, "/cgi-bin/midas/sandbox/getbalance", ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "sandbox", "getbalance") @@ -199,7 +180,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, HttpMethod.Post.Method, "/cgi-bin/midas/sandbox/pay", ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "sandbox", "pay") @@ -208,6 +189,28 @@ namespace SKIT.FlurlHttpClient.Wechat.Api return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); } + /// + /// 异步调用 [POST] /cgi-bin/midas/sandbox/cancelpay 接口。 + /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/midas-payment/midas.cancelPay.html + /// + /// + /// + /// + /// + public static async Task ExecuteCgibinMidasSandboxCancelPayAsync(this WechatApiClient client, Models.CgibinMidasSandboxCancelPayRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + PreprocessRequest(client, ref request); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "sandbox", "cancelpay") + .SetQueryParam("access_token", request.AccessToken); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + /// /// 异步调用 [POST] /cgi-bin/midas/sandbox/present 接口。 /// REF: https://developers.weixin.qq.com/minigame/dev/api-backend/midas-payment/midas.present.html @@ -221,7 +224,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api if (client is null) throw new ArgumentNullException(nameof(client)); if (request is null) throw new ArgumentNullException(nameof(request)); - InitRequest(client, HttpMethod.Post.Method, "/cgi-bin/midas/sandbox/present", ref request); + PreprocessRequest(client, ref request); IFlurlRequest flurlReq = client .CreateRequest(request, HttpMethod.Post, "cgi-bin", "midas", "sandbox", "present") diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteWxaGameExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteWxaGameExtensions.cs new file mode 100644 index 00000000..e9c56752 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Extensions/WechatApiClientExecuteWxaGameExtensions.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using Flurl; +using Flurl.Http; +using Newtonsoft.Json.Converters; + +namespace SKIT.FlurlHttpClient.Wechat.Api +{ + public static class WechatApiClientExecuteWxaGameExtensions + { + private static T PreprocessRequest(WechatApiClient client, ref T request) + where T : Models.WxaGameRequestBase, new() + { + if (client == null) throw new ArgumentNullException(nameof(request)); + if (request == null) throw new ArgumentNullException(nameof(request)); + + string? tmpRawData = null; // 用于缓存待签名数据中的请求正文部分,避免序列化多次浪费性能 + + if (request.OfferId == null) + { + request.OfferId = client.Credentials.MidasOfferIdV2; + } + + if (request.Timestamp == null) + { + request.Timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds(); + } + + if (request.SignMethod == null) + { + request.SignMethod = Constants.MidasSignMethods.HMAC_SHA256; + } + + if (request.Signature == null) + { + tmpRawData = tmpRawData ?? client.JsonSerializer.Serialize(request); + + switch (request.SignMethod) + { + case Constants.MidasSignMethods.HMAC_SHA256: + { + string msgText = tmpRawData; + request.Signature = Utilities.HMACUtility.HashWithSHA256(request.SessionKey ?? string.Empty, msgText).ToLower(); + } + break; + + default: + { + request.Signature = string.Empty; + } + break; + } + } + + if (request.PaySign == null) + { + tmpRawData = tmpRawData ?? client.JsonSerializer.Serialize(request); + + string msgText = $"{request.GetRequestPath()}&{tmpRawData}"; + request.PaySign = Utilities.HMACUtility.HashWithSHA256(client.Credentials.MidasAppKeyV2 ?? string.Empty, msgText).ToLower(); + } + + return request; + } + + /// + /// 异步调用 [POST] /wxa/game/getbalance 接口。 + /// REF: https://docs.qq.com/doc/DVUN0QWJja0J5c2x4 + /// + /// + /// + /// + /// + public static async Task ExecuteWxaGameGetBalanceAsync(this WechatApiClient client, Models.WxaGameGetBalanceRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + PreprocessRequest(client, ref request); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "wxa", "game", "getbalance") + .SetQueryParam("access_token", request.AccessToken) + .SetQueryParam("sig_method", request.SignMethod) + .SetQueryParam("signature", request.Signature) + .SetQueryParam("pay_sig", request.PaySign); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + + /// + /// 异步调用 [POST] /wxa/game/pay 接口。 + /// REF: https://docs.qq.com/doc/DVUN0QWJja0J5c2x4 + /// + /// + /// + /// + /// + public static async Task ExecuteWxaGamePayAsync(this WechatApiClient client, Models.WxaGamePayRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + PreprocessRequest(client, ref request); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "wxa", "game", "pay") + .SetQueryParam("access_token", request.AccessToken) + .SetQueryParam("sig_method", request.SignMethod) + .SetQueryParam("signature", request.Signature) + .SetQueryParam("pay_sig", request.PaySign); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + + /// + /// 异步调用 [POST] /wxa/game/cancelpay 接口。 + /// REF: https://docs.qq.com/doc/DVUN0QWJja0J5c2x4 + /// + /// + /// + /// + /// + public static async Task ExecuteWxaGameCancelPayAsync(this WechatApiClient client, Models.WxaGameCancelPayRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + PreprocessRequest(client, ref request); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "wxa", "game", "cancelpay") + .SetQueryParam("access_token", request.AccessToken) + .SetQueryParam("sig_method", request.SignMethod) + .SetQueryParam("signature", request.Signature) + .SetQueryParam("pay_sig", request.PaySign); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + + /// + /// 异步调用 [POST] /wxa/game/present 接口。 + /// REF: https://docs.qq.com/doc/DVUN0QWJja0J5c2x4 + /// + /// + /// + /// + /// + public static async Task ExecuteWxaGamePresentAsync(this WechatApiClient client, Models.WxaGamePresentRequest request, CancellationToken cancellationToken = default) + { + if (client is null) throw new ArgumentNullException(nameof(client)); + if (request is null) throw new ArgumentNullException(nameof(request)); + + PreprocessRequest(client, ref request); + + IFlurlRequest flurlReq = client + .CreateRequest(request, HttpMethod.Post, "wxa", "game", "present") + .SetQueryParam("access_token", request.AccessToken) + .SetQueryParam("sig_method", request.SignMethod) + .SetQueryParam("signature", request.Signature) + .SetQueryParam("pay_sig", request.PaySign); + + return await client.SendRequestWithJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken); + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Abstractions/CgibinMidasRequestBase.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Abstractions/CgibinMidasRequestBase.cs index f16a41eb..2a8be20d 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Abstractions/CgibinMidasRequestBase.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Abstractions/CgibinMidasRequestBase.cs @@ -1,4 +1,4 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { public abstract class CgibinMidasRequestBase : WechatApiRequest { @@ -9,6 +9,21 @@ [System.Text.Json.Serialization.JsonPropertyName("appid")] public string? AppId { get; set; } + /// + /// 获取或设置米大师分配的 OfferId。如果不指定将使用构造 时的 参数。 + /// + [Newtonsoft.Json.JsonProperty("offer_id")] + [System.Text.Json.Serialization.JsonPropertyName("offer_id")] + public string? MidasOfferId { get; set; } + + /// + /// 获取或设置米大师分区 ID。 + /// 默认值:1 + /// + [Newtonsoft.Json.JsonProperty("zone_id")] + [System.Text.Json.Serialization.JsonPropertyName("zone_id")] + public string MidasZoneId { get; set; } = "1"; + /// /// 获取或设置用户唯一标识。 /// @@ -16,27 +31,6 @@ [System.Text.Json.Serialization.JsonPropertyName("openid")] public string OpenId { get; set; } = string.Empty; - /// - /// 获取或设置米大师分配的 OfferId。 - /// - [Newtonsoft.Json.JsonProperty("offer_id")] - [System.Text.Json.Serialization.JsonPropertyName("offer_id")] - public string MidasOfferId { get; set; } = string.Empty; - - /// - /// 获取或设置米大师分区。 - /// - [Newtonsoft.Json.JsonProperty("zone_id")] - [System.Text.Json.Serialization.JsonPropertyName("zone_id")] - public string MidasZoneId { get; set; } = string.Empty; - - /// - /// 获取或设置米大师环境。 - /// - [Newtonsoft.Json.JsonProperty("env")] - [System.Text.Json.Serialization.JsonPropertyName("env")] - public string MidasEnv { get; set; } = string.Empty; - /// /// 获取或设置平台标识。 /// 默认值:android @@ -65,5 +59,9 @@ [Newtonsoft.Json.JsonProperty("sig")] [System.Text.Json.Serialization.JsonPropertyName("sig")] public string? Signature { get; set; } + + protected internal abstract string GetRequestMethod(); + + protected internal abstract string GetRequestPath(); } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasCancelPayRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasCancelPayRequest.cs index c58054e7..fad7c10f 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasCancelPayRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasCancelPayRequest.cs @@ -1,4 +1,4 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/cancelpay 接口的请求。 @@ -18,5 +18,15 @@ [Newtonsoft.Json.JsonProperty("pay_item")] [System.Text.Json.Serialization.JsonPropertyName("pay_item")] public string? PayItem { get; set; } + + protected internal override string GetRequestMethod() + { + return "POST"; + } + + protected internal override string GetRequestPath() + { + return "/cgi-bin/midas/cancelpay"; + } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasCancelPayResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasCancelPayResponse.cs index c25fb583..a613d23e 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasCancelPayResponse.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasCancelPayResponse.cs @@ -1,4 +1,4 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/cancelpay 接口的响应。 @@ -6,7 +6,7 @@ public class CgibinMidasCancelPayResponse : WechatApiResponse { /// - /// 获取或设置扣除游戏币的订单号。 + /// 获取或设置订单号。 /// [Newtonsoft.Json.JsonProperty("bill_no")] [System.Text.Json.Serialization.JsonPropertyName("bill_no")] diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasGetBalanceRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasGetBalanceRequest.cs index 64956c73..65c581ea 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasGetBalanceRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasGetBalanceRequest.cs @@ -1,9 +1,18 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/getbalance 接口的请求。 /// public class CgibinMidasGetBalanceRequest : CgibinMidasRequestBase, IInferable { + protected internal override string GetRequestMethod() + { + return "POST"; + } + + protected internal override string GetRequestPath() + { + return "/cgi-bin/midas/getbalance"; + } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPayRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPayRequest.cs index 29c0c3ee..774ed0af 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPayRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPayRequest.cs @@ -1,17 +1,10 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/pay 接口的请求。 /// public class CgibinMidasPayRequest : CgibinMidasRequestBase, IInferable { - /// - /// 获取或设置扣除游戏币数量。 - /// - [Newtonsoft.Json.JsonProperty("amt")] - [System.Text.Json.Serialization.JsonPropertyName("amt")] - public int Amount { get; set; } - /// /// 获取或设置订单号。 /// @@ -19,6 +12,13 @@ [System.Text.Json.Serialization.JsonPropertyName("bill_no")] public string BillNumber { get; set; } = string.Empty; + /// + /// 获取或设置扣除游戏币数量。 + /// + [Newtonsoft.Json.JsonProperty("amt")] + [System.Text.Json.Serialization.JsonPropertyName("amt")] + public int Amount { get; set; } + /// /// 获取或设置道具名称。 /// @@ -32,5 +32,15 @@ [Newtonsoft.Json.JsonProperty("app_remark")] [System.Text.Json.Serialization.JsonPropertyName("app_remark")] public string? Remark { get; set; } + + protected internal override string GetRequestMethod() + { + return "POST"; + } + + protected internal override string GetRequestPath() + { + return "/cgi-bin/midas/pay"; + } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPresentRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPresentRequest.cs index 4a2102b8..f3c81852 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPresentRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPresentRequest.cs @@ -1,4 +1,4 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/present 接口的请求。 @@ -18,5 +18,15 @@ [Newtonsoft.Json.JsonProperty("present_counts")] [System.Text.Json.Serialization.JsonPropertyName("present_counts")] public int PresentAmount { get; set; } + + protected internal override string GetRequestMethod() + { + return "POST"; + } + + protected internal override string GetRequestPath() + { + return "/cgi-bin/midas/present"; + } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPresentResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPresentResponse.cs index 97426bb2..6f4ecb6d 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPresentResponse.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/CgibinMidasPresentResponse.cs @@ -1,4 +1,4 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/present 接口的响应。 @@ -6,7 +6,7 @@ public class CgibinMidasPresentResponse : WechatApiResponse { /// - /// 获取或设置赠送游戏币的订单号。 + /// 获取或设置订单号。 /// [Newtonsoft.Json.JsonProperty("bill_no")] [System.Text.Json.Serialization.JsonPropertyName("bill_no")] diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxCancelPayRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxCancelPayRequest.cs index 629a35eb..60af3561 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxCancelPayRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxCancelPayRequest.cs @@ -1,9 +1,13 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/sandbox/cancelpay 接口的请求。 /// public class CgibinMidasSandboxCancelPayRequest : CgibinMidasCancelPayRequest, IInferable { + protected internal override string GetRequestPath() + { + return "/cgi-bin/midas/sandbox/cancelpay"; + } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxGetBalanceRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxGetBalanceRequest.cs index 2532c193..9137e508 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxGetBalanceRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxGetBalanceRequest.cs @@ -1,9 +1,13 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/sandbox/getbalance 接口的请求。 /// public class CgibinMidasSandboxGetBalanceRequest : CgibinMidasGetBalanceRequest, IInferable { + protected internal override string GetRequestPath() + { + return "/cgi-bin/midas/sandbox/getbalance"; + } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPayRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPayRequest.cs index 22ba0cc4..6bd9ac3d 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPayRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPayRequest.cs @@ -1,9 +1,13 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/sandbox/pay 接口的请求。 /// public class CgibinMidasSandboxPayRequest : CgibinMidasPayRequest, IInferable { + protected internal override string GetRequestPath() + { + return "/cgi-bin/midas/sandbox/pay"; + } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPresentRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPresentRequest.cs index 2660bc11..e60c139d 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPresentRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPresentRequest.cs @@ -1,9 +1,13 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/sandbox/present 接口的请求。 /// public class CgibinMidasSandboxPresentRequest : CgibinMidasPresentRequest, IInferable { + protected internal override string GetRequestPath() + { + return "/cgi-bin/midas/sandbox/present"; + } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPresentResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPresentResponse.cs index aaa953cb..8eeceb8e 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPresentResponse.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/CgibinMidas/Sandbox/CgibinMidasSandboxPresentResponse.cs @@ -1,4 +1,4 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /cgi-bin/midas/sandbox/present 接口的响应。 diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaBusiness/WxaBusinessGetPayForOrderRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaBusiness/WxaBusinessGetPayForOrderRequest.cs index 0a204896..63a8fcfa 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaBusiness/WxaBusinessGetPayForOrderRequest.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaBusiness/WxaBusinessGetPayForOrderRequest.cs @@ -1,4 +1,4 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api.Models +namespace SKIT.FlurlHttpClient.Wechat.Api.Models { /// /// 表示 [POST] /wxa/business/getpayfororder 接口的请求。 @@ -12,6 +12,13 @@ [System.Text.Json.Serialization.JsonPropertyName("appid")] public string? AppId { get; set; } + /// + /// 获取或设置米大师环境。 + /// + [Newtonsoft.Json.JsonProperty("env")] + [System.Text.Json.Serialization.JsonPropertyName("env")] + public int MidasEnvironment { get; set; } + /// /// 获取或设置微信索要单号。 /// diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/Abstractions/WxaGameRequestBase.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/Abstractions/WxaGameRequestBase.cs new file mode 100644 index 00000000..07863192 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/Abstractions/WxaGameRequestBase.cs @@ -0,0 +1,78 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + public abstract class WxaGameRequestBase : WechatApiRequest + { + /// + /// 获取或设置虚拟支付应用 ID。如果不指定将使用构造 时的 参数。 + /// + [Newtonsoft.Json.JsonProperty("offer_id")] + [System.Text.Json.Serialization.JsonPropertyName("offer_id")] + public string? OfferId { get; set; } + + /// + /// 获取或设置虚拟支付分区 ID。 + /// + [Newtonsoft.Json.JsonProperty("zone_id")] + [System.Text.Json.Serialization.JsonPropertyName("zone_id")] + public string ZoneId { get; set; } = string.Empty; + + /// + /// 获取或设置用户唯一标识。 + /// + [Newtonsoft.Json.JsonProperty("openid")] + [System.Text.Json.Serialization.JsonPropertyName("openid")] + public string OpenId { get; set; } = string.Empty; + + /// + /// 获取或设置虚拟支付环境。 + /// + [Newtonsoft.Json.JsonProperty("env")] + [System.Text.Json.Serialization.JsonPropertyName("env")] + public int Environment { get; set; } + + /// + /// 获取或设置用户 IP。 + /// + [Newtonsoft.Json.JsonProperty("user_ip")] + [System.Text.Json.Serialization.JsonPropertyName("user_ip")] + public string? UserIp { get; set; } + + /// + /// 获取或设置请求时间戳。如果不指定将由系统自动生成。 + /// + [Newtonsoft.Json.JsonProperty("ts")] + [System.Text.Json.Serialization.JsonPropertyName("ts")] + public long? Timestamp { get; set; } + + /// + /// 获取或设置用于用户登录态签名的会话密钥。 + /// + [Newtonsoft.Json.JsonIgnore] + [System.Text.Json.Serialization.JsonIgnore] + public string SessionKey { get; set; } = string.Empty; + + /// + /// 获取或设置用于用户登录态签名的方式。 + /// 默认值: + /// + [Newtonsoft.Json.JsonIgnore] + [System.Text.Json.Serialization.JsonIgnore] + public string SignMethod { get; set; } = Constants.MidasSignMethods.HMAC_SHA256; + + /// + /// 获取或设置用户登录态签名。如果不指定将由系统自动生成。 + /// + [Newtonsoft.Json.JsonIgnore] + [System.Text.Json.Serialization.JsonIgnore] + public string? Signature { get; set; } + + /// + /// 获取或设置支付签名。如果不指定将由系统自动生成。 + /// + [Newtonsoft.Json.JsonIgnore] + [System.Text.Json.Serialization.JsonIgnore] + public string? PaySign { get; set; } + + protected internal abstract string GetRequestPath(); + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameCancelPayRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameCancelPayRequest.cs new file mode 100644 index 00000000..36c95d5b --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameCancelPayRequest.cs @@ -0,0 +1,34 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /wxa/game/cancelpay 接口的请求。 + /// + public class WxaGameCancelPayRequest : WxaGameRequestBase, IInferable + { + /// + /// 获取或设置扣除游戏币的订单号。 + /// + [Newtonsoft.Json.JsonProperty("pay_bill_no")] + [System.Text.Json.Serialization.JsonPropertyName("pay_bill_no")] + public string PayBillNumber { get; set; } = string.Empty; + + /// + /// 获取或设置退回游戏币的订单号。 + /// + [Newtonsoft.Json.JsonProperty("bill_no")] + [System.Text.Json.Serialization.JsonPropertyName("bill_no")] + public string BillNumber { get; set; } = string.Empty; + + /// + /// 获取或设置本次退回的退游戏币的数量。 + /// + [Newtonsoft.Json.JsonProperty("amount")] + [System.Text.Json.Serialization.JsonPropertyName("amount")] + public int Amount { get; set; } + + protected internal override string GetRequestPath() + { + return "/wxa/game/cancelpay"; + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameCancelPayResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameCancelPayResponse.cs new file mode 100644 index 00000000..a6659734 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameCancelPayResponse.cs @@ -0,0 +1,15 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /wxa/game/cancelpay 接口的响应。 + /// + public class WxaGameCancelPayResponse : WechatApiResponse + { + /// + /// 获取或设置退回游戏币的订单号。 + /// + [Newtonsoft.Json.JsonProperty("bill_no")] + [System.Text.Json.Serialization.JsonPropertyName("bill_no")] + public string BillNumber { get; set; } = default!; + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameGetBalanceRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameGetBalanceRequest.cs new file mode 100644 index 00000000..af53e918 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameGetBalanceRequest.cs @@ -0,0 +1,13 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /wxa/game/getbalance 接口的请求。 + /// + public class WxaGameGetBalanceRequest : WxaGameRequestBase, IInferable + { + protected internal override string GetRequestPath() + { + return "/wxa/game/getbalance"; + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameGetBalanceResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameGetBalanceResponse.cs new file mode 100644 index 00000000..341b9e80 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGameGetBalanceResponse.cs @@ -0,0 +1,57 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /wxa/game/getbalance 接口的响应。 + /// + public class WxaGameGetBalanceResponse : WechatApiResponse + { + /// + /// 获取或设置游戏币总余额。 + /// + [Newtonsoft.Json.JsonProperty("balance")] + [System.Text.Json.Serialization.JsonPropertyName("balance")] + public int Balance { get; set; } + + /// + /// 获取或设置赠送账户的游戏币余额。 + /// + [Newtonsoft.Json.JsonProperty("present_balance")] + [System.Text.Json.Serialization.JsonPropertyName("present_balance")] + public int PresentBalance { get; set; } + + /// + /// 获取或设置是否满足首充活动。 + /// + [Newtonsoft.Json.JsonProperty("first_save")] + [System.Text.Json.Serialization.JsonPropertyName("first_save")] + public bool IsFirstSave { get; set; } + + /// + /// 获取或设置累计现金充值获得的游戏币数量。 + /// + [Newtonsoft.Json.JsonProperty("sum_save")] + [System.Text.Json.Serialization.JsonPropertyName("sum_save")] + public int SumSave { get; set; } + + /// + /// 获取或设置累计赠送的游戏币数量。 + /// + [Newtonsoft.Json.JsonProperty("sum_present")] + [System.Text.Json.Serialization.JsonPropertyName("sum_present")] + public int SumPresent { get; set; } + + /// + /// 获取或设置累计获得的游戏币数量。 + /// + [Newtonsoft.Json.JsonProperty("sum_balance")] + [System.Text.Json.Serialization.JsonPropertyName("sum_balance")] + public int SumBalance { get; set; } + + /// + /// 获取或设置累计总消耗游戏币数量。 + /// + [Newtonsoft.Json.JsonProperty("sum_cost")] + [System.Text.Json.Serialization.JsonPropertyName("sum_cost")] + public int SumCost { get; set; } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePayRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePayRequest.cs new file mode 100644 index 00000000..d67b201b --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePayRequest.cs @@ -0,0 +1,41 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /wxa/game/pay 接口的请求。 + /// + public class WxaGamePayRequest : WxaGameRequestBase, IInferable + { + /// + /// 获取或设置扣除游戏币的订单号。 + /// + [Newtonsoft.Json.JsonProperty("bill_no")] + [System.Text.Json.Serialization.JsonPropertyName("bill_no")] + public string BillNumber { get; set; } = string.Empty; + + /// + /// 获取或设置扣除游戏币数量。 + /// + [Newtonsoft.Json.JsonProperty("amount")] + [System.Text.Json.Serialization.JsonPropertyName("amount")] + public int Amount { get; set; } + + /// + /// 获取或设置道具名称。 + /// + [Newtonsoft.Json.JsonProperty("payitem")] + [System.Text.Json.Serialization.JsonPropertyName("payitem")] + public string? PayItem { get; set; } + + /// + /// 获取或设置备注。 + /// + [Newtonsoft.Json.JsonProperty("remark")] + [System.Text.Json.Serialization.JsonPropertyName("remark")] + public string? Remark { get; set; } + + protected internal override string GetRequestPath() + { + return "/wxa/game/pay"; + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePayResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePayResponse.cs new file mode 100644 index 00000000..5321d196 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePayResponse.cs @@ -0,0 +1,29 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /wxa/game/pay 接口的响应。 + /// + public class WxaGamePayResponse : WechatApiResponse + { + /// + /// 获取或设置扣除游戏币的订单号。 + /// + [Newtonsoft.Json.JsonProperty("bill_no")] + [System.Text.Json.Serialization.JsonPropertyName("bill_no")] + public string BillNumber { get; set; } = default!; + + /// + /// 获取或设置预扣后的余额。 + /// + [Newtonsoft.Json.JsonProperty("balance")] + [System.Text.Json.Serialization.JsonPropertyName("balance")] + public int Balance { get; set; } + + /// + /// 获取或设置本次扣的赠送币的数量。 + /// + [Newtonsoft.Json.JsonProperty("used_present_amount")] + [System.Text.Json.Serialization.JsonPropertyName("used_present_amount")] + public int UsedPresentAmount { get; set; } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePresentRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePresentRequest.cs new file mode 100644 index 00000000..1ba78d67 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePresentRequest.cs @@ -0,0 +1,27 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /wxa/game/present 接口的请求。 + /// + public class WxaGamePresentRequest : WxaGameRequestBase, IInferable + { + /// + /// 获取或设置赠送游戏币的订单号。 + /// + [Newtonsoft.Json.JsonProperty("bill_no")] + [System.Text.Json.Serialization.JsonPropertyName("bill_no")] + public string BillNumber { get; set; } = string.Empty; + + /// + /// 获取或设置赠送游戏币的个数。 + /// + [Newtonsoft.Json.JsonProperty("amount")] + [System.Text.Json.Serialization.JsonPropertyName("amount")] + public int Amount { get; set; } + + protected internal override string GetRequestPath() + { + return "/wxa/game/present"; + } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePresentResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePresentResponse.cs new file mode 100644 index 00000000..e1e921c1 --- /dev/null +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Models/WxaGame/WxaGamePresentResponse.cs @@ -0,0 +1,22 @@ +namespace SKIT.FlurlHttpClient.Wechat.Api.Models +{ + /// + /// 表示 [POST] /wxa/game/present 接口的响应。 + /// + public class WxaGamePresentResponse : WechatApiResponse + { + /// + /// 获取或设置赠送游戏币的订单号。 + /// + [Newtonsoft.Json.JsonProperty("bill_no")] + [System.Text.Json.Serialization.JsonPropertyName("bill_no")] + public string BillNumber { get; set; } = default!; + + /// + /// 获取或设置赠送后的余额。 + /// + [Newtonsoft.Json.JsonProperty("balance")] + [System.Text.Json.Serialization.JsonPropertyName("balance")] + public int Balance { get; set; } + } +} diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/Settings/Credentials.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/Settings/Credentials.cs index 2ae4c850..2c0be034 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/Settings/Credentials.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/Settings/Credentials.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace SKIT.FlurlHttpClient.Wechat.Api.Settings { @@ -39,6 +39,21 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Settings /// public string? MidasAppKey { get; } + /// + /// 初始化客户端时 的副本。 + /// + public string? MidasOfferId { get; } + + /// + /// 初始化客户端时 的副本。 + /// + public string? MidasAppKeyV2 { get; } + + /// + /// 初始化客户端时 的副本。 + /// + public string? MidasOfferIdV2 { get; } + internal Credentials(WechatApiClientOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); @@ -50,6 +65,9 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Settings ImmeDeliveryAppKey = options.ImmeDeliveryAppKey; ImmeDeliveryAppSecret = options.ImmeDeliveryAppSecret; MidasAppKey = options.MidasAppKey; + MidasOfferId = options.MidasOfferId; + MidasAppKeyV2 = options.MidasAppKeyV2; + MidasOfferIdV2 = options.MidasOfferIdV2; } } } diff --git a/src/SKIT.FlurlHttpClient.Wechat.Api/WechatApiClientOptions.cs b/src/SKIT.FlurlHttpClient.Wechat.Api/WechatApiClientOptions.cs index 1d4e2519..1d944a03 100644 --- a/src/SKIT.FlurlHttpClient.Wechat.Api/WechatApiClientOptions.cs +++ b/src/SKIT.FlurlHttpClient.Wechat.Api/WechatApiClientOptions.cs @@ -1,4 +1,4 @@ -namespace SKIT.FlurlHttpClient.Wechat.Api +namespace SKIT.FlurlHttpClient.Wechat.Api { /// /// 一个用于构造 时使用的配置项。 @@ -38,18 +38,33 @@ public string? PushToken { get; set; } /// - /// 获取或设置即时配送公司帐号 AppKey。 + /// 获取或设置即时配送公司帐号 AppKey(用于小程序即使配送相关接口)。 /// public string? ImmeDeliveryAppKey { get; set; } /// - /// 获取或设置即时配送公司帐号 AppSecret。 + /// 获取或设置即时配送公司帐号 AppSecret(用于小程序即使配送相关接口)。 /// public string? ImmeDeliveryAppSecret { get; set; } /// - /// 获取或设置米大师平台 AppKey。 + /// 获取或设置米大师平台 OfferId(用于小游戏虚拟支付 1.0 相关接口)。 + /// + public string? MidasOfferId { get; set; } + + /// + /// 获取或设置米大师平台 AppKey(用于小游戏虚拟支付 1.0 相关接口)。 /// public string? MidasAppKey { get; set; } + + /// + /// 获取或设置米大师平台 OfferId(用于小游戏虚拟支付 2.0 相关接口)。 + /// + public string? MidasOfferIdV2 { get; set; } + + /// + /// 获取或设置米大师平台 AppKey(用于小游戏虚拟支付 2.0 相关接口)。 + /// + public string? MidasAppKeyV2 { get; set; } } } diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/EventSamples/WxaGame/MiniGameCoinDeliverCompletedEvent.xml b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/EventSamples/WxaGame/MiniGameCoinDeliverCompletedEvent.xml new file mode 100644 index 00000000..c3c60834 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/EventSamples/WxaGame/MiniGameCoinDeliverCompletedEvent.xml @@ -0,0 +1,10 @@ + + 1583202606 + + + + {"OpenId":"to_user_openid","OutTradeNo":"xxxxxxx","WeChatPayInfo":{"MchOrderNo":"xxxxxxx","TransactionId":"xxxxxxx"},"Env":0,"CoinInfo":{"ZoneId":"1","TotalPrice":100,"BuyQuantity":1,"OrigPrice":100}} + f749f67b751fa80f27ddc0b7c8d2821aeda162ea22b323cd64a2c8056c2736f0 + true + + diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameCancelPayRequest.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameCancelPayRequest.json new file mode 100644 index 00000000..930cdd5b --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameCancelPayRequest.json @@ -0,0 +1,10 @@ +{ + "offer_id": "12345678", + "openid": "oUrsfxxxxxxxxxx", + "ts": 1668512806, + "zone_id": "1", + "env": 0, + "bill_no": "test_cancel_pay_1668512806", + "pay_bill_no": "test_pay_1668512428", + "amount": 1 +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameCancelPayResponse.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameCancelPayResponse.json new file mode 100644 index 00000000..b7e1823b --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameCancelPayResponse.json @@ -0,0 +1,5 @@ +{ + "errcode": 0, + "errmsg": "ok", + "bill_no": "test_cancel_pay_1668512806" +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameGetBalanceRequest.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameGetBalanceRequest.json new file mode 100644 index 00000000..4fa71f7e --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameGetBalanceRequest.json @@ -0,0 +1,7 @@ +{ + "offer_id": "12345678", + "openid": "oUrsfxxxxxxxxxx", + "ts": 1668512543, + "zone_id": "1", + "env": 0 +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameGetBalanceResponse.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameGetBalanceResponse.json new file mode 100644 index 00000000..190c71a4 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGameGetBalanceResponse.json @@ -0,0 +1,11 @@ +{ + "errcode": 0, + "errmsg": "ok", + "balance": 11, + "present_balance": 1, + "sum_save": 10, + "sum_present": 1, + "sum_balance": 11, + "sum_cost": 0, + "first_save": false +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePayRequest.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePayRequest.json new file mode 100644 index 00000000..8bd7fb10 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePayRequest.json @@ -0,0 +1,11 @@ +{ + "offer_id": "12345678", + "openid": "oUrsfxxxxxxxxxx", + "ts": 1668512428, + "zone_id": "1", + "env": 0, + "bill_no": "test_pay_1668512428", + "amount": 1, + "payitem": "钻石", + "remark": "测试" +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePayResponse.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePayResponse.json new file mode 100644 index 00000000..cc4ee6b1 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePayResponse.json @@ -0,0 +1,7 @@ +{ + "errcode": 0, + "errmsg": "ok", + "bill_no": "test_pay_1668512428", + "balance": 10, + "used_present_amount": 1 +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePresentRequest.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePresentRequest.json new file mode 100644 index 00000000..de45318a --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePresentRequest.json @@ -0,0 +1,9 @@ +{ + "offer_id": "12345678", + "openid": "oUrsfxxxxxxxxxx", + "ts": 1668512716, + "zone_id": "1", + "env": 0, + "bill_no": "test_present_1668512716", + "amount": 1 +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePresentResponse.json b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePresentResponse.json new file mode 100644 index 00000000..33d71d23 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/ModelSamples/WxaGame/WxaGamePresentResponse.json @@ -0,0 +1,6 @@ +{ + "errcode": 0, + "errmsg": "ok", + "bill_no": "test_present_1668512716", + "balance": 11 +} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_DeliveryRequestSignatureTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_DeliveryRequestSignatureTests.cs deleted file mode 100644 index 0e69099a..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_DeliveryRequestSignatureTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Threading.Tasks; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests -{ - public class TestCase_DeliveryRequestSignatureTests - { - [Fact(DisplayName = "测试用例:即时配送请求签名")] - public async Task TestDeliveryRequestSignature() - { - var client = new WechatApiClient(new WechatApiClientOptions() - { - AppId = "", - AppSecret = "", - ImmeDeliveryAppKey = "test_shop_id", - ImmeDeliveryAppSecret = "test_app_secrect" - }); - var request = new Models.CgibinExpressLocalBusinessTestUpdateOrderRequest() - { - ShopOrderId = "test_shop_order_id" - }; - var response = await client.ExecuteCgibinExpressLocalBusinessTestUpdateOrderAsync(request); - - Assert.Equal("a93d8d6bae9a9483c1b1d4e8670e7f6226ec94cb", request.DeliverySignature, ignoreCase: true); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_MidasRequestSignatureTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_MidasRequestSignatureTests.cs deleted file mode 100644 index eaf38e62..00000000 --- a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_MidasRequestSignatureTests.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Threading.Tasks; -using Xunit; - -namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests -{ - public class TestCase_MidasRequestSignatureTests - { - [Fact(DisplayName = "测试用例:米大师请求签名")] - public async Task TestMidasRequestSignature() - { - var client = new WechatApiClient(new WechatApiClientOptions() - { - AppId = "wx1234567", - AppSecret = "", - MidasAppKey = "zNLgAGgqsEWJOg1nFVaO5r7fAlIQxr1u" - }); - var request = new Models.CgibinMidasGetBalanceRequest() - { - OpenId = "odkx20ENSNa2w5y3g_qOkOvBNM1g", - MidasOfferId = "12345678", - MidasZoneId = "1", - Platform = "android", - Timestamp = 1507530737 - }; - var response = await client.ExecuteCgibinMidasGetBalanceAsync(request); - - Assert.Equal("1ad64e8dcb2ec1dc486b7fdf01f4a15159fc623dc3422470e51cf6870734726b", request.Signature, ignoreCase: true); - } - } -} diff --git a/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_RequestSignatureTests.cs b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_RequestSignatureTests.cs new file mode 100644 index 00000000..88691145 --- /dev/null +++ b/test/SKIT.FlurlHttpClient.Wechat.Api.UnitTests/TestCase_RequestSignatureTests.cs @@ -0,0 +1,85 @@ +using System.Threading.Tasks; +using Xunit; + +namespace SKIT.FlurlHttpClient.Wechat.Api.UnitTests +{ + public class TestCase_RequestSignatureTests + { + [Fact(DisplayName = "测试用例:即时配送请求签名")] + public async Task TestImmeDeliveryRequestSignature() + { + var mockClient = new WechatApiClient(new WechatApiClientOptions() + { + AppId = "", + AppSecret = "", + ImmeDeliveryAppKey = "test_shop_id", + ImmeDeliveryAppSecret = "test_app_secrect" + }); + + var request = new Models.CgibinExpressLocalBusinessTestUpdateOrderRequest() + { + ShopOrderId = "test_shop_order_id" + }; + var response = await mockClient.ExecuteCgibinExpressLocalBusinessTestUpdateOrderAsync(request); // 这里不关心响应结果,只为获得预处理请求 + + Assert.Equal("a93d8d6bae9a9483c1b1d4e8670e7f6226ec94cb", request.DeliverySignature, ignoreCase: true); + } + + [Fact(DisplayName = "测试用例:米大师虚拟支付 1.0 请求签名")] + public async Task TestMidasRequestSignature() + { + var mockClient = new WechatApiClient(new WechatApiClientOptions() + { + AppId = "wx1234567", + AppSecret = "", + MidasOfferId = "12345678", + MidasAppKey = "zNLgAGgqsEWJOg1nFVaO5r7fAlIQxr1u" + }); + + var request = new Models.CgibinMidasGetBalanceRequest() + { + OpenId = "odkx20ENSNa2w5y3g_qOkOvBNM1g", + MidasZoneId = "1", + Platform = "android", + Timestamp = 1507530737 + }; + var response = await mockClient.ExecuteCgibinMidasGetBalanceAsync(request); // 这里不关心响应结果,只为获得预处理请求 + + Assert.Equal("1ad64e8dcb2ec1dc486b7fdf01f4a15159fc623dc3422470e51cf6870734726b", request.Signature, ignoreCase: true); + } + + [Fact(DisplayName = "测试用例:米大师虚拟支付 2.0 请求签名")] + public async Task TestMidasRequestSignatureV2() + { + var mockClient = new WechatApiClient(new WechatApiClientOptions() + { + AppId = "wx1234567", + AppSecret = "", + MidasOfferIdV2 = "12345678", + MidasAppKeyV2 = "12345" + }); + mockClient.Configure(settings => + { + var jsonOptions = FlurlSystemTextJsonSerializer.GetDefaultSerializerOptions(); + jsonOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull; + jsonOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.Strict; + jsonOptions.WriteIndented = false; + settings.JsonSerializer = new FlurlSystemTextJsonSerializer(jsonOptions); + }); + + var request = new Models.WxaGameGetBalanceRequest() + { + OpenId = "oUrsfxxxxxxxxxx", + OfferId = "12345678", + ZoneId = "1", + Environment = 0, + Timestamp = 1668136271, + SessionKey = "9hAb/NEYUlkaMBEsmFgzig==" + }; + var response = await mockClient.ExecuteWxaGameGetBalanceAsync(request); // 这里不关心响应结果,只为获得预处理请求 + + Assert.Equal("7ec6d737f118b0c898de39ef1b6b199c48290e699495364fe9d069597a7da125", request.Signature, ignoreCase: true); + Assert.Equal("5fc5460b23b2589efb8adbc2cf08d7a9cd8892b33e084249a26455b7880741a8", request.PaySign, ignoreCase: true); + } + } +}